Skip to Content
Welcome to Zendera Knowledge Hub

Orders API

v2

Read orders, reserve tracking links, attach documents, cancel and replan, book on route-scheduling intervals, set vehicle type, read completion proofs, follow external carrier updates, and apply transformation rules in the Zendera transportation management system.

Where this fits in your operation

Once an order exists in Zendera (via import), this API handles everything that happens to it before and after transport:

  • The customer cancels in your systemcancel-orders by your order numbers; if they change their mind, replan-cancelled re-activates it.
  • Your customer portal offers delivery slots → book the chosen slot with book-on-interval.
  • Share live tracking → reserve a tracking link and put it in your order-confirmation email or SMS.
  • Paperwork must follow the goods → attach delivery notes or customs documents (created via the Documents API).
  • Invoicing needs proof → read the completion proof (signature, photos) when the order is delivered.
  • A subcontractor carries the order → follow the carrier’s progress on the external updates timeline.

Interactive API Explorer

Loading API Documentation...

Endpoints Overview

Orders are the main domain. This API covers reading orders, tracking links, document attachment, cancel/replan, booking on route-scheduling intervals, vehicle type, completion proof, external carrier updates, transformation rules, and order skills.

For creating orders, use POST /v3/orders/import — see Importing and recurring orders. The integration API does not have a single-order POST or a monolithic order update.

Draft Booking Management

  • POST /v2/drafts/{orderDraftId}/book-on-interval - Book a draft on a schedule interval
  • GET /v2/drafts/{orderDraftId}/booking - Get booking details for a draft
  • POST /v2/drafts/{orderDraftId}/cancel-booking - Cancel booking for a draft

Order Booking Management

  • POST /v2/orders/{orderId}/book-on-interval - Book an order on a schedule interval
  • GET /v2/orders/{orderId}/booking - Get booking details for an order
  • POST /v2/orders/{orderId}/cancel-booking - Cancel booking for an order

Document Management

  • POST /v2/orders/attach-documents - Attach documents to an order or draft

Order Operations

  • POST /v2/orders/cancel-orders - Cancel orders by external ID
  • POST /v2/orders/replan-cancelled - Replan one cancelled order by external ID
  • POST /v2/orders/{orderId}/apply-transformations - Run order transformation rules (with dry-run)
  • POST /v2/orders/tracking-link - Reserve a tracking link for an order
  • DELETE /v2/orders/tracking-link/{code} - Delete a tracking link reservation

Vehicle Type Management

  • GET /v2/orders/vehicle-type - Get vehicle type by external ID
  • PUT /v2/orders/vehicle-type - Set vehicle type for an order

Completion Proof

  • GET /v2/orders/{orderId}/completion-proof - Get completion proof for an order

External Carrier Updates

  • GET /v2/orders/{orderId}/external-updates - Timeline of updates from an external carrier

Order Skills

  • GET /v1/orders/{orderId}/skills - Required/prohibited skills and driver lock for an order

Reading Orders (v1)

  • GET /v1/orders - List orders in a date range, with filters and eager-loading
  • GET /v1/orders/{orderId} / GET /v1/orders/internal/{internalOrderNumber} - Read one order in full
  • GET /v1/orders/search - Search by order number, reference, or location name
  • POST /v1/orders/paginated - Paginated list by status/driver/route
  • GET /v1/orders/count - Count orders by status in a date range
  • GET /v1/orders/{orderId}/order-products - Read the products on an order
  • GET /v1/orders/{orderId}/duration - Total planned time for an order
  • GET /v1/orders/{orderId}/documentations - Driver-recorded events (see Order Documentations)

Prohibited drivers and order splitting are managed in the Zendera web application — those endpoints are not available with an API key.

Authentication

Authorization: apikey YOUR_API_KEY_HERE

Base URLs

  • Production: https://app.zenderatms.com/api/
  • Staging: https://staging.zenderatms.com/api/

Cancelling and re-activating

Cancel many orders by external ID

POST /v2/orders/cancel-orders

Body:

{ "externalIds": ["ERP-001", "ERP-002", "ERP-003"] }

The externalIds are your internalOrderNumber values — i.e. the IDs you used on import.

Response:

{ "results": [ { "externalId": "ERP-001", "result": "SUCCESS" }, { "externalId": "ERP-002", "result": "SUCCESS" }, { "externalId": "ERP-003", "result": "ORDER_NOT_FOUND" } ] }

result is one of SUCCESS, ORDER_NOT_FOUND, or UNKNOWN_RESULT.

Re-activate a cancelled order

POST /v2/orders/replan-cancelled?externalId=ERP-001

The order is identified by query param. This endpoint takes one order at a time — to replan many cancelled orders, call it once per order.

POST /v2/orders/tracking-link

Body:

{ "externalId": "ERP-001", "expirationHours": 48 }
FieldNotes
externalIdRequired. Your internalOrderNumber.
expirationHoursOptional, nullable. Hours until the links expire. Omit for the default lifetime.

This reserves (creates) tracking links for an order. The response returns separate links for the pickup and delivery, each a TrackingLinkReservation with trackingLink and code:

