Dispatch a job with proof of delivery
Scopes: dispatch:write, dispatch:read, webhooks:write.
1. Create the job
A job is 1 or more ordered stops, each a pickup or a delivery:
JOB=$(curl -s -X POST "https://api.zaitrack.app/v1/dispatch/jobs" \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"reference": "PO-88213",
"stops": [
{"kind": "pickup", "name": "Riyadh depot", "lat": 24.7136, "lon": 46.6753},
{"kind": "delivery", "name": "Al Olaya store", "address": "King Fahd Rd, Riyadh",
"lat": 24.6904, "lon": 46.6855, "windowStart": "2026-10-29T09:00:00Z", "windowEnd": "2026-10-29T11:00:00Z",
"contactName": "Store manager", "contactPhone": "+966501234567", "notify": true,
"items": [{"description": "Chilled cartons", "quantity": 24, "unit": "carton"}]}
]}')
JOB_ID=$(echo "$JOB" | jq -r '.id')
echo "$JOB" | jq '{displayNumber, status, trackingUrl}'
2. Dispatch it
curl -s -X POST "https://api.zaitrack.app/v1/dispatch/jobs/$JOB_ID:dispatch" \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d "{\"vehicleId\": \"$VEHICLE_ID\", \"driverId\": \"$DRIVER_ID\"}" | jq '.status'
vehicleId is required; driverId is optional.
3. Hear about the stops
curl -s -X POST "https://api.zaitrack.app/v1/webhooks" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://hooks.example.com/zaitrack", "events": ["zaitrack.dispatch.stop.*"]}' | jq '{id, secret}'
zaitrack.dispatch.stop.completed.v1 comes with the proof of delivery and zaitrack.dispatch.stop.late.v1 when a
stop is expected to miss its window.
4. Complete a stop
The driver's app does this; an integration can too. The proof is a recipient's name, a note, a signature image and photos, each file as base64 with its content type:
STOP_ID=$(echo "$JOB" | jq -r '.stops[1].id')
curl -s -X POST "https://api.zaitrack.app/v1/dispatch/jobs/$JOB_ID/stops/$STOP_ID:arrive" \
-H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)"
curl -s -X POST "https://api.zaitrack.app/v1/dispatch/jobs/$JOB_ID/stops/$STOP_ID:complete" \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d "{\"recipientName\": \"Faisal\", \"note\": \"Left at the cold room\",
\"signature\": {\"contentType\": \"image/png\", \"data\": \"$(base64 -w0 signature.png)\"},
\"lat\": 24.6905, \"lon\": 46.6854}" | jq '.stops[1]'
A stop that cannot be completed is failed with a reason: POST /v1/dispatch/jobs/{id}/stops/{stopId}:fail.
The completed stop's pod holds the proof; download a file of it with
GET /v1/dispatch/jobs/{id}/files/{fileId}.