Orders & Deliveries
An order is a tenant-scoped delivery job. POST /v1/orders persists unified_json (schema version 1). Status is stored in unified_json.status (string, normalized by workers and PATCH /v1/orders/:id).
Creating an order
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer ilv_… (integration key) or merchant access JWT |
Content-Type | Yes | application/json |
Idempotency-Key | No | ≤255 chars. Same tenant + key + identical JSON body replays the stored response (idempotent: true/false on 200/201). Same key with a different body → 409 idempotency_conflict. Independent of natural idempotency on (source, external_order_id). |
Required body (API behaviour)
The API validates standardized.scheduled_pickup_at, standardized.delivery_window_start, and standardized.delivery_window_end (ISO-8601 datetimes). Pickup must be in the future; delivery window start must be before end; pickup must be before window end.
curl -X POST https://api.ideliver.ng/v1/orders \
-H "Authorization: Bearer ilv_test_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: create-ord-001-retry" \
-d '{
"schema_version": "1",
"source": "api",
"external_order_id": "store-order-8842",
"raw_payload": {},
"standardized": {
"pickup_address": "12 Bode Thomas Street, Surulere, Lagos",
"dropoff_address": "14 Awolowo Road, Ikoyi, Lagos",
"customer_phone": "+2348011122233",
"customer_name": "Amara Obi",
"pickup_lat": 6.4969,
"pickup_lng": 3.3506,
"dropoff_lat": 6.4474,
"dropoff_lng": 3.4296,
"scheduled_pickup_at": "2026-05-01T14:00:00.000Z",
"delivery_window_start": "2026-05-01T15:00:00.000Z",
"delivery_window_end": "2026-05-01T18:00:00.000Z",
"notes": "Gate code 1234",
"cod_amount_minor": 250000,
"cod_currency": "NGN",
"weight_kg": 3.5,
"length_cm": 30,
"width_cm": 20,
"height_cm": 15,
"is_fragile": false
}
}'const order = await client.orders.create({
schema_version: "1",
source: "api",
external_order_id: "store-order-8842",
raw_payload: {},
standardized: {
pickup_address: "12 Bode Thomas Street, Surulere, Lagos",
dropoff_address: "14 Awolowo Road, Ikoyi, Lagos",
customer_phone: "+2348011122233",
customer_name: "Amara Obi",
pickup_lat: 6.4969,
pickup_lng: 3.3506,
dropoff_lat: 6.4474,
dropoff_lng: 3.4296,
scheduled_pickup_at: "2026-05-01T14:00:00.000Z",
delivery_window_start: "2026-05-01T15:00:00.000Z",
delivery_window_end: "2026-05-01T18:00:00.000Z",
cod_amount_minor: 250000,
cod_currency: "NGN",
weight_kg: 3.5,
length_cm: 30,
width_cm: 20,
height_cm: 15,
is_fragile: false,
},
});Core fields
| Field | Notes |
|---|---|
schema_version | Must be "1" |
source | Ingestion source (e.g. api, shopify) |
external_order_id | Your unique id — natural idempotency with source |
raw_payload | Opaque object from your system (may be {}) |
standardized.* | Addresses, phones, optional lat/lng, windows, items, notes, optional cod_amount_minor / cod_currency |
standardized.weight_kg | Optional parcel weight in kg (max 500). Enables automatic vehicle type suggestion |
standardized.length_cm | Optional parcel length in cm (max 500) |
standardized.width_cm | Optional parcel width in cm (max 500) |
standardized.height_cm | Optional parcel height in cm (max 500) |
standardized.is_fragile | Optional boolean — upgrades suggested vehicle (e.g. motorcycle → car) |
standardized.vehicle_type_hint | Optional — auto-set from dimensions when omitted: motorcycle, car, van, truck |
Response
201 (new) or 200 (duplicate external_order_id) includes order with:
id— IDeliver UUIDcustomer_tracking_url— public tracking link whenTRACKING_PUBLIC_BASE_URLis configured on the API; otherwisenullrider— assigned rider summary whenstandardized.rider_idis set
Coverage gate: When
pickup_lat/lngordropoff_lat/lngare provided, the API validates them against your merchant dispatch zones. Coordinates outside all active zones are rejected with400 OUT_OF_COVERAGE_AREA. CallGET /v1/coverage/checkfirst to verify. See API Reference — Coverage Check and Dispatch & Zones.
Order status (unified_json.status)
Statuses are free-form strings up to 128 chars; typical values include:
| Status | Meaning (typical) |
|---|---|
pending | Accepted / awaiting dispatch |
accepted | Rider accepted |
picked_up | Collected at pickup |
in_transit | En route to customer |
delivered | Completed |
cancelled | Cancelled |
Exact transitions depend on dispatch, rider app, and PATCH /v1/orders/:id. See Order lifecycle & cancellation.
Cancelling an order (merchant API)
curl -X POST "https://api.ideliver.ng/v1/orders/ORDER_UUID/cancel" \
-H "Authorization: Bearer ilv_test_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"reason":"Customer requested cancel","notes":"optional"}'- 200 — cancelled or
already_cancelled: trueif already cancelled - 409
cannot_cancel— terminal or disallowed status (same policy as admin cancel; envADMIN_ORDER_CANCEL_PRE_PICKUP_ONLYtightens rules) order.status_updatedoutbound webhook fires on successful cancel
Admin break-glass: POST /v1/admin/orders/:orderId/cancel (separate auth).
Idempotency (natural + header)
(source, external_order_id)— resubmitting the same pair returns the existing order (200) withidempotent: true.Idempotency-Key— optional header for safe retries when the body is byte-identical; conflicts return 409idempotency_conflict.
Listing & patching
GET /v1/orders— newest first; filtersstatus,external_order_id,is_test, etc.GET /v1/orders/:id— one order (merchant-scoped)PATCH /v1/orders/:id— updatestatusand/orpayment_verified(commission paths env-gated)
Next steps
- Order lifecycle & cancellation — cancel rules & status overview
- Integrator readiness — checklist (rate limits, webhooks, zones)
- Webhooks & Events — signed deliveries & retries
- Errors & Rate Limits —
429,outside_coverage, etc. - Dispatch & Zones — fare preview & coverage before dispatch