{ "pickup": { "trackingLink": "https://track.zenderatms.com/p/abc123xyz", "code": "abc123xyz" }, "delivery": { "trackingLink": "https://track.zenderatms.com/d/def456uvw", "code": "def456uvw" } }

The URLs are public and read-only — share them with your end customers (email, SMS, customer portal). Anyone with a URL can see live status and ETA for that one stop.

DELETE /v2/orders/tracking-link/{code}

Where {code} is the code returned when the link was reserved.

Documents

Attach a document to an order

POST /v2/orders/attach-documents

{ "externalId": "ERP-001", "documentIds": [101, 102], "attachBehavior": "APPEND" }
FieldNotes
externalIdRequired. Your internalOrderNumber.
documentIdsRequired. Array of integer document IDs.
attachBehaviorOptional. APPEND (default), REPLACE_ALL (detach all existing, attach new), or REPLACE_SAME_NAME (detach existing with the same names, attach new). Detached documents are not deleted, just unlinked.

Response:

{ "success": { "orderId": 12345, "orderDraftId": 0 }, "failure": { "reason": null } }

On failure, failure.reason is one of UNKNOWN_FAILURE_REASON, ORDER_OR_DRAFT_NOT_FOUND, or DOCUMENT_NOT_FOUND.

Creating and uploading the documents themselves happens via the Documents APIPOST /v1/documents returns the document_id values you reference here, plus a signed URL to upload the file bytes.

Booking on a route-scheduling interval

If your customer-facing flow lets the customer pick a delivery time slot, book it via:

POST /v2/orders/{orderId}/book-on-interval

The order ID is in the URL path. The body has just one field:

{ "intervalId": 42 }

Response: a ScheduleInterval describing the booked window.

Booking against a draft order

If you want to book before finalising the order:

POST /v2/drafts/{orderDraftId}/book-on-interval

{ "intervalId": 42 }

Reading a current booking

GET /v2/orders/{orderId}/booking GET /v2/drafts/{orderDraftId}/booking

Returns a DetailedBooking (intervalId, booked-at, pickup/delivery windows, etc.).

Removing a booking

POST /v2/orders/{orderId}/cancel-booking Body: {} (empty) POST /v2/drafts/{orderDraftId}/cancel-booking Body: {} (empty)

Interval IDs come from the Route Scheduling API — read the schedule’s intervals via schedule-details or interval search, and manage schedules, intervals, and capacity there. To let Zendera pick a matching slot automatically instead of booking a specific interval, use schedule-order.

Vehicle type

Read the required vehicle type

GET /v2/orders/vehicle-type?externalId=ERP-001

Response:

{ "vehicleType": { "id": 2, "name": "Truck > 3.5t" } }

Set the required vehicle type

PUT /v2/orders/vehicle-type

{ "externalId": "ERP-001", "vehicleType": { "id": 2 } }

You can identify the vehicle type by its id or name. The optimizer will reassign the order if the new vehicle type differs.

Completion proof (POD)

Read proof of delivery

GET /v2/orders/{orderId}/completion-proof

Response:

{ "proofType": "in_person", "inPersonProof": { "signatureUrl": "https://storage.googleapis.com/.../sig.png?<signed>", "signee": "John Smith", "comment": "Left at front desk", "imageUrls": ["https://storage.googleapis.com/.../photo1.jpg?<signed>"] }, "contactlessProof": { "signatureUrl": "...", "signee": "...", "comment": "...", "imageUrls": ["..."] } }

The signed URLs are short-lived. If you need long-term storage of POD assets, download and re-host them on your side.

External carrier updates

When an order is fulfilled by an external carrier (see the Orders Export API), every export attempt and carrier status lands on a per-order timeline:

GET /v2/orders/{orderId}/external-updates

{ "updates": [ { "eventType": "EVENT_TYPE_DELIVERED", "label": "Delivered to recipient", "occurredAt": "2026-06-11T14:30:00Z", "receivedAt": "2026-06-11T14:30:05Z", "signeeName": "John Smith", "isContactless": false, "success": true, "failureReason": null, "rawBody": "{...}" } ] }

updates is ordered newest first. eventType is one of EVENT_TYPE_ORDER_EXPORTED (export attempt — success: false means the export failed, see failureReason), EVENT_TYPE_PICKUP_COMPLETED, EVENT_TYPE_DELIVERED, EVENT_TYPE_TERMINAL_SCAN, EVENT_TYPE_STATUS_COMMENT (free-text carrier status in label), or EVENT_TYPE_UNSPECIFIED. signeeName / isContactless are only set when the update carries proof of delivery, and rawBody is the carrier’s payload verbatim.

Applying transformation rules

If your organization has order transformation rules configured (automatic rewrites applied on order events), you can trigger or preview them:

POST /v2/orders/{orderId}/apply-transformations

