Skip to main content

Booking Appointments

note

This article is targeted towards carriers who are using Opendock to book appointments.

tip

Before getting started, we encourage you to familiarize yourself with the booking process from our UI perspective, so you understand the steps and the information involved. You can watch it here.

Booking appointments as a carrier involve a set of steps, given how customizable Opendock is for our customers. In this guide, we will walk you through the scheduling process and the settings you should pay attention to.

Authenticating

The authentication process is similar for carriers and warehouses. First, you have to create an account and associate it with a new or existing carrier company. You can learn more about registering as a carrier clicking here.

After registering, you can start using our API right away. Use the /auth/login endpoint to retrieve your JWT token. Learn more about authentication clicking here.

note

Make sure you've followed the registration process completely, including the verification of your email address and the association with a carrier company.

Searching for a Warehouse

After you are authenticated, the first step in booking an appointment is to search for the warehouse you want to schedule against. If you are scheduling always with the same warehouses you can skip this step, and use a pre-saved list of warehouse UUIDs.

To search for a warehouse, you can use the /carrier/warehouse-search endpoint, providing the following parameters:

  • searchStr: The string you want to search for. It can be a warehouse name, address, or Org name.
  • size: The number of results you want to retrieve.
  • page: The page number you want to retrieve.

Example: GET /carrier/warehouse-search?searchStr=MyWarehouse&size=10&page=1

This API call will return up to 10 results that match the search string "MyWarehouse". If there are more than 10 results matching the criteria, additional pages can be accessed, using page=2, page=3 and so on. Note that we do a fuzzy search on top of the parameters, which means unexact matches may be returned.

An example response would be:

{
"data": [
{
"id": "c91798b8-102e-4354-a088-4148c623e6fe",
"name": "My Warehouse",
"street": "175 W Jackson Blvd",
"city": "Chicago",
"state": "IL",
"zip": "60604",
"country": "USA",
"org": {
"id": "f1aa64da-55ab-4958-83c8-1678c5d9b56d",
"name": "JDarold"
}
},
{
"id": "37a32b56-c9c6-4cbd-9f51-a8bbfdd950ec",
"name": "Broadway",
"street": "459 Broadway",
"city": "New York",
"state": "NY",
"zip": "10013",
"country": "USA",
"org": {
"id": "4ef81fa8-538d-430f-9e1d-5e0ed6ac3c21",
"name": "My Cool Warehouses"
}
}
],
"total": 2,
"count": 2,
"page": 1,
"pageCount": 1
}

Having the desired warehouse UUID, you can proceed to the next step.

Getting the Warehouse Details

The details of a warehouse can be retrieved using the /warehouse/{id} endpoint, where {id} is the UUID retrieved previously. Some of the important information you should pay attention to are:

  • Operating Hours: The warehouse operating hours are important to know when you can schedule an appointment. They are expressed as a list of days of the week, with zero or more chunks of start and end time of the operation for that day, in 24-hour format.
  • Timezone: The timezone of the warehouse is important to know when you should schedule an appointment.
  • Settings, such as:
    • Reference Number Label: The label used for the reference number. This information provides insights into the type of reference number you should provide.
    • Reference Number Required: If the reference number is required, you should provide it when scheduling an appointment.
  • Custom Fields: Custom fields are additional information that the warehouse requires when scheduling an appointment. You should provide this information when scheduling an appointment. Let's dig into it below.

An example response would be:

