Route Scheduling API
v1Manage route schedules and their bookable intervals, auto-book orders onto matching slots, adjust capacity, and list bookings.
Route scheduling is Zendera’s capacity calendar: a schedule holds intervals — bookable slots, each with a pickup window, a delivery window, a booking cutoff, and a number of available slots — and orders get booked onto them.
Where this fits in your operation
- Offer real delivery slots in your webshop or customer portal: read the schedule’s intervals, show the ones that match the order, and book the customer’s choice.
- Maintain the capacity calendar from your planning system: create and update schedules and intervals via the CRUD endpoints instead of clicking them in one by one.
- React to capacity changes: a vehicle drops out for Thursday — lower that interval’s slot count so no more orders get booked onto it.
- Reconcile bookings: list bookings per schedule to see which orders landed on which slots.
Interactive API Explorer
Loading API Documentation...
Authentication
Authorization: apikey YOUR_API_KEY_HEREBase URLs
- Production:
https://app.zenderatms.com/api/ - Staging:
https://staging.zenderatms.com/api/
Key concepts
- Schedule (
RouteSchedule): the container. Tied to a zone area and a freight level set, with a name.intervalCountis computed at read time. - Interval (
RouteScheduleInterval): one bookable slot. Carries the pickup and delivery windows, abookBeforecutoff,availableSlots(capacity you set) andbookedSlots(engine-managed, read-only), plus its matching rules:orderTypeIds,freightLevels,fromToZones, andskills. - Booking: an order (identified by your external order ID) occupying a slot on an interval.
Note that there are two endpoint families: /v1/route-schedules + /v1/route-schedule-intervals for managing the calendar (CRUD + search), and /route-scheduling/v1/... for operating on it (auto-book, read details, list bookings, adjust availability).
Managing schedules
POST /v1/route-schedules
POST /v1/route-schedules/search
GET /v1/route-schedules/{routeScheduleId}
PUT /v1/route-schedules/{routeScheduleId}
DELETE /v1/route-schedules/{routeScheduleId}Create takes zoneAreaId, freightLevelSetId, and name. Search is page-based (page / perPage, both required) with optional zoneAreaId / freightLevelSetId filters and a searchTerm matched case-insensitively against the name.
Managing intervals
POST /v1/route-schedule-intervals
POST /v1/route-schedule-intervals/search
GET /v1/route-schedule-intervals/{intervalId}
PUT /v1/route-schedule-intervals/{intervalId}
DELETE /v1/route-schedule-intervals/{intervalId}Create example:
{
"routeScheduleId": 7,
"pickupEarliest": "2026-06-18T07:00:00Z",
"pickupLatest": "2026-06-18T09:00:00Z",
"deliveryEarliest": "2026-06-18T10:00:00Z",
"deliveryLatest": "2026-06-18T14:00:00Z",
"bookBefore": "2026-06-17T12:00:00Z",
"availableSlots": 25,
"orderTypeIds": [1, 2],
"freightLevels": [3],
"fromToZones": [{ "fromZone": "OSLO", "toZone": "BERGEN" }],
"skills": []
}Interval search requires routeScheduleId plus page / perPage, with optional pickupFrom / pickupUntil bounds on the interval’s pickupEarliest.
Reading the schedule with its intervals
GET /route-scheduling/v1/schedule-details?intervalsSince=...&intervalsUntil=...
Returns your organization’s schedule — its zoneArea, freightLevelSet, and the intervals whose pickup or delivery window overlaps the requested range. intervalsSince defaults to now, and intervalsUntil defaults to two months after intervalsSince. This is the natural source of interval IDs for a slot picker.
Booking
Auto-book the first matching interval
POST /route-scheduling/v1/schedule-order
{
"externalOrderId": "ERP-001",
"orderTypeId": 1,
"customerId": 456,
"fromZone": "OSLO",
"toZone": "BERGEN",
"freightLevel": 3
}Zendera finds an available interval matching the order type, zone pair, and freight level — respecting bookBefore and remaining slots — books the order onto it, and returns the interval’s time window (interval with intervalId and the four window timestamps).
schedule-order is idempotent per externalOrderId. If the order already has a booking, the existing booking is returned instead of creating a new one. To book a specific interval the customer chose, use POST /v2/orders/{orderId}/book-on-interval instead.
Adjust an interval’s capacity
PATCH /route-scheduling/v1/schedule-interval/{scheduleId}/interval/{intervalId}/update-availability
{ "totalSlots": 10 }Sets the interval’s total slot count (not the remaining count).
List bookings
GET /route-scheduling/v1/bookings?scheduleId=7&since=2026-06-01T00:00:00Z
scheduleId is optional. Each booking carries externalOrderId, scheduleId, scheduleIntervalId, the four window timestamps, and createdAt.
Common gotchas
- Two endpoint families. Calendar management lives under
/v1/route-schedulesand/v1/route-schedule-intervals; booking and reading live under/route-scheduling/v1/.... schedule-orderwon’t move an existing booking. SameexternalOrderIdreturns the existing booking — rebooking onto a different slot goes through the Orders API booking endpoints.update-availabilitytakes the new total, not a delta and not the remaining free slots.bookedSlotsis read-only. The booking engine maintains it; you controlavailableSlots.- Matching is exact. An order only fits an interval whose
orderTypeIds,fromToZones, andfreightLevelsall match — a failedschedule-ordercall usually means no interval matches those three, every matching interval is full, or thebookBeforecutoff has passed.
Related documentation
- Orders API — booking — book a specific interval for an order or draft
- Orders Import — orders must exist (or be drafts) before booking