{ "dryRun": true, "includePreview": true, "trigger": "TRANSFORM_TRIGGER_ORDER_UPDATED" }
FieldNotes
dryRunIf true, rules are evaluated but nothing is persisted.
includePreviewIf true, the response includes each rule’s input/output JSON.
triggerWhich event to simulate: TRANSFORM_TRIGGER_ORDER_CREATED, _ORDER_UPDATED, _ORDER_MERGED, or _ORDER_PRODUCTS_CHANGED.

Response: appliedRules[] with ruleName and (when previewing) inputJson / outputJson per rule.

Order skills

GET /v1/orders/{orderId}/skills

Returns the skill requirements that constrain which driver can take the order:

{ "requiredSkills": [{ "skillName": "ADR", "sources": [...] }], "prohibitedSkills": [], "driverLock": { "driverId": 11, "driverName": "Anna Hansen" } }

Each skill lists its sources (where the requirement comes from — e.g. a product or order type). driverLock is set when the order is locked to a specific driver; when absent, any driver with matching skills and availability can take it.

Reading orders (v1)

For keeping a downstream system in sync, use the status feed — it’s the efficient path. The v1 read endpoints below are for ad-hoc and deep reads: pulling one order with everything on it, or listing a day’s orders with specific relations loaded. They all return snake_case JSON.

List orders in a date range

GET /v1/orders?startDate=2026-06-12&endDate=2026-06-12&filters=customer_id=42&loads=OrderLocations,OrderProducts

startDate/endDate (YYYY-MM-DD) are required. filters accepts order_id, customer_id, business_id, driver_id, order_status_id, serial_code, department_id, order_type_id, vehicle_type_id, and internal_order_number. Returns an array of order objects (order_id, internal_order_number, serial_code, order_status_id, customer_id, driver_id, reference, …) with any loads relations embedded.

Read one order in full

GET /v1/orders/{orderId}?loads=Customer,Driver,OrderLocations.Address,OrderProducts.Product GET /v1/orders/internal/{internalOrderNumber}?loads=...

The second form looks up by your order number instead of Zendera’s id. loads eager-loads relations; the useful ones are Customer, Department, Driver, OrderStatus, OrderType, VehicleType, Skills, Documents, Documentations, OrderLocations (with .Address, .Location, .OrderLocationContacts, .TrackTraces), and OrderProducts (with .Product, .OrderProductSkills, .OrderProductUnits).

GET /v1/orders/search?internal_order_number=A-1001

Searches by order id, serial id, internal order number, reference, shipment id, or pickup/delivery location name. Returns a paginated wrapper: { "total": ..., "pages": ..., "page": ..., "items": [...] }.

Paginated list and count

POST /v1/orders/paginated GET /v1/orders/count?startDate=2026-06-01&endDate=2026-06-12&orderStatusID=5

The paginated body takes order_status_ids (required), start_date/end_date, and optional order_type_ids, group_ids, driver_ids, routes, page, limit, sort_by. count returns a bare integer.

Products on an order

GET /v1/orders/{orderId}/order-products GET /v1/orders/{orderId}/order-products/{orderProductId}

The read counterpart of Product Upsert: each product carries id, name, quantity, dimensions/weight, barcode_id, and the hierarchy fields parent_id / parent_sscc / atom_type (see Atoms).

Planned duration

GET /v1/orders/{orderId}/duration returns { "total_time": "1h32m10s" } — the planned travel plus service time across the order’s stops.

Key Data Models

Schedule Interval

Represents a bookable time slot with the following properties:

  • intervalId: Unique identifier for the interval
  • orderTypes: List of order types that can be booked
  • fromToZones: Zone pairs for pickup and delivery
  • freightLevels: Available freight levels
  • pickupEarliest/Latest: Pickup time window
  • deliveryEarliest/Latest: Delivery time window
  • totalAvailableSlots: Maximum bookable orders
  • bookedSlots: Currently booked orders

Completion Proof

Provides proof of delivery with two types:

  • In-Person Proof: Includes signature, signee name, comments, and images
  • Contactless Proof: Similar to in-person but for contactless deliveries
  • trackingLink: The full URL for tracking
  • code: Unique code for the tracking link

Common gotchas

  • No single-order POST. Even one order at a time goes through POST /v3/orders/import.
  • No monolithic order update. “Updating an order” means calling per-area endpoints: vehicle type, products upsert, atoms tree, attach documents.
  • No order status change endpoint. Status transitions happen as a result of driver actions in the mobile app. You read them via the status feed.
  • externalId everywhere. Most endpoints that act on a single order key off your internalOrderNumber, exposed in the API as externalId.
  • camelCase JSON on the v2/v3 endpoints (internalOrderNumber, documentIds, nextToken). Some v1 endpoints (Documents, Products) use snake_case instead — check the page you’re integrating against.

Error Handling

The API uses standard HTTP status codes and returns error details in the response:

{ "code": 404, "message": "Order not found", "details": [] }

Common error scenarios:

  • ORDER_OR_DRAFT_NOT_FOUND: The specified order or draft doesn’t exist
  • DOCUMENT_NOT_FOUND: Referenced document not found
  • ORDER_NOT_FOUND: Order with given external ID not found
Last updated on