{
"data": {
"id": "c91798b8-102e-4354-a088-4148c623e6fe",
"schedule": {
"friday": [
{
"end": "23:59",
"start": "8:00"
}
],
"monday": [
{
"end": "23:59",
"start": "8:00"
}
],
"sunday": [
{
"end": "23:59",
"start": "8:00"
}
],
"tuesday": [
{
"end": "23:59",
"start": "8:00"
}
],
"saturday": [
{
"end": "23:59",
"start": "8:00"
}
],
"thursday": [
{
"end": "23:59",
"start": "8:00"
}
],
"wednesday": [
{
"end": "23:59",
"start": "8:00"
}
]
},
"name": "My Warehouse",
"facilityNumber": "01",
"street": "175 W Jackson Blvd",
"city": "Chicago",
"state": "IL",
"zip": "60604",
"country": "USA",
"timezone": "America/Chicago",
"phone": "+55 48 99913-6861",
"email": "example@loadsmart.com",
"notes": "Welcome! In this field, you can find some additional information about our processes.",
"instructions": "When you arrive, make sure to check-in at the front desk.",
"customApptFieldsTemplate": [
{
"name": "strDispatcher Name",
"type": "str",
"label": "Dispatcher Name",
"requiredForCarrier": true,
},
{
"name": "docBOL",
"type": "doc",
"label": "BOL",
"requiredForCarrier": true,
}
],
"settings": {
"customLogo": "storage/5a8618cd-9ae9-4258-9aa3-34db0e6106f7/701d1e845d/hamster.jpeg",
"referenceNumberIsUnique": true,
"referenceNumberIsRequired": true,
"referenceNumberDisplayName": "Pineapple Number",
"referenceNumberHelperText": "The Pinapple Number can be found in the BOL",
"appointmentStartTimeMinutes": 30,
"yardMap": "storage/5a8618cd-9ae9-4258-9aa3-34db0e6106f7/1a5905a493/map.png",
},
"amenities": [
"Lumper services",
"Drivers restroom",
"Overnight parking",
"Free Wi-Fi"
],
"ppeRequirements": [
"Hard Hat",
"High Visibility Vest"
]
},
"entity": "Warehouse",
"action": "read"
}

Based on the response above, you can infer that:

  • This warehouse is open everyday, from 8 to midnight
  • It is under the America/Chicago timezone (see this link for details)
  • It does require an unique reference number called "Pineapple Number", which can be found in the BOL
  • It accepts appointments on "top and bottom of the hour"
    • Don't worry much about it now, as in a later step we'll dig into availability
  • It has a logo and a yard map
    • Notice that both are expressed as relative paths. In order to build the actual URL, prepend https://files.opendock.com/ to the path
  • It offers a set of amenities and requires some PPE (Personal Protective Equipment)
  • It requires the dispatcher name and the BOL as custom fields, when scheduling an appointment

Let's dig into the custom fields below.

Custom Fields

Opendock is very customizable, and warehouses can require additional information when scheduling an appointment. We call this information custom fields. When scheduling an appointment, some fields may be required.

tip

Custom Fields is a bigger topic, and we have a dedicated article for it. You can check it out here.

Upon fetching the warehouse details, you should pay attention to the customApptFieldsTemplate property. This property brings the "schema" of the custom fields required by the warehouse. Some relevant parts of the schema are:

  • type: Expresses which type of data this field is expecting. It can be str, int, doc, multidoc, etc. You can find the full list of types on the article mentioned above.
  • dropDownValues: If the field type is a dropdown, this property will contain the possible values for the dropdown.
  • label: The human-readable name of the field. This is what will be displayed to the user.
  • requiredForCarrier: If this field is required when scheduling an appointment as a carrier. If this is not required you can decide upon providing it or not.

