Skip to content
Developers & API

Plan and approve trips for your own riders

Turn queued OUTLET orders into trips for your online riders, approve them in one call or in the portal, and read the trips back.

3 min readUpdated Developers

On this page

These endpoints are for orders created with delivery_mode: "OUTLET". They optimise the queued orders across your online riders with the same engine as the outlet portal and, by default, assign the trips at once. MINIDROP orders are never touched. All calls need your access token.

Set BASE_URL to the API address you were given. The examples below use $BASE_URL and $ACCESS_TOKEN.

text
POST /api/orders  {..., "delivery_mode": "OUTLET"}     repeat for each orderPOST /api/trips   {}                                   send an Idempotency-Key header<- webhooks: order.updated with status ASSIGNED, then PICKED_UP, DELIVERED ...

Plan trips#

POST /api/trips. Every body field is optional.

Field

Default and meaning

order_ids

All queued OUTLET orders. Restrict to these orders (max 200)

delivery_executive_ids

All eligible riders. Restrict to these riders (they must belong to your outlet)

auto_assign

true: approve at once (trips ASSIGNED, riders notified). false: leave the batch PENDING_APPROVAL for review in the portal or with the approve call

Send the optional header Idempotency-Key: <string, max 100 chars>. Reusing a key within 24 hours returns the first response and creates nothing new, so a retry after a timeout is safe.

Terminal
curl -X POST "$BASE_URL/api/trips" \  -H "Authorization: Bearer $ACCESS_TOKEN" \  -H "Content-Type: application/json" \  -H "Idempotency-Key: dispatch-2026-10-20-1" \  -d '{}'

Response 201:

JSON
{  "success": true,  "data": {    "batch_id": "uuid",    "status": "DISPATCHED",    "is_optimized": true,    "baseline_distance_km": 42.1,    "optimized_distance_km": 27.4,    "km_saved": 14.7,    "trips": [      {        "trip_id": "uuid",        "status": "ASSIGNED",        "distance_km": 13.2,        "delivery_executive": { "id": "uuid", "name": "Ravi", "phone": "+9198..." },        "orders": [          { "order_id": "uuid", "order_number": "MD...", "reference_order_id": "POS-1", "sequence": 0, "status": "ASSIGNED", "track_url": null }        ]      }    ],    "unassigned_orders": [{ "order_id": "uuid", "reason": "UNKNOWN" }],    "skipped_orders": [{ "order_id": "uuid", "reason": "NOT_QUEUED" }]  },  "message": "Trips created and assigned"}
  • status is DISPATCHED when auto_assign is true, otherwise PENDING_APPROVAL.

  • sequence is the drop order inside the trip, starting at 0.

  • track_url is the customer tracking link of that order. It is null while the batch is PENDING_APPROVAL.

  • unassigned_orders are valid orders the optimiser could not place. They stay queued for the next call. reason is currently always UNKNOWN.

  • skipped_orders are ids from order_ids that were not eligible. reason is NOT_FOUND (also used for another outlet’s order), NOT_OUTLET_MODE, NOT_QUEUED or CANCELLED.

Errors#

Status and code

When

400 VALIDATION_ERROR

Bad body or header. Unknown delivery_executive_ids are listed in details.invalid_delivery_executive_ids

409 DISPATCH_IN_PROGRESS

Another dispatch for your outlet is running. Retry shortly

409 PENDING_BATCH_EXISTS

A batch already waits for approval. details.batch_id identifies it

409 NO_RIDERS_ONLINE

No eligible rider is online

409 RIDER_OFFLINE

A rider went offline before approval. The batch stays PENDING_APPROVAL; details.batch_id identifies it

422 NO_QUEUED_ORDERS

Nothing eligible to dispatch (details.skipped_orders when order_ids was sent)

Approve a batch#

If you used auto_assign: false, approve the batch in the outlet portal (see Review, adjust and approve each rider’s route) or with the API:

Terminal
curl -X POST "$BASE_URL/api/trips/batches/$BATCH_ID/approve" \  -H "Authorization: Bearer $ACCESS_TOKEN"

It approves a PENDING_APPROVAL batch of your outlet and returns the same data shape, with empty unassigned_orders and skipped_orders. 404 NOT_FOUND if the batch does not exist or was already processed.

Read trips#

  • GET /api/trips/:tripId returns one trip of your outlet: trip_id, batch_id, status, distance_km, delivery_executive, orders (in drop order, with status and track_url), created_at, started_at, completed_at.

  • GET /api/trips lists your trips, newest first. Query status: active (the default: PENDING_APPROVAL, CREATED, ASSIGNED, STARTED), completed or all. limit is 1 to 100 (default 50). cursor takes data.next_cursor from the previous page. The response has data.trips and data.next_cursor (null on the last page).

Why do I get NO_RIDERS_ONLINE?

No eligible rider is online. A rider counts as online with work_online: true and a location received in the last 5 minutes. See Add and manage your riders from your system.

Can I run POST /api/trips twice safely?

Yes, if you send the same Idempotency-Key within 24 hours. You get the first response back and nothing new is created.

Related guideAdd and manage your riders from your systemCreate, list, update and remove your own riders with the delivery-executives endpoints, and what the rider does next.

Type to search all guides.