Appointments API
π Why Use the Appointments API?β
Appointments are the heartbeat of warehouse operations in DataDocks. They represent scheduled time slots at your docks or yards for receiving or shipping inventory. The Appointments API gives you programmatic control over your entire warehouse scheduling workflowβfrom booking slots to tracking truck movements to completing shipments.
Real Problems This API Solvesβ
- Eliminate double-entry: Sync appointments directly between your ERP/WMS and DataDocks
- Reduce communication overhead: Automate notifications between warehouse staff and carriers
- Optimize dock utilization: Programmatically schedule appointments to maximize efficiency
- Track KPIs in real-time: Monitor on-time performance, dwell times, and throughput
- Enhance visibility: Give carriers and customers self-service access to appointment status
5-Minute Quickstartβ
Want to see the API in action right now? Follow these steps to get your first appointment created:
- Request and Get your API token from support
- Find your location subdomain (e.g.,
your-warehouse.datadocks.com) - Create a basic appointment with this command:
See quickstart cURL example
curl -X POST \
https://your-warehouse.datadocks.com/api/v1/appointments \
-H 'Authorization: Token YOUR_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"appointment": {
"scheduled_at": "2023-12-15T10:00:00-05:00",
"duration": 60,
"dock_name": "Dock 1",
"shipping_number": "SHIP-12345"
}
}'
- A successful request returns
200 OKwith your appointment. Check your DataDocks dashboard to see it. Use an appropriate date and an existing dock, and include any extra fields required by your location.
API Architecture Overviewβ
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Your System ββββββββΆβ DataDocks API ββββββββΆβ Warehouse Ops β
β (ERP/WMS/TMS) βββββββββ€ (REST/JSON) βββββββββ€ (Scheduling) β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β β²
β β
βΌ β
βββββββββββββββββββ
β Carrier Apps β
β (Check-in) β
βββββββββββββββββββ
Authenticationβ
All API requests must include your API token in the Authorization header:
Authorization: Token YOUR_API_TOKEN
API tokens belong to users. Location access and appointment permissions follow that user's permissions. Audit logs identify the API user; the display name depends on how the user was configured. Use the full location hostname, including its organization suffix where applicable.
Important Limitationsβ
- Recurring appointments cannot be created or modified through the API
- Appointment deletion is not supported through the API (use cancellation instead)
- DateTime parameters should include timezone information to avoid ambiguity; values without it use the location's timezone.
- Only non-recurring appointments are returned in listing endpoints, including generated instances but excluding recurring templates.
Listing Appointmentsβ
Purposeβ
Retrieve a paginated list of appointments with optional filtering by date range or purchase order number. Use this endpoint for syncing appointments with your systems or generating reports.
Business Use Casesβ
- Sync appointments with your WMS or TMS for the coming week
- Generate reports on upcoming shipments by dock or carrier
- Display appointments in a dashboard with status monitoring
- Track KPIs like on-time performance, dwell times, and dock utilization
HTTP Requestβ
GET https://[location_subdomain].datadocks.com/api/v1/appointments
Query Parametersβ
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
page | Integer | No | Page number for pagination (defaults to 1) | page=2 |
internal_id | String | No | Filter by internal appointment ID (case-insensitive exact match) | internal_id=ERP-A12345 |
po_number | String | No | Filter by purchase order number (case-insensitive exact match) | po_number=PO-12345 |
from | String | No | Filter appointments scheduled on or after this date/time (location timezone) | from=2023-10-01 08:00 AM |
to | String | No | Filter appointments scheduled before this date/time (location timezone) | to=2023-10-05 06:00 PM |
Filters can be combined. Results are ordered by appointment ID. Date filters exclude appointments without a scheduled time. PO filtering checks packing-list PO numbers and linked purchase orders.
Response Formatβ
The response contains a paginated array of appointment objects, each with the following fields. Unset optional values can be null. Honor the offset in returned ISO8601 timestamps rather than assuming a particular timezone:
| Field | Type | Description |
|---|---|---|
id | Integer | Unique identifier for the appointment |
location_name | String | Name of the warehouse; included in list, show, create, and update responses |
location | String | Compatibility alias for location_name |
org | String | Organization name |
ref_number | String | Formatted appointment reference |
created_at, updated_at | String | Record creation and update timestamps |
appointment_number | Integer | Human-readable appointment number |
state | String | Current state of the appointment (e.g., "booked", "arrived", "completed") |
duration | Integer | Duration in minutes |
scheduled_at | String | ISO8601 timestamp of when the appointment is scheduled |
shipping_number | String | Reference number for shipping |
trailer_number | String | Identification number of the trailer |
bol_number | String | Bill of Lading number |
carrier_name | String | Name of the carrier company |
carrier_id | Integer | Assigned carrier company ID |
driver_name | String | Name of the driver |
driver_phone | String | Contact phone number for the driver |
driver_email | String | Contact email for the driver |
created_by | String | Name of the user who created the appointment |
outbound | Boolean | Whether this is an outbound (true) or inbound (false) appointment |
drop_trailer | Boolean | Whether this is a drop trailer appointment |
queued | Boolean | Whether this appointment is in a queue |
dock | String | Name of the assigned dock (null if yard is assigned) |
yard | String | Name of the assigned yard (null if dock is assigned) |
internal_id | String | Your internal identifier for this appointment |
free_until | String | Stored free-until timestamp; not a calculated dock-availability time |
approved_at | String | ISO8601 timestamp of when the appointment was approved |
arrived_at | String | ISO8601 timestamp of when the appointment arrived |
started_at | String | ISO8601 timestamp of when the appointment started loading/unloading |
completed_at | String | ISO8601 timestamp of when the appointment completed loading/unloading |
left_at | String | ISO8601 timestamp of when the appointment left |
cancelled_at | String | ISO8601 timestamp of when the appointment was cancelled (null if active) |
custom_values | Object | Key-value pairs of custom fields |
packing_lists | Array | List of packing list objects associated with the appointment |
notes | Array | List of note objects associated with the appointment (see note format below) |
documents | Array | Documents marked safe, each with id, filename, and presigned_url |
warnings | Array | Warning messages when present; omitted when there are none |
carrier_number and checklist_values are accepted inputs but are not returned. Response keys dock and yard differ from request keys dock_name and yard_name.
Packing-list responses contain id, po_number, customer_id, customer_name, created_at, updated_at, product, supplier, unit, booked_quantity, booked_weight, actual_quantity, actual_weight, and custom_values. Associated names and numeric values can be null. Responses do not include customer_number, product_name, or unit_name.
Code Examplesβ
cURLβ
See cURL example
# Basic listing
curl -H "Authorization: Token YOUR_API_TOKEN" \
https://YOUR_LOCATION.datadocks.com/api/v1/appointments
# Filtered by date range and purchase order
curl -H "Authorization: Token YOUR_API_TOKEN" \
"https://YOUR_LOCATION.datadocks.com/api/v1/appointments?from=2023-10-01%2008:00%20AM&to=2023-10-05%2006:00%20PM&po_number=PO-12345"
JavaScriptβ
See JavaScript example
// Using fetch API with filters
const getAppointments = async (fromDate, toDate, poNumber) => {
const params = new URLSearchParams();
if (fromDate) params.append("from", fromDate);
if (toDate) params.append("to", toDate);
if (poNumber) params.append("po_number", poNumber);
const response = await fetch(
`https://YOUR_LOCATION.datadocks.com/api/v1/appointments?${params.toString()}`,
{
method: "GET",
headers: {
Authorization: "Token YOUR_API_TOKEN",
"Content-Type": "application/json",
},
}
);
// Handle potential errors
if (!response.ok) {
const errorData = await response.text();
throw new Error(
`Failed to fetch appointments: ${JSON.stringify(errorData)}`
);
}
return response.json();
};
// Processing paginated results
const getAllAppointments = async (fromDate, toDate, poNumber) => {
let currentPage = 1;
let allAppointments = [];
let hasMorePages = true;
while (hasMorePages) {
const params = new URLSearchParams({
page: currentPage.toString(),
});
if (fromDate) params.append("from", fromDate);
if (toDate) params.append("to", toDate);
if (poNumber) params.append("po_number", poNumber);
const response = await fetch(
`https://YOUR_LOCATION.datadocks.com/api/v1/appointments?${params.toString()}`,
{
method: "GET",
headers: {
Authorization: "Token YOUR_API_TOKEN",
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch appointments");
}
const appointments = await response.json();
allAppointments = [...allAppointments, ...appointments];
// Check if there are more pages
const totalPages = parseInt(response.headers.get("Total-Pages"), 10);
if (!Number.isInteger(totalPages) || totalPages < 1) {
throw new Error("Missing or invalid Total-Pages header");
}
hasMorePages = currentPage < totalPages;
currentPage++;
}
return allAppointments;
};
Sample Responseβ
See sample response example
[
{
"id": 1,
"location_name": "Main Warehouse",
"location": "Main Warehouse",
"org": "Example Organization",
"ref_number": "1",
"created_at": "2020-09-22T13:35:00-04:00",
"updated_at": "2020-09-25T13:35:00-04:00",
"appointment_number": 1,
"state": "left",
"duration": 120,
"shipping_number": "57886",
"trailer_number": "2222222",
"bol_number": "922",
"carrier_name": "FastCo",
"carrier_id": 12,
"driver_name": "Jason Smith",
"driver_phone": "+1 (555) 123-4567",
"driver_email": "jason.smith@fastco.example.com",
"created_by": "Sysadmin",
"outbound": false,
"drop_trailer": false,
"queued": false,
"dock": "Dock 2",
"yard": null,
"internal_id": "ERP-A12345",
"free_until": null,
"scheduled_at": "2020-09-30T06:00:00-04:00",
"approved_at": "2020-09-22T13:35:00-04:00",
"arrived_at": null,
"started_at": "2020-09-24T13:35:00-04:00",
"completed_at": "2020-09-24T13:35:00-04:00",
"left_at": "2020-09-25T13:35:00-04:00",
"cancelled_at": null,
"custom_values": {
"expected_at": "2020-10-01",
"travel_type": "Truck",
"forklift_operator": "Sue",
"inspection_passed": "1"
},
"packing_lists": [
{
"id": 4,
"created_at": "2020-09-22T13:35:00-04:00",
"updated_at": "2020-09-25T13:35:00-04:00",
"supplier": null,
"po_number": "A-2000",
"customer_name": "FishCo",
"customer_id": 34,
"product": "Trout",
"unit": "Skid",
"booked_quantity": 10,
"booked_weight": 152,
"actual_quantity": 12,
"actual_weight": 160,
"custom_values": {
"barcode": "11223344",
"dimensions": "S",
"temperature_celcius": "-5"
}
}
],
"notes": [
{
"id": 3,
"body": "First note.",
"note_type": "user_note"
}
],
"documents": []
}
]
Paginationβ
The response contains up to 20 appointments per page. Headers include Current-Page, Page-Items, Total-Pages, Total-Count, and Link. Requests beyond the last page return the last page, so use the headers rather than waiting for an empty page. For detailed information about pagination headers and navigation, please refer to the Pagination documentation.
Common Gotchas and Troubleshootingβ
-
Date/time parsing issues:
fromandtoparameters are interpreted in the location's timezone. If you experience unexpected results, ensure you're providing timezone information.β Good: from=2023-10-01T08:00:00-04:00β Good: from=2023-10-01 08:00 AM EDTβ Good: from=2023-10-01 (midnight in the location timezone) -
PO number filtering is case-insensitive but requires an exact match. Partial matches won't work.
β Will match: po_number=PO-12345β Will match: po_number=po-12345 (case-insensitive)β Won't match: po_number=12345 (partial) -
Malformed date handling: Malformed dates do not have a consistent validation response: parsing can produce an empty result or raise an error. Prefer ISO8601 values and URL-encode query parameters.
-
Non-recurring appointments only: This endpoint only returns non-recurring appointments. Recurring appointment templates are not included in the results.
-
Performance considerations: When dealing with large date ranges, consider breaking your queries into smaller time chunks for better performance (e.g., weekly instead of monthly).
Creating an Appointmentβ
Purposeβ
Create a new appointment at a specific dock or yard, with optional packing lists and metadata. This is the primary way to schedule new appointments in your warehouse.
Business Use Casesβ
- System Integration: Schedule appointments directly from your ERP, WMS, or TMS
- Automated Scheduling: Create appointments based on business rules or triggers
- Carrier Self-Service: Allow carriers to book appointments through your portal
- Mobile Applications: Enable appointment creation from warehouse mobile apps
- Order Fulfillment: Automatically create outbound appointments when orders are ready
HTTP Requestβ
POST https://[location_subdomain].datadocks.com/api/v1/appointments
Request Bodyβ
| Parameter | Type | Required | Description | Constraints | Default | Example |
|---|---|---|---|---|---|---|
scheduled_at | String | No | ISO8601 date/time when appointment is scheduled | Past dates depend on permissions; not before 2000-01-01 | None | "2023-10-15T09:00:00-04:00" |
duration | Integer | No | Duration in minutes | Must be > 0 | Calculated from booking rules | 120 |
dock_name | String | No* | Name of dock to assign | Case-insensitive lookup | None | "Dock 1" |
yard_name | String | No* | Name of yard to assign | Case-insensitive lookup | None | "Yard A" |
carrier_name | String | No** | Name of carrier | 2β64 characters when required | None | "FastCo Logistics" |
carrier_id | Integer | No | Accessible carrier ID; a changed nonblank ID takes precedence over name/number | Must be accessible | None | 123 |
carrier_number | String | No | ID of carrier in your system | None | None | "CARRIER-123" |
shipping_number | String | No** | Shipping reference number | None | None | "SHIP-9876" |
trailer_number | String | No** | ID of trailer | None | None | "TRAILER-456" |
bol_number | String | No** | Bill of Lading number | 2β256 characters when nonblank | None | "BOL-789" |
driver_name | String | No** | Name of driver | 2β64 characters when nonblank | None | "John Smith" |
driver_phone | String | No** | Driver's contact phone | 10β20 characters when nonblank | None | "+1 (555) 123-4567" |
driver_email | String | No** | Driver's contact email | 7β128 characters when nonblank; no email syntax check | None | "driver@carrier.com" |
outbound | Boolean | No | Whether appointment is outbound | None | User preference, otherwise location preference | true |
drop_trailer | Boolean | No | Whether this is a drop trailer | None | false | false |
queued | Boolean | No | Whether this is a queued appointment | None | false | false |
free_until | String | No | Stored free-until timestamp | No general comparison with scheduled_at; may be required | None | "2023-10-15T11:00:00-04:00" |
internal_id | String | No | Your internal identifier for this appointment | None | None | "ERP-A12345" |
approved_at | String | No | ISO8601 date/time when appointment was approved | None | None | "2023-10-14T09:00:00-04:00" |
arrived_at | String | No | ISO8601 date/time when appointment arrived | None | None | "2023-10-15T08:45:00-04:00" |
started_at | String | No | ISO8601 date/time when appointment started loading | None | None | "2023-10-15T09:05:00-04:00" |
completed_at | String | No | ISO8601 date/time when appointment finished loading | None | None | "2023-10-15T10:30:00-04:00" |
left_at | String | No | ISO8601 date/time when appointment left | None | None | "2023-10-15T10:45:00-04:00" |
cancelled_at | String | No | ISO8601 date/time when appointment was cancelled | None | None | "2023-10-14T10:00:00-04:00" |
packing_lists | Array | No** | Array of packing list objects | None | None | See packing list format below |
notes | Array | No | Array of note objects | None | None | See note format below |
custom_values | Object | No** | Key-value pairs of custom fields. The key will be in lower case, with underscores in place of spaces. | Based on location settings | None | {"reference": "ABC123"} |
checklist_values | Object | No | Stored checklist values; not returned in responses | Based on location settings | None | {"safety_check": "Passed"} |
* Assignment depends on configuration and auto-assignment. Unknown names resolve to no association rather than a dedicated not-found error; validation and auto-assignment may then apply.
** Might be required based on the Location preferences
Automatic Appointment Approvalβ
By default, appointments created via API may be automatically approved based on your location's settings (if scheduled_at is present). This behavior is controlled by the internal preferences (contact support to change the API auto-approval setting).
An appointment can be created without scheduled_at. Omitting duration invokes the booking defaults; relevant changes can cause recalculation. Explicit approval and later state transitions can populate approved_at even with automatic approval disabled.
Carrier Assignment Logicβ
A changed, nonblank carrier_id takes precedence and must refer to an accessible company. Otherwise, carrier_number is matched case-insensitively when the name is blank or unchanged. If no number matches, it becomes the name used for subsequent assignment. A changed name generally takes precedence over number lookup. Name assignment can match or create a carrier, depending on location settings and permissions. Sending the same ID again does not count as changing it.
Packing List Formatβ
{
"po_number": "PO-12345",
"customer_name": "ACME Corp",
"customer_number": "CUST-001",
"product_name": "Widgets",
"unit_name": "Skid",
"booked_quantity": 10,
"booked_weight": 500,
"actual_quantity": null,
"actual_weight": null,
"custom_values": {
"temperature": "-5",
"fragile": "Yes"
}
}
Packing List Parameter Detailsβ
| Parameter | Type | Required | Description | Constraints | Default | Example |
|---|---|---|---|---|---|---|
id | Integer | No* | ID of existing packing list (required for updates/deletion) | Must be a valid ID for an existing packing list linked to the appointment | None | 123 |
po_number | String | No** | Purchase order number | Max length varies; check location settings | None | "PO-12345" |
customer_name | String | No** | Name of the customer company | Length: 2β255 chars (if provided) | None | "ACME Corp" |
customer_number | String | No | Customer company number (used for lookup if name/ID not given) | None | None | "CUST-001" |
customer_id | Integer | No | Direct ID of the customer company (overrides name/number lookup) | Must be a valid Company ID accessible to the location | None | 456 |
product_name | String | No** | Name of the product | Must exist or be creatable via location settings | None | "Widgets" |
unit_name | String | No** | Name of the unit | Must exist or be creatable via location settings | None | "Skid" |
booked_quantity | Decimal | No** | Quantity booked | Must be >= 0; greater than zero when required; within system limits | None | 10 or 10.5 |
booked_weight | Decimal | No** | Weight booked | Must be >= 0; greater than zero when required; within system limits | None | 500 or 500.75 |
actual_quantity | Decimal | No | Actual quantity received/shipped (typically set on update) | Must be >= 0 and within system limits | null | 9 or 9.5 |
actual_weight | Decimal | No | Actual weight received/shipped (typically set on update) | Must be >= 0 and within system limits | null | 450 or 450.25 |
custom_values | Object | No** | Key-value pairs for packing list custom fields. The key will be in lower case, with underscores in place of spaces. | Required custom fields are validated; unknown keys are not filtered | {} | {"lot_number": "A123"} |
_destroy | Boolean | No* | Set to true to remove the packing list (on update only) | Only applicable during PUT requests | false | true |
* Only relevant/used during PUT /appointments/:id requests when modifying or deleting existing packing lists.
** May be required based on Location field configurations. Check your Location settings for specific requirements.
Customer Assignment Logicβ
When creating or updating packing lists, a changed, nonblank customer_id takes precedence and must refer to an accessible company. Sending the same ID again does not count as changing it. Otherwise:
-
If
customer_numberis provided and the name is blank or unchanged, the system will:- Search for a company with a matching company number
- If found, automatically populate
customer_nameandcustomer_id - If not found, set
customer_nameto match the providedcustomer_number
-
A changed name generally takes precedence over number lookup. Subsequent name assignment can match or create a customer, depending on settings and permissions.
Product and Unit Handlingβ
When specifying products and units, case-insensitive matching ignores surrounding whitespace. Automatic creation is disabled by default and can be enabled separately through support. Unknown names do not always cause an error: required-field rules and product validation determine whether the request fails, and unresolved associations can remain unset. Product-specific unit restrictions also apply.
On update, omitting product_name or unit_name preserves that association. An empty value requests clearing it, subject to validation.
Note Formatβ
{
"body": "Driver requires lift gate"
}
New notes are automatically associated with the current API user. Include id to edit an existing note, or id and _destroy: true to request deletion. Use notes rather than the legacy scalar note key, which has no model writer.
Responses also return a read-only note_type for each note:
| Value | Meaning |
|---|---|
user_note | A note written by a person. This is the default, and the only type you can create. |
cancellation_note | Recorded by DataDocks when an appointment is cancelled with a reason from the Booking Portal. |
note_type is assigned by DataDocks and is ignored if you send it. Cancellation notes cannot be
deleted β they document what happened to the appointment, so a _destroy sent for one is rejected
and the whole update fails.
Responseβ
A successful request returns a 200 OK response with the full appointment object, including the generated id and other system-assigned values.
Code Examplesβ
cURLβ
See cURL example
curl -H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-X POST \
-d '{
"appointment": {
"scheduled_at": "2023-10-15T09:00:00-04:00",
"duration": 120,
"dock_name": "Dock 1",
"carrier_name": "FastCo Logistics",
"carrier_number": "CARRIER-123",
"trailer_number": "TRAILER-456",
"driver_name": "John Smith",
"driver_phone": "+1 (555) 123-4567",
"driver_email": "john.smith@fastco.example.com",
"outbound": false,
"internal_id": "ERP-A12345",
"packing_lists": [
{
"po_number": "PO-12345",
"product_name": "Widgets",
"unit_name": "Skid",
"booked_quantity": 10,
"booked_weight": 500
}
],
"notes": [
{
"body": "Driver requires lift gate"
}
],
"custom_values": {
"reference": "ABC123",
"priority": "High"
},
"checklist_values": {
"safety_check": "Scheduled",
"dock_seal": "Required"
}
}
}' \
https://YOUR_LOCATION.datadocks.com/api/v1/appointments
JavaScriptβ
See JavaScript example
const createAppointment = async (
apiToken,
locationSubdomain,
appointmentData
) => {
try {
const response = await fetch(
`https://${locationSubdomain}.datadocks.com/api/v1/appointments`,
{
method: "POST",
headers: {
Authorization: `Token ${apiToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ appointment: appointmentData }),
}
);
if (!response.ok) {
const errorData = await response.text();
const errorMessages = errorData || `HTTP ${response.status}`;
throw new Error(`Failed to create appointment:\n${errorMessages}`);
}
return await response.json();
} catch (error) {
console.error("API Error:", error);
throw error;
}
};
// Example usage with complete data
const appointmentData = {
scheduled_at: "2023-10-15T09:00:00-04:00",
duration: 120,
dock_name: "Dock 1",
carrier_name: "FastCo Logistics",
carrier_number: "CARRIER-123",
trailer_number: "TRAILER-456",
driver_name: "John Smith",
driver_phone: "+1 (555) 123-4567",
driver_email: "john.smith@fastco.example.com",
outbound: false,
internal_id: "ERP-A12345",
packing_lists: [
{
po_number: "PO-12345",
product_name: "Widgets",
unit_name: "Skid",
booked_quantity: 10,
booked_weight: 500,
},
],
notes: [
{
body: "Driver requires lift gate",
},
],
custom_values: {
reference: "ABC123",
priority: "High",
},
checklist_values: {
safety_check: "Scheduled",
dock_seal: "Required",
},
};
// Create the appointment
createAppointment("YOUR_API_TOKEN", "your-warehouse", appointmentData)
.then((appointment) => {
console.log("Created appointment:", appointment.id);
// Process the newly created appointment
})
.catch((error) => {
// Handle any errors
});
Error Handlingβ
| Error Code | Description | Possible Cause |
|---|---|---|
| 400 | Bad Request | Malformed request, such as a missing appointment wrapper |
| 404 | Not Found | Nested record ID not found in the accessible scope |
| 422 | Unprocessable Entity | Business validation failed (e.g., scheduling conflict, full dock) |
| 401 | Unauthorized | Invalid or missing API token |
| 403 | Forbidden | Insufficient permissions to create appointments |
Model validation failures generally return 422. Unknown dock, yard, product, or unit names do not inherently produce 404. Unpaid or deleted locations can return 402; throttled requests return 429. Error bodies can be JSON, plain text, or empty. Nested packing-list error keys can include an index.
Sample Error Responseβ
{
"errors": {
"driver_name": ["is too short (minimum is 2 characters)"]
}
}
Common Gotchas and Troubleshootingβ
-
Dock vs. Yard Assignment: Prefer providing either
dock_nameoryard_name. If both associations are set, a changed yard wins; otherwise the dock wins. On update, an omitted name preserves the assignment unless other model behavior changes it, while an empty string requests clearing it. -
Time Formats: Explicit timezone information is recommended. Without it, times are interpreted in the location's timezone.
β Good: "2023-10-15T09:00:00-04:00"β Accepted: "2023-10-15T09:00:00" (location timezone) -
Product/Unit Creation: Automatic creation is disabled by default. Unknown names may fail validation or leave an unset association, depending on configuration. Ask support to enable automatic creation if needed.
-
Customer Lookups: Customer numbers are matched case-insensitively. For example, "CUST-001" and "cust-001" will both match the same customer.
-
Packing List Deletion: To delete a packing list when updating an appointment, include the packing list's
idand set_destroy: true.{"id": 123,"_destroy": true} -
Recurring Appointments: The API does not support creating or modifying recurring appointments. Use the web interface for these operations.
-
Custom Fields: Required custom fields are validated, but unknown keys are not automatically filtered out.
-
Automatic Approval: Check with your administrator about your location's automatic approval settings. Disabling API auto-approval skips the internal auto-approval path; explicit approval and other transitions can still set approval timestamps.
Performance Optimization Tipsβ
- Batch Your Requests: When creating multiple appointments, space your API calls to avoid rate limiting
- Minimize Custom Values: Only include custom fields that are actually needed
- Preload Resources: Make sure your products, units, and carriers exist before referencing them
- Validate Locally: Validate data formats client-side to minimize failed requests
Retrieving a Single Appointmentβ
Purposeβ
Get detailed information about a specific appointment by ID. Use this endpoint when you need comprehensive data about a particular appointment, including its current status, associated packing lists, and metadata.
Business Use Casesβ
- Status Tracking: Check the current state of an appointment
- Arrival Monitoring: View arrival and departure times
- Document Verification: Check attached documents and packing lists
- Carrier Information: Retrieve driver and trailer details
- Custom Field Access: Access location-specific custom fields; checklist values are not returned
HTTP Requestβ
GET https://[location_subdomain].datadocks.com/api/v1/appointments/:id
Path Parametersβ
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer | Yes | Unique ID of the appointment |
Responseβ
A successful request returns a 200 OK response with the full appointment object in the same format as the list response.
Code Examplesβ
cURLβ
See cURL example
curl -H "Authorization: Token YOUR_API_TOKEN" \
https://YOUR_LOCATION.datadocks.com/api/v1/appointments/123
JavaScriptβ
See JavaScript example
const getAppointment = async (appointmentId) => {
try {
const response = await fetch(
`https://YOUR_LOCATION.datadocks.com/api/v1/appointments/${appointmentId}`,
{
method: "GET",
headers: {
Authorization: "Token YOUR_API_TOKEN",
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
if (response.status === 404) {
throw new Error(`Appointment #${appointmentId} not found`);
}
const errorData = await response.text();
throw new Error(
`Failed to retrieve appointment: ${JSON.stringify(errorData)}`
);
}
return await response.json();
} catch (error) {
console.error("Error fetching appointment:", error);
throw error;
}
};
// Usage
getAppointment(123)
.then((appointment) => {
console.log(
`Appointment #${appointment.id} is currently ${appointment.state}`
);
// Check if appointment is completed
if (appointment.completed_at) {
const completionTime = new Date(appointment.completed_at);
console.log(`Completed at: ${completionTime.toLocaleString()}`);
}
// Calculate total appointment duration
if (appointment.left_at && appointment.arrived_at) {
const arrivedTime = new Date(appointment.arrived_at);
const leftTime = new Date(appointment.left_at);
const durationMinutes = Math.round((leftTime - arrivedTime) / 60000);
console.log(`Total facility dwell time: ${durationMinutes} minutes`);
}
})
.catch((error) => {
// Handle error gracefully
if (error.message.includes("not found")) {
// Handle not found case
} else {
// Handle other errors
}
});
Error Responsesβ
| Error Code | Description | Possible Cause |
|---|---|---|
| 404 | Not Found | Appointment ID doesn't exist |
| 401 | Unauthorized | Invalid or missing API token |
| 403 | Forbidden | Insufficient permissions to view |
Limitationsβ
- Only non-recurring appointments can be retrieved with this endpoint
- If you need to view recurring appointment templates, use the web interface
Updating an Appointmentβ
Purposeβ
Update an existing appointment's details, status, or associated data. This endpoint accepts the fields listed above, subject to configuration and permissions. Documents and signatures cannot be uploaded through this endpoint.
Business Use Casesβ
- Status Updates: Mark appointments as arrived, started, completed, or left
- Schedule Changes: Adjust appointment times or durations
- Detail Updates: Update carrier information, trailer numbers, or shipping references
- Add/Update Packing Lists: Modify the products, quantities, or custom values
- Note Management: Add notes to document important information
HTTP Requestβ
PUT https://[location_subdomain].datadocks.com/api/v1/appointments/:id
Path Parametersβ
| Parameter | Type | Required | Description |
|---|---|---|---|
id | Integer | Yes | Unique ID of the appointment |
Request Bodyβ
The request body accepts the same parameters as the create endpoint. Only the fields you want to change need to be included.
Status Transition Flowβ
When updating appointment status fields, they should generally follow this sequence:
scheduled_at β approved_at β arrived_at β started_at β completed_at β left_at
Permissions and validation govern changes. State is derived from timestamps; state itself is not a writable field. When state changes, callbacks can fill missing earlier timestamps or clear later ones. For example, setting left_at fills missing approval, arrival, start, and completion timestamps with the departure time. Send measured timestamps when available.
Common Update Scenariosβ
Marking an Appointment as Arrivedβ
{
"appointment": {
"arrived_at": "2023-10-15T08:45:00-04:00",
"trailer_number": "TRAILER-789"
}
}
Updating Packing List Quantitiesβ
{
"appointment": {
"packing_lists": [
{
"id": 123,
"actual_quantity": 9,
"actual_weight": 450
}
]
}
}
Adding a New Noteβ
{
"appointment": {
"notes": [
{
"body": "Truck arrived with damaged seal. Inspection completed."
}
]
}
}
Removing a Packing Listβ
{
"appointment": {
"packing_lists": [
{
"id": 123,
"_destroy": true
}
]
}
}
Marking an Appointment as Completedβ
{
"appointment": {
"completed_at": "2023-10-15T10:30:00-04:00",
"left_at": "2023-10-15T10:45:00-04:00",
"checklist_values": {
"dock_condition": "Clean",
"paperwork_complete": "Yes"
}
}
}
Code Examplesβ
cURLβ
See cURL example
curl -H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-X PUT \
-d '{
"appointment": {
"trailer_number": "UPDATED-TRAILER-789",
"arrived_at": "2023-10-15T08:45:00-04:00",
"notes": [
{
"body": "Truck arrived with different trailer number than scheduled."
}
]
}
}' \
https://YOUR_LOCATION.datadocks.com/api/v1/appointments/123
JavaScriptβ
See JavaScript example
const updateAppointment = async (appointmentId, updateData) => {
try {
const response = await fetch(
`https://YOUR_LOCATION.datadocks.com/api/v1/appointments/${appointmentId}`,
{
method: "PUT",
headers: {
Authorization: "Token YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ appointment: updateData }),
}
);
if (!response.ok) {
const errorData = await response.text();
throw new Error(
`Failed to update appointment: ${JSON.stringify(errorData)}`
);
}
return await response.json();
} catch (error) {
console.error("Error updating appointment:", error);
throw error;
}
};
// Example: Mark appointment as arrived and started
const markAppointmentArrived = async (appointmentId, arrivalTime) => {
const now = arrivalTime || new Date().toISOString();
try {
const updatedAppointment = await updateAppointment(appointmentId, {
arrived_at: now,
notes: [
{
body: `Truck arrived at ${new Date(now).toLocaleTimeString()}`,
},
],
});
console.log(
`Successfully marked appointment #${updatedAppointment.id} as arrived`
);
return updatedAppointment;
} catch (error) {
console.error(
`Failed to mark appointment #${appointmentId} as arrived:`,
error
);
throw error;
}
};
// Example: Update packing list quantities
const updatePackingListQuantities = async (
appointmentId,
packingListId,
actualQuantity,
actualWeight
) => {
try {
const updatedAppointment = await updateAppointment(appointmentId, {
packing_lists: [
{
id: packingListId,
actual_quantity: actualQuantity,
actual_weight: actualWeight,
},
],
});
console.log(
`Successfully updated packing list #${packingListId} quantities`
);
return updatedAppointment;
} catch (error) {
console.error(`Failed to update packing list quantities:`, error);
throw error;
}
};
Error Handlingβ
| Error Code | Description | Possible Cause |
|---|---|---|
| 400 | Bad Request | Malformed request; model validation generally returns 422 |
| 404 | Not Found | Appointment ID doesn't exist |
| 422 | Unprocessable Entity | Business validation failed (e.g., invalid transition) |
| 401 | Unauthorized | Invalid or missing API token |
| 403 | Forbidden | Insufficient permissions to update |
Important Limitationsβ
-
Recurring Appointments: The API does not support updating recurring appointment templates. The endpoint will return an error if you attempt to update a recurring appointment.
-
Partial Updates: Only include the fields you want to update. Omitted ordinary fields are preserved, but callbacks can change timestamps, duration, and associations. JSON objects such as
custom_valuesandchecklist_valuesreplace the whole attribute rather than merging individual keys; preserve existing keys explicitly. -
Nested Objects: When updating nested objects like packing lists, you must include the
idof the existing object to update it, otherwise a new object will be created. Omitting existing entries does not delete them. -
Deletion Not Supported: There is no API endpoint to delete appointments. To cancel an appointment, set the
cancelled_atfield instead.
Status Transition Best Practicesβ
Send actual timestamps in their logical sequence when available. A later-precedence timestamp controls the state even if you update an earlier one. The normal sequence is:
- Create appointment (
scheduled_at) - Approve appointment (
approved_at) - Mark as arrived (
arrived_at) - Mark as started (
started_at) - Mark as completed (
completed_at) - Mark as left (
left_at)
Each status update should include relevant metadata, such as actual quantities for packing lists when marking as completed.
Appointment Lifecycle & Workflowβ
Understanding the appointment lifecycle is critical for effective API integration. Each appointment follows a defined state machine that governs its progression through your warehouse operations.
Appointment States Visual Workflowβ
The following diagram illustrates the typical lifecycle of an appointment:
ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ
β Booked βββββΆβ Arrived βββββΆβ Started βββββΆβ Completed βββββΆβ Left β
ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ ββββββββββββββ
β
β ββββββββββββββ
βββββββββββββββββββββββββββββββΆβ Cancelled β
ββββββββββββββ
State Transition Eventsβ
Each transition is triggered by updating the corresponding timestamp field:
| From | To | Timestamp Field | Description |
|---|---|---|---|
| Needs booking | Pending | scheduled_at | Appointment with scheduled at |
| Pending | Booked | approved_at | Appointment approval (may be automatic) |
| Booked | Arrived | arrived_at | Truck has arrived at facility |
| Arrived | Started | started_at | Loading/unloading has begun |
| Started | Completed | completed_at | Loading/unloading is finished |
| Completed | Left | left_at | Truck has departed from facility |
| Any | Cancelled | cancelled_at | Appointment cancelled |
The returned states are needs_booking, pending, booked, arrived, started, completed, left, and cancelled. Timestamp precedence is cancelled_at, left_at, completed_at, started_at, arrived_at, approved_at, then scheduled_at. Scheduling may automatically produce booked rather than pending. Clearing cancelled_at lets the state be recalculated from remaining timestamps, subject to permissions.
Data Collection During Transitionsβ
Each state transition is an opportunity to collect important operational data:
Arrivedβ
- Update driver information if changed
- Verify trailer number
- Record arrival time for on-time performance
- Document any discrepancies or issues
Startedβ
- Document dock assignment changes
- Record loading/unloading start time
- Begin tracking operational duration
Completedβ
- Record actual quantities received/shipped
- Document quality issues or discrepancies
- Collect signatures or confirmations through the appropriate application workflow
- Upload documents through the application; these endpoints do not accept uploads
Leftβ
- Calculate total facility time
- Record departure time for yard management
- Complete checklist items
Implementation Best Practicesβ
- Validate State Transitions: Ensure your application validates the logical sequence of transitions
- Include Metadata: Each status update should include relevant metadata
- Add Context Notes: Automatically generate notes to document each transition
- Trigger Notifications: Use webhooks to notify relevant stakeholders of important transitions
- Record Timing Metrics: Track how long appointments spend in each state
Security Best Practicesβ
Protecting your warehouse data requires implementing proper security measures for API access.
Secure Storageβ
- Never hardcode tokens: Store tokens in environment variables or secure credential stores
- Encrypt at rest: Ensure tokens are encrypted when stored
- Use secrets management: Consider tools like HashiCorp Vault or AWS Secrets Manager
Connection Securityβ
- Always use HTTPS: Never make API calls over unencrypted connections
- Validate certificates: Verify SSL/TLS certificates on all API calls
Additional Security Measuresβ
- Set up monitoring: Establish alerts for suspicious API activity
- Create a security incident response plan: Know what to do if a token is compromised
Related Endpointsβ
- Products API - Manage products referenced in packing lists
- Purchase Orders API - Manage POs associated with appointments
- Companies API - Manage carriers and customers
- Webhooks - Get real-time notifications about appointment changes
Appointment Deletion (Not Supported)β
Important Limitationβ
The Appointments API does not support deletion of appointments. Use cancellation to retain the appointment record.
Alternatives to Deletionβ
Instead of deleting appointments, use one of these approaches:
- Cancel the appointment by setting the
cancelled_atfield - Update appointment details if you need to change scheduling information
- Maintain metadata in custom fields to track appointment status in your system
Cancelling an Appointmentβ
Cancel by setting cancelled_at. Any note you send alongside it is an ordinary user_note:
cancellation notes are only produced by the Booking Portal's cancellation flow, where the facility
can require carriers to give a reason.
See cURL example
curl -H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-X PUT \
-d '{
"appointment": {
"cancelled_at": "2023-10-14T15:30:00-04:00",
"notes": [
{
"body": "Cancelled due to weather conditions."
}
]
}
}' \
https://YOUR_LOCATION.datadocks.com/api/v1/appointments/123
API Cookbook: Common Scenariosβ
This section provides ready-to-use recipes for common integration scenarios. Copy, adapt, and use these examples to accelerate your integration.
Recipe: Sync Outbound Shipments from ERPβ
This recipe demonstrates how to automatically create appointments for outbound shipments when they're ready in your ERP system.
See JavaScript example
/**
* Create an outbound appointment from shipping data
* @param {Object} shipment - Shipping data from ERP
* @returns {Object} - Created appointment
*/
async function createOutboundAppointment(shipment) {
// Calculate appointment duration based on item count
const duration = Math.max(30, shipment.items.length * 15); // Minimum 30 minutes
// Format scheduled time with timezone
const scheduledDate = new Date(shipment.plannedShipDate);
const scheduledTime = scheduledDate.toISOString();
// Build packing lists from shipment items
const packingLists = shipment.items.map((item) => ({
po_number: item.purchaseOrderNumber,
product_name: item.productName,
unit_name: item.unitType,
booked_quantity: item.quantity,
booked_weight: item.weight,
customer_number: shipment.customerId,
customer_name: shipment.customerName,
}));
// Create appointment object
const appointmentData = {
scheduled_at: scheduledTime,
duration: duration,
outbound: true,
dock_name: shipment.preferredDock || "Shipping Dock",
shipping_number: shipment.shipmentId,
carrier_name: shipment.carrierName,
carrier_number: shipment.carrierId,
internal_id: `SHIP-${shipment.id}`,
custom_values: {
origin: "ERP-SYNC",
priority: shipment.priority,
department: shipment.department,
},
packing_lists: packingLists,
notes: [
{
body: `Automated outbound appointment for shipment ${shipment.shipmentId}.`,
},
],
};
// Call DataDocks API
const response = await fetch(
`https://YOUR_LOCATION.datadocks.com/api/v1/appointments`,
{
method: "POST",
headers: {
Authorization: "Token YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ appointment: appointmentData }),
}
);
if (!response.ok) {
const errorData = await response.text();
throw new Error(
`Failed to create appointment: ${JSON.stringify(errorData)}`
);
}
return await response.json();
}
Recipe: Real-time Dock Utilization Dashboardβ
This recipe shows scheduled dock utilization and facility dwell time. Supply explicit date boundaries in the location's timezone and operating minutes for that interval. Arrival-to-departure measures facility dwell, not dock occupancy; automatically filled timestamps may not represent measured activity.
See JavaScript example
/**
* Calculate dock utilization metrics
* @param {string} fromDate - Start with location timezone offset
* @param {string} toDate - Exclusive end with location timezone offset
* @param {number} operatingMinutes - Operating minutes per dock for the interval
* @returns {Object} - Scheduled utilization and facility dwell by dock
*/
async function calculateDockUtilization(fromDate, toDate, operatingMinutes) {
if (!(operatingMinutes > 0)) throw new Error("Provide operating minutes for this interval");
// Fetch appointments for the supplied interval
const appointments = await getAllAppointments(fromDate, toDate);
// Group by dock
const dockMap = {};
appointments.forEach((appt) => {
if (!appt.dock || appt.state === "cancelled") return;
if (!dockMap[appt.dock]) {
dockMap[appt.dock] = {
totalAppointments: 0,
completedAppointments: 0,
scheduledMinutes: 0,
facilityMinutes: 0,
appointmentsList: [],
};
}
// Calculate scheduled minutes
const scheduledMinutes = appt.duration || 0;
// Calculate facility dwell where arrival and departure are present
let facilityMinutes = 0;
if (appt.arrived_at && appt.left_at) {
const arrivedTime = new Date(appt.arrived_at);
const leftTime = new Date(appt.left_at);
facilityMinutes = Math.round((leftTime - arrivedTime) / 60000);
}
// Update dock metrics
dockMap[appt.dock].totalAppointments++;
dockMap[appt.dock].scheduledMinutes += scheduledMinutes;
dockMap[appt.dock].facilityMinutes += facilityMinutes;
if (appt.completed_at) {
dockMap[appt.dock].completedAppointments++;
}
dockMap[appt.dock].appointmentsList.push({
id: appt.id,
state: appt.state,
scheduled_at: appt.scheduled_at,
duration: appt.duration,
carrier_name: appt.carrier_name,
});
});
// Calculate utilization rates
const dockUtilization = {};
const businessHours = operatingMinutes;
Object.keys(dockMap).forEach((dockName) => {
const dock = dockMap[dockName];
dockUtilization[dockName] = {
...dock,
scheduledUtilization:
((dock.scheduledMinutes / businessHours) * 100).toFixed(
1
) + "%",
completionRate: dock.totalAppointments
? ((dock.completedAppointments / dock.totalAppointments) * 100).toFixed(
1
) + "%"
: "0%",
};
});
return dockUtilization;
}
Recipe: Automatic Truck Arrival Processingβ
This recipe demonstrates how to update appointment status when a truck arrives, including updating driver information.
See JavaScript example
/**
* Process truck arrival
* @param {string} appointmentId - Appointment ID
* @param {Object} arrivalData - Data collected during arrival
* @returns {Object} - Updated appointment
*/
async function processTruckArrival(appointmentId, arrivalData) {
const arrivalTime = new Date().toISOString();
// Update appointment with arrival info
const appointmentUpdate = {
arrived_at: arrivalTime,
trailer_number: arrivalData.trailerNumber || null,
driver_name: arrivalData.driverName || null,
driver_phone: arrivalData.driverPhone || null,
driver_email: arrivalData.driverEmail || null,
notes: [
{
body: `Truck arrived at ${new Date(
arrivalTime
).toLocaleString()}. Check-in processed by gate security.`,
},
],
custom_values: {
...(arrivalData.customValues || {}),
actual_arrival_time: arrivalTime,
},
};
// Add delay note if applicable
if (arrivalData.isDelayed) {
appointmentUpdate.notes.push({
body: `Truck arrived ${arrivalData.delayMinutes} minutes after scheduled time. Reason: ${arrivalData.delayReason}`,
});
}
// Call DataDocks API
const response = await fetch(
`https://YOUR_LOCATION.datadocks.com/api/v1/appointments/${appointmentId}`,
{
method: "PUT",
headers: {
Authorization: "Token YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ appointment: appointmentUpdate }),
}
);
if (!response.ok) {
const errorData = await response.text();
throw new Error(
`Failed to update appointment: ${JSON.stringify(errorData)}`
);
}
return await response.json();
}
Recipe: Bulk Appointment Status Updatesβ
This recipe sends a separate request for each update. Share a rate budget across workers using the same credentials; these requests are not an atomic batch.
See JavaScript example
/**
* Process a batch of appointment status updates
* @param {Array} updates - Array of updates to process
* @returns {Object} - Results of updates
*/
async function processBatchStatusUpdates(updates) {
const results = {
successful: [],
failed: [],
};
// Pace this worker below both API-specific limits; other workers must share the budget.
for (const update of updates) {
await new Promise((resolve) => setTimeout(resolve, 1000));
try {
const { appointmentId, status, timestamp, notes } = update;
// Determine which status field to update
let statusUpdate = {};
switch (status) {
case "arrived":
statusUpdate = { arrived_at: timestamp || new Date().toISOString() };
break;
case "started":
statusUpdate = { started_at: timestamp || new Date().toISOString() };
break;
case "completed":
statusUpdate = {
completed_at: timestamp || new Date().toISOString(),
};
break;
case "left":
statusUpdate = { left_at: timestamp || new Date().toISOString() };
break;
default:
throw new Error(`Invalid status: ${status}`);
}
// Add notes if provided
if (notes) {
statusUpdate.notes = [{ body: notes }];
}
// Call API to update appointment
const response = await fetch(
`https://YOUR_LOCATION.datadocks.com/api/v1/appointments/${appointmentId}`,
{
method: "PUT",
headers: {
Authorization: "Token YOUR_API_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({ appointment: statusUpdate }),
}
);
if (!response.ok) {
const errorData = await response.text();
throw new Error(JSON.stringify(errorData));
}
const updatedAppointment = await response.json();
results.successful.push({
appointmentId,
status,
result: updatedAppointment,
});
} catch (error) {
results.failed.push({
appointmentId: update.appointmentId,
status: update.status,
error: error.message,
});
}
}
return results;
}
Performance Optimizationβ
Optimize your API integration with these performance tips:
Efficient Data Loadingβ
- Limit results with date filtering: Always provide
fromandtoparameters for list endpoints - Cache results: Store and reuse data that doesn't change frequently
- Use pagination: Request only the data you need by page
Request Optimizationβ
- Batch updates: Group related updates together rather than making multiple API calls
- Implement concurrency control: Limit parallel requests to avoid rate limiting
- Use documented responses: Conditional GET and ETag support are not part of the current API contract
Network Performanceβ
- Keep-alive connections: Reuse connections when making multiple requests
- Send JSON request bodies: Gzip-compressed request bodies are not documented as supported
- Implement exponential backoff: When encountering rate limits, use exponential backoff strategy
Troubleshooting Common Issuesβ
Authentication Problemsβ
Symptomsβ
- 401 Unauthorized errors
- "Access denied" error messages
Solutionsβ
- Verify your API token is correct and has not been replaced
- Ensure token has proper permissions
- Check that the API user has access to the location you're accessing
- Verify proper header format:
Authorization: Token YOUR_API_TOKEN
Rate Limitingβ
Symptomsβ
- 429 Too Many Requests errors
- Sudden failure of requests that previously worked
Solutionsβ
- Share a budget across clients using the same credentials: API-specific limits are 120 requests per minute and 5,000 per hour, grouped by the authorization-header value. General request throttles also apply
- Add delays between requests in batch operations
- Honor the ISO8601
X-RateLimit-Resetheader and use backoff; 429 responses also includeX-RateLimit-LimitandX-RateLimit-Remaining - Before retrying a create after an ambiguous failure, reconcile using
internal_idor another reference to avoid duplicates;internal_idis not an idempotency key
Date/Time Issuesβ
Symptomsβ
- Appointments created at wrong times
- Filtering not returning expected results
Solutionsβ
- Always specify timezone in date strings (e.g.,
2023-10-15T09:00:00-04:00) - Be aware of daylight saving time changes
- Use ISO8601 format for all date/time values
- For date range queries, ensure
fromis beforeto
Data Validation Errorsβ
Symptomsβ
- 422 Unprocessable Entity errors
- Specific field errors in response
Solutionsβ
- Check error response for specific field validation errors
- Verify location-required fields are provided.
scheduled_atcan be omitted, and duration is calculated when omitted - Ensure referenced resources (docks, products, units) exist
- Validate data formats client-side before sending
Help and Supportβ
Finding Error Solutionsβ
If you're experiencing issues not covered in this documentation:
- Check the error response: Most API errors include specific information about what went wrong
- Review API limitations: Some operations (like recurring appointments) are not supported
- Test in smaller steps: Break down complex operations to identify the specific issue
- Check rate limits: Check the 120 requests per minute and 5,000 per hour API-specific limits, plus general request throttles
Getting Helpβ
For additional assistance with the DataDocks API:
- Documentation: Check the full API documentation
- Support: Contact support at support@datadocks.com
When contacting support, please include:
- Your location subdomain
- Request details (method, endpoint, parameters)
- Full error response
- Timestamp of the error