So, when creating the appointment (which we'll cover later on), you should:

  • Copy the exact contents of the customApptFieldsTemplate property
  • For the fields that you are filling, you should add the value property, with the content you want to provide
  • For the rest of the fields, leave them as-is, or remove them from the list if you prefer (both options are valid)

In the example above, you would provide something like:

{
"customFields": [
{
"name": "strDispatcher Name",
"type": "str",
"label": "Dispatcher Name",
"requiredForCarrier": true,
"value": "John Doe"
},
{
"name": "docBOL",
"type": "doc",
"label": "BOL",
"requiredForCarrier": true,
"value": "storage/c91798b8-102e-4354-a088-4148c623e6fe/bol.pdf"
}
]
}

Document Fields

You may notice on the example above that the docBOL field is of type doc. For document fields, before providing them for the appointment, you should upload the document to the warehouse. This can be done using the /storage endpoint. Again, you can find details about this on the article mentioned above.

Choosing a Load Type

Every appointment must be associated with a Load Type. Load Types are a way for warehouses to categorize what is coming in and out of their facilities. Load Types can have different lengths and availabilities.

In order to list the available Load Types for a warehouse, you can use the /loadtype endpoint, passing the following parameters:

  • warehouseId: The UUID of the warehouse you want to list the Load Types for, as retrieved in the previous steps.
  • showOnlyAssignedLoadTypes: This is important to be set as true, so that only Load Types currently assigned to a given Dock are returned.
  • s: Search parameters, based on existing fields, expressed as a JSON object.
    • allowCarrierScheduling: Since you are a carrier, you should set this as true, so that only Load Types that allow carrier scheduling are returned.

Therefore, the endpoint would look like this:

GET /loadtype?&warehouseId=c91798b8-102e-4354-a088-4148c623e6fe&showOnlyAssignedLoadTypes=true&s={"allowCarrierScheduling":true}

Which would return something like:

{
"data": [
{
"id": "a9ef463d-bd53-435b-841e-e39f63569b77",
"name": "Apples 🍎",
"duration_min": 30,
"direction": "Inbound",
"operation": "Live",
"equipmentType": "Dry Van",
"transportationMode": "FTL",
"allowCarrierScheduling": true,
"description": "Apples are delicious and nutritious."
},
{
"id": "53f175dc-d0f5-4fb6-8819-c0d430573985",
"name": "Oranges 🍊",
"duration_min": 60,
"direction": "Inbound",
"operation": null,
"equipmentType": null,
"transportationMode": null,
"allowCarrierScheduling": true,
"description": "Oranges are a great source of vitamin C."
},
{
"id": "9c562bec-bc05-4179-9a66-e258b0d35d48",
"name": "Warm Cookies 🍪",
"duration_min": 45,
"direction": "Inbound",
"operation": null,
"equipmentType": null,
"transportationMode": null,
"allowCarrierScheduling": true,
"description": "Warm cookies are delicious and comforting."
}
],
"entity": "LoadType",
"action": "read",
"count": 3,
"total": 3,
"page": 1,
"pageCount": 1
}

Please notice that, similarly to the Warehouse Search, this is a paginated response, therefore you should pay attention to the page and pageCount properties.

Having the desired Load Type UUID, you can proceed to the next step.

Getting the Available Dates and Times

The last information you need before scheduling an appointment is the availability of the warehouse. This is a combination between various aspects, such as:

  • The Warehouse hours of operation
  • The Docks hours of operation
  • The hours of operation a Load Type is allowed to be scheduled
  • Existing appointments
  • Lead Times

You should not worry about any of these aspects, as we have an endpoint that will take care of bringing computed times for you to schedule, based on the information you have until now.

So, you can call the following endpoint:

POST /loadtype/{loadTypeId}/get-availability, with the following content as body:

  • warehouseId: The UUID of the warehouse you want to schedule an appointment for, as retrieved previously.
  • includeStartTimes: This is extremely useful to retrieve the exact times you can schedule, as opposed to a range.
  • start: The start date and time of the range you want to get times for. This should be provided as a ISO-8601 formatted string, with an explicit timezone. We recommend using the Warehouse timezone for better understanding.
  • end: The end date and time of the range you want to get times for, expressed as ISO-8601 just as the start.
tip

We recommend you use some library to handle dates and times, as the ISO-8601 format can be tricky to handle manually. Some suggestions would be: Luxon (JavaScript), java.time (Java), datetime (Python), DateTime (C#).

So, for example:

{
"warehouseId":"c91798b8-102e-4354-a088-4148c623e6fe",
"includeStartTimes":true,
"start":"2024-08-14T00:00:00.000-05:00",
"end":"2024-08-19T23:59:59.999-05:00"
}

Which would return something like:

{
"data": [
{
"availability": [
{
"start": "2024-08-15T19:21:00.000Z",
"end": "2024-08-16T05:00:00.000Z"
},
{
"start": "2024-08-16T13:00:00.000Z",
"end": "2024-08-17T05:00:00.000Z"
},
{
"start": "2024-08-19T13:00:00.000Z",
"end": "2024-08-20T04:59:59.000Z"
}
],
"startTimes": [
"2024-08-15T19:30:00.000Z",
"2024-08-15T20:00:00.000Z",
"...",
"2024-08-15T20:30:00.000Z",
"2024-08-20T04:30:00.000Z"
]
}
]
}

From the response above you can get the availability using the ranges, or pick an exact time from the startTimes array. Please notice that these date times are also expressed as ISO-8601 strings, and in the example above they are using the UTC (Z) timezone. If none of the options are suitable for you, then you may consider tweaking the parameters provided in the POST body to adjust the desired window.

Submitting the Appointment

Now it is just a matter of submitting the data you've gathered so far, along with the additional information you are required to inform. You can use the POST /appointment endpoint to do so, using the following parameters:

  • refNumber: As discussed before, the PO Number for the load, it might be required or not.
  • notes: Any additional notes you want to provide.
  • start: The start date and time of the appointment, expressed as an ISO-8601 string. Tip: Use the exact string retrieved from the previous step.
  • loadTypeId: The UUID of the Load Type you want to schedule an appointment for, as retrieved previously.
  • warehouseId: The UUID of the warehouse you want to schedule an appointment for, as retrieved previously.
  • userId: The UUID of the Carrier, that is, your own UUID. You can hit the /auth/me endpoint to retrieve it, as explained in the authentication article.
  • ccEmails: An array of email addresses you want to CC in the appointment confirmation and following updates. This is optional.
  • customFields: The custom fields you want to provide, as discussed before.

So, for example:

{
"refNumber": "190219",
"notes": "Scheduled by my API integration. How cool is that?",
"start": "2024-08-15T20:30:00.000Z",
"loadTypeId": "a9ef463d-bd53-435b-841e-e39f63569b77",
"warehouseId": "c91798b8-102e-4354-a088-4148c623e6fe",
"userId": "2639c603-5705-4116-b577-287319b2b107",
"ccEmails": [
"email1@example.com",
"email2@example.com"
],
"customFields": [
{
"name": "strDispatcher Name",
"type": "str",
"label": "Dispatcher Name",
"requiredForCarrier": true,
"value": "John Doe"
},
{
"name": "docBOL",
"type": "doc",
"label": "BOL",
"requiredForCarrier": true,
"value": "storage/c91798b8-102e-4354-a088-4148c623e6fe/bol.pdf"
}
]
}

If this call is successful, you will receive a 201 Created response, with the appointment details in the response body, including the start and end times and the status of it. You should also receive emails with the updates.

note

Some warehouses require the appointment to be confirmed by them. In this case, the appointment will be created with a "requested" status, therefore you should pay attention to that on the response.

Errors

Some errors may be returned when trying to schedule an appointment. The error response shape is mostly the same:

{
"message": "The PO Number '123' is already in use.",
"statusCode": 409
}

Therefore you can use the message to guide your users on the corrective actions. Some common errors are:

  • The time you selected was taken during the time you tried to schedule. You should try again with a different time.
  • The PO Number you provided is already in use. You should provide a different one.
  • The custom fields you provided are not valid. You should provide the correct information.
  • The Appointment Validation system at that Warehouse rejected the appointment. You should contact the Warehouse for more information if the error message is not clear enough.