Waybills
23 API calls in this section.
List Waybills
/delivery/waybills?page=1&limit=20&status=&carrier_type=&driver_id=&from_date=&to_date=&waybill_number=&warehouse_id=&direction=List waybills with pagination and filters for dispatcher/admin screens. Supports warehouse_id + direction filters for warehouse-centric views. Response includes a statuses matrix for tab counts; it respects the active non-status filters and ignores only the current status filter.
1curl --request GET "$ONDI_BASE_URL/delivery/waybills?page=1&limit=20&status=&carrier_type=&driver_id=&from_date=&to_date=&waybill_number=&warehouse_id=&direction=" \2 --header "Authorization: Bearer {{access_token}}"Query parameters
pageOptional1
Page number
limitOptional20
Items per page (max 100)
statusOptionalFilter by status: drafted, sealed, picked_up, in_transit, received, closed, cancelled
carrier_typeOptionalFilter by carrier: internal, prime, external
driver_idOptionalFilter by assigned driver UUID
from_dateOptionalStart date (YYYY-MM-DD)
to_dateOptionalEnd date (YYYY-MM-DD)
waybill_numberOptionalSearch by waybill number
warehouse_idOptionalFilter by warehouse UUID — shows waybills where this warehouse is origin or destination (combine with direction for specificity)
directionOptionalUsed with warehouse_id. 'outbound' = origin warehouse, 'inbound' = destination warehouse. Omit to match both.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybills retrieved successfully",4 "data": [5 {6 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",7 "tenant_id": "{{tenant_id}}",8 "waybill_number": "WB00001",9 "origin_type": "warehouse",10 "origin_warehouse_id": "{{warehouse_id}}",11 "origin_location": {12 "id": "{{warehouse_address_id}}",13 "full_address": "Main Warehouse, Erbil",14 "latitude": 36.191,15 "longitude": 44.01,16 "city": "Erbil",17 "state": null,18 "country": "Iraq",19 "postal_code": null,20 "country_code": "IQ",21 "contact_info": null22 },23 "destination_type": "location",24 "destination_warehouse_id": null,25 "destination_location": {26 "latitude": 36.1901,27 "longitude": 44.0091,28 "full_address": "Erbil, Kurdistan Region"29 },30 "carrier_type": "internal",31 "driver_id": "{{driver_id}}",32 "vehicle_id": "{{vehicle_id}}",33 "external_carrier_ref": null,34 "assigned_by": "{{user_id}}",35 "assignment_time": "2026-04-07T12:20:00Z",36 "status": "sealed",37 "sealed_at": "2026-04-07T12:15:00Z",38 "dispatched_at": null,39 "received_at": null,40 "received_by": null,41 "closed_at": null,42 "cancelled_at": null,43 "proof_of_delivery": null,44 "notes": "Batch for afternoon dispatch",45 "created_by": "{{user_id}}",46 "created_at": "2026-04-07T12:00:00Z",47 "updated_at": "2026-04-07T12:20:00Z",48 "item_count": 1,49 "origin_warehouse": {50 "id": "{{warehouse_id}}",51 "name": "Main Warehouse",52 "code": "WH-MAIN"53 },54 "destination_warehouse": null,55 "origin_zone": {56 "id": "{{origin_zone_id}}",57 "name": "Erbil Central",58 "code": "ERB-CENTRAL"59 },60 "destination_zone": {61 "id": "{{destination_zone_id}}",62 "name": "Erbil East",63 "code": "ERB-EAST"64 }65 }66 ],67 "statuses": [68 {69 "status": "drafted",70 "label": "Drafted",71 "count": 072 },73 {74 "status": "sealed",75 "label": "Sealed",76 "count": 177 },78 {79 "status": "picked_up",80 "label": "Picked Up",81 "count": 082 },83 {84 "status": "in_transit",85 "label": "In Transit",86 "count": 087 },88 {89 "status": "received",90 "label": "Received",91 "count": 092 },93 {94 "status": "closed",95 "label": "Closed",96 "count": 097 },98 {99 "status": "cancelled",100 "label": "Cancelled",101 "count": 0102 }103 ],104 "total": 1,105 "page": 1,106 "limit": 20107}1{2 "success": false,3 "message": "Insufficient permissions",4 "data": null5}Create Waybill
/delivery/waybillsCreate a draft waybill. You can attach deliveries at creation time or later while still drafted. The backend generates waybill_number atomically in PostgreSQL. New delivery Waybills use the format WB00001 without a hyphen; existing WB-00001 values remain valid and are not rewritten. Frontend contract: - Do not send waybill_number; it is server-generated. - On success, use data.id as the entity ID and display data.waybill_number exactly as returned. - On errors, use the top-level code for behavior and the localized message for display. - Preserve the create form on 500/409 errors so the user can retry. - Important creation codes: waybill_creation_failed (500), waybill_zone_resolution_failed (500), and waybill_number_conflict (409).
1curl --request POST "$ONDI_BASE_URL/delivery/waybills" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "origin_type": "warehouse",7 "origin_warehouse_id": "{{warehouse_id}}",8 "destination_type": "location",9 "destination_location": {10 "latitude": 36.1901,11 "longitude": 44.0091,12 "full_address": "Erbil, Kurdistan Region"13 },14 "carrier_type": "internal",15 "notes": "Batch for afternoon dispatch",16 "delivery_ids": [17 "{{delivery_id}}"18 ]19}'1{2 "origin_type": "warehouse",3 "origin_warehouse_id": "{{warehouse_id}}",4 "destination_type": "location",5 "destination_location": {6 "latitude": 36.1901,7 "longitude": 44.0091,8 "full_address": "Erbil, Kurdistan Region"9 },10 "carrier_type": "internal",11 "notes": "Batch for afternoon dispatch",12 "delivery_ids": [13 "{{delivery_id}}"14 ]15}Request body fields
origin_typeExampleExample field from the request body.
origin_warehouse_idExampleExample field from the request body.
destination_typeExampleExample field from the request body.
destination_locationExampleExample field from the request body.
destination_location.latitudeExampleExample field from the request body.
destination_location.longitudeExampleExample field from the request body.
destination_location.full_addressExampleExample field from the request body.
carrier_typeExampleExample field from the request body.
notesExampleExample field from the request body.
delivery_idsExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill created successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": {11 "id": "{{warehouse_address_id}}",12 "full_address": "Main Warehouse, Erbil",13 "latitude": 36.191,14 "longitude": 44.01,15 "city": "Erbil",16 "state": null,17 "country": "Iraq",18 "postal_code": null,19 "country_code": "IQ",20 "contact_info": null21 },22 "destination_type": "location",23 "destination_warehouse_id": null,24 "destination_location": {25 "latitude": 36.1901,26 "longitude": 44.0091,27 "full_address": "Erbil, Kurdistan Region"28 },29 "carrier_type": "internal",30 "driver_id": "{{driver_id}}",31 "vehicle_id": "{{vehicle_id}}",32 "external_carrier_ref": null,33 "assigned_by": "{{user_id}}",34 "assignment_time": "2026-04-07T12:20:00Z",35 "status": "sealed",36 "sealed_at": "2026-04-07T12:15:00Z",37 "dispatched_at": null,38 "received_at": null,39 "received_by": null,40 "closed_at": null,41 "cancelled_at": null,42 "proof_of_delivery": null,43 "notes": "Batch for afternoon dispatch",44 "created_by": "{{user_id}}",45 "created_at": "2026-04-07T12:00:00Z",46 "updated_at": "2026-04-07T12:20:00Z",47 "deliveries": [48 {49 "id": "{{delivery_id}}",50 "delivery_code": 1533,51 "barcode": "DEL1533",52 "external_reference_id": "ORD-1533",53 "status": "pending",54 "pickup_location": {55 "full_address": "Origin warehouse",56 "latitude": 36.191,57 "longitude": 44.0158 },59 "delivery_location": {60 "full_address": "Customer address",61 "latitude": 36.1901,62 "longitude": 44.009163 },64 "unit_size": 1,65 "payment_method": "cod",66 "cod_amount": 12000,67 "notes": "Handle with care",68 "created_at": "2026-04-07T11:40:00Z"69 }70 ],71 "summary": {72 "total_deliveries": 1,73 "status_breakdown": {74 "pending": 175 }76 }77 }78}1{2 "success": false,3 "message": "This field is required",4 "details": [5 {6 "field": "origin_warehouse_id",7 "message": "This field is required"8 }9 ]10}1{2 "success": false,3 "code": "delivery_already_in_waybill",4 "message": "Delivery is already linked to another waybill",5 "data": null6}1{2 "success": false,3 "code": "waybill_creation_failed",4 "message": "Unable to create the Waybill. Please try again.",5 "data": null6}1{2 "success": false,3 "code": "waybill_number_conflict",4 "message": "Unable to allocate a unique Waybill number. Please try again.",5 "data": null6}1{2 "success": false,3 "code": "waybill_zone_resolution_failed",4 "message": "Unable to validate the Waybill locations. Please try again.",5 "data": null6}Get Waybill Detail
/delivery/waybills/{{waybill_id}}Returns Waybill-level detail only. Child deliveries are intentionally excluded; load them through GET /delivery/waybills/{waybill_id}/deliveries. status_updates is the chronological audit timeline for lifecycle and custody actions. Each event contains event_type, previous/new status, timestamp, actor, optional reason/notes, and assignment metadata with previous/new driver and vehicle snapshots. Frontend should render this array in response order and show reason for driver_switched.
1curl --request GET "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill retrieved successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "status": "picked_up",9 "driver_id": "{{new_driver_id}}",10 "assignment_time": "2026-04-07T12:35:00Z",11 "status_updates": [12 {13 "event_type": "created",14 "previous_status": null,15 "new_status": "drafted",16 "timestamp": "2026-04-07T12:00:00Z",17 "actor_id": "{{user_id}}",18 "actor_role": "dispatcher",19 "actor": {20 "id": "{{user_id}}",21 "full_name": "Dispatcher User"22 },23 "metadata": {24 "previous_driver": null,25 "new_driver": null,26 "previous_vehicle": null,27 "new_vehicle": null28 }29 },30 {31 "event_type": "driver_switched",32 "previous_status": "picked_up",33 "new_status": "picked_up",34 "timestamp": "2026-04-07T12:35:00Z",35 "actor_id": "{{user_id}}",36 "actor_role": "dispatcher",37 "reason": "Previous driver had vehicle issue",38 "actor": {39 "id": "{{user_id}}",40 "full_name": "Dispatcher User"41 },42 "metadata": {43 "previous_driver_id": "{{driver_id}}",44 "new_driver_id": "{{new_driver_id}}",45 "previous_vehicle_id": "{{vehicle_id}}",46 "new_vehicle_id": "{{new_vehicle_id}}",47 "previous_driver": {48 "id": "{{driver_id}}",49 "user": {50 "full_name": "John Driver"51 }52 },53 "new_driver": {54 "id": "{{new_driver_id}}",55 "user": {56 "full_name": "Backup Driver"57 }58 },59 "previous_vehicle": {60 "id": "{{vehicle_id}}",61 "name": "Van 101"62 },63 "new_vehicle": {64 "id": "{{new_vehicle_id}}",65 "name": "Van 202"66 }67 }68 },69 {70 "event_type": "in_transit",71 "previous_status": "picked_up",72 "new_status": "in_transit",73 "timestamp": "2026-04-07T12:45:00Z",74 "actor_role": "driver",75 "actor": {76 "id": "{{driver_user_id}}",77 "full_name": "Backup Driver"78 },79 "metadata": {80 "previous_driver": null,81 "new_driver": null,82 "previous_vehicle": null,83 "new_vehicle": null84 }85 }86 ]87 }88}1{2 "success": false,3 "message": "Waybill not found",4 "data": null5}List Waybill Deliveries
/delivery/waybills/{{waybill_id}}/deliveries?page=1&limit=20&sort_by=created_at&sort_order=desc&search=&column_filters={}Returns deliveries already attached to the Waybill. Supports the same search, column filters, sorting, customer information, zone information, and pagination contract as the eligible-deliveries endpoint.
1curl --request GET "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/deliveries?page=1&limit=20&sort_by=created_at&sort_order=desc&search=&column_filters={}" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
Query parameters
pageOptional1
Page number, minimum 1
limitOptional20
Items per page, from 1 to 100
sort_byOptionalcreated_at
delivery_code, status, barcode, external_reference_id, unit_size, created_at, or customer
sort_orderOptionaldesc
asc or desc
searchOptionalSearch delivery code, barcode, external reference, or customer name
column_filtersOptional{}
URL-encoded JSON. Supports delivery_code, status, barcode, external_reference_id, pickup, delivery, unit_size, payment_method, cod_amount, created_at, and customer. pickup matches address or pickup zone; delivery matches address or dropoff zone. unit_size and cod_amount accept an exact value or {"min":value,"max":value}.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill deliveries retrieved successfully",4 "data": [5 {6 "id": "{{delivery_id}}",7 "delivery_code": "1533",8 "barcode": "DEL1533",9 "external_reference_id": "ORD-1533",10 "status": "pending",11 "pickup_location": {12 "full_address": "Origin warehouse",13 "latitude": 36.191,14 "longitude": 44.0115 },16 "delivery_location": {17 "full_address": "Customer address",18 "latitude": 36.1901,19 "longitude": 44.009120 },21 "unit_size": 1,22 "payment_method": "cod",23 "cod_amount": 12000,24 "notes": "Handle with care",25 "created_at": "2026-04-07T11:40:00Z",26 "pickup_zone_id": "{{origin_zone_id}}",27 "dropoff_zone_id": "{{destination_zone_id}}",28 "pickup_warehouse_id": "{{warehouse_id}}",29 "dropoff_warehouse_id": null,30 "is_returned": false,31 "return_reason": null,32 "return_trigger_point": null,33 "returned_at": null,34 "pickup_warehouse": {35 "id": "{{warehouse_id}}",36 "name": "Main Warehouse",37 "code": "WH-MAIN"38 },39 "dropoff_warehouse": null,40 "pickup_zone": {41 "id": "{{origin_zone_id}}",42 "name": "Central Pickup Zone",43 "code": "PZ-CENTRAL"44 },45 "dropoff_zone": {46 "id": "{{destination_zone_id}}",47 "name": "Downtown Dropoff Zone",48 "code": "DZ-DOWNTOWN"49 },50 "customer": {51 "id": "{{customer_id}}",52 "full_name": "Customer Name",53 "avatar_url": null54 }55 }56 ],57 "total": 1,58 "page": 1,59 "limit": 2060}1{2 "success": false,3 "code": "waybill_not_found",4 "message": "Waybill not found",5 "data": null6}Update Waybill
/delivery/waybills/{{waybill_id}}Update a drafted waybill only.
1curl --request PUT "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "notes": "Updated notes",7 "carrier_type": "internal"8}'1{2 "notes": "Updated notes",3 "carrier_type": "internal"4}Path parameters
waybill_idRequiredVariable used inside the request path.
Request body fields
notesExampleExample field from the request body.
carrier_typeExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill updated successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": {11 "id": "{{warehouse_address_id}}",12 "full_address": "Main Warehouse, Erbil",13 "latitude": 36.191,14 "longitude": 44.01,15 "city": "Erbil",16 "state": null,17 "country": "Iraq",18 "postal_code": null,19 "country_code": "IQ",20 "contact_info": null21 },22 "destination_type": "location",23 "destination_warehouse_id": null,24 "destination_location": {25 "latitude": 36.1901,26 "longitude": 44.0091,27 "full_address": "Erbil, Kurdistan Region"28 },29 "carrier_type": "internal",30 "driver_id": "{{driver_id}}",31 "vehicle_id": "{{vehicle_id}}",32 "external_carrier_ref": null,33 "assigned_by": "{{user_id}}",34 "assignment_time": "2026-04-07T12:20:00Z",35 "status": "sealed",36 "sealed_at": "2026-04-07T12:15:00Z",37 "dispatched_at": null,38 "received_at": null,39 "received_by": null,40 "closed_at": null,41 "cancelled_at": null,42 "proof_of_delivery": null,43 "notes": "Updated notes",44 "created_by": "{{user_id}}",45 "created_at": "2026-04-07T12:00:00Z",46 "updated_at": "2026-04-07T12:20:00Z"47 }48}1{2 "success": false,3 "message": "Waybill cannot be edited in its current status",4 "data": null5}Scan Eligible Delivery for Waybill
/delivery/waybills/{{waybill_id}}/scan/{{scan_value}}Validate one scanned delivery without attaching it to the waybill. The path value is matched exactly in this order: barcode, external_reference_id, then delivery_code (with an optional DEL prefix). Success returns the same delivery field shape used in waybill details, including locations, payment, zones, warehouses, and return fields. The frontend must add data.id to shared local selection state, handle duplicate scans locally, and submit all selected IDs once through POST /delivery/waybills/{id}/deliveries. Important errors return a machine-readable code: delivery_not_found (404), delivery_already_in_waybill, delivery_in_active_route_session, delivery_parent_not_eligible, delivery_status_not_eligible, delivery_has_active_assignment, or waybill_membership_locked (409).
1curl --request GET "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/scan/{{scan_value}}" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
scan_valueRequiredDEL1533
URL-encoded barcode, external_reference_id, or delivery_code
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Eligible delivery retrieved successfully",4 "data": {5 "id": "3bebb14a-3179-4b34-8a65-6e52afa2870f",6 "delivery_code": "3033",7 "barcode": "DEL3033",8 "external_reference_id": "",9 "status": "pending",10 "pickup_location": {11 "id": "c8eed194-887e-4da9-b312-2d04d8edc4d8",12 "city": "Baghdad",13 "state": null,14 "country": "Iraq",15 "latitude": 33.29605487,16 "longitude": 44.3399507,17 "postal_code": null,18 "contact_info": null,19 "country_code": null,20 "full_address": "1234, Yarmouk, Baghdad, Baghdad Governorate, Iraq"21 },22 "delivery_location": {23 "id": "03fc2031-1778-4355-874f-4589287f3cde",24 "city": "Lajan",25 "state": null,26 "country": "Iraq",27 "latitude": 36.125664,28 "longitude": 43.79169851,29 "postal_code": null,30 "contact_info": null,31 "country_code": null,32 "full_address": "206, lajan, Lajan, Erbil Governorate, Iraq"33 },34 "unit_size": 1,35 "payment_method": "cash",36 "cod_amount": 10000,37 "notes": "",38 "created_at": "2026-05-22T12:33:54.61787+00:00",39 "pickup_zone_id": "23ba845d-faf0-4241-ad50-86a438d98853",40 "dropoff_zone_id": "4f04820c-e9de-4449-ad12-2cd3758ac09b",41 "pickup_warehouse_id": "3a577909-49a2-4819-a54b-0559e7dec3ce",42 "dropoff_warehouse_id": "8e2f5943-8500-49cc-8830-f12a3fc40d4e",43 "is_returned": false,44 "return_reason": null,45 "return_trigger_point": null,46 "returned_at": null47 }48}1{2 "success": false,3 "code": "delivery_not_found",4 "message": "Delivery not found",5 "data": null6}1{2 "success": false,3 "code": "delivery_status_not_eligible",4 "message": "Delivery status is not eligible for waybill attachment",5 "data": null6}List Eligible Deliveries for Waybill
/delivery/waybills/{{waybill_id}}/eligible-deliveries?page=1&limit=25&sort_by=created_at&sort_order=desc&search=&column_filters={}Returns deliveries that can be attached to the target drafted waybill. Eligibility requires the same tenant, no current waybill, status draft/pending/staged_at_warehouse, no parent delivery, and no active assignment. The response includes customer information. Frontend sends column_filters as URL-encoded JSON and handles 400 validation errors for invalid JSON, keys, value types, sort fields, or date values; 409 means waybill membership is locked.
1curl --request GET "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/eligible-deliveries?page=1&limit=25&sort_by=created_at&sort_order=desc&search=&column_filters={}" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
Query parameters
pageOptional1
Page number, minimum 1
limitOptional25
Items per page, from 1 to 100
sort_byOptionalcreated_at
Sort field: delivery_code, status, barcode, external_reference_id, unit_size, created_at, or customer
sort_orderOptionaldesc
Sort direction: asc or desc
searchOptionalGlobal partial search by delivery code, barcode, external reference, or customer name
column_filtersOptional{}
URL-encoded JSON. Supports delivery_code, status, barcode, external_reference_id, pickup, delivery, unit_size, payment_method, cod_amount, created_at, and customer. pickup matches address or pickup zone; delivery matches address or dropoff zone. unit_size and cod_amount accept an exact value or {"min":value,"max":value}.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Eligible deliveries retrieved successfully",4 "data": [5 {6 "id": "{{delivery_id}}",7 "delivery_code": "1533",8 "barcode": "DEL1533",9 "external_reference_id": "ORD-1533",10 "status": "pending",11 "unit_size": 1,12 "payment_method": "cod",13 "cod_amount": 12000,14 "notes": "Handle with care",15 "pickup_location": {16 "full_address": "Origin warehouse",17 "latitude": 36.191,18 "longitude": 44.0119 },20 "delivery_location": {21 "full_address": "Customer address",22 "latitude": 36.1901,23 "longitude": 44.009124 },25 "pickup_warehouse_id": "{{warehouse_id}}",26 "dropoff_warehouse_id": null,27 "pickup_warehouse": {28 "id": "{{warehouse_id}}",29 "name": "Main Warehouse",30 "code": "WH-MAIN"31 },32 "dropoff_warehouse": null,33 "pickup_zone": {34 "id": "{{pickup_zone_id}}",35 "name": "Central Pickup Zone",36 "code": "PZ-CENTRAL"37 },38 "dropoff_zone": {39 "id": "{{dropoff_zone_id}}",40 "name": "Downtown Dropoff Zone",41 "code": "DZ-DOWNTOWN"42 },43 "customer": {44 "id": "{{customer_id}}",45 "full_name": "Customer Name",46 "avatar_url": null47 },48 "created_at": "2026-04-07T11:40:00Z",49 "updated_at": "2026-04-07T11:45:00Z"50 }51 ],52 "total": 1,53 "page": 1,54 "limit": 2555}1{2 "success": false,3 "message": "Deliveries cannot be added or removed after waybill is sealed",4 "data": null5}Add Deliveries to Waybill
/delivery/waybills/{{waybill_id}}/deliveriesAttach selected deliveries to a drafted waybill. Use the eligible-deliveries endpoint first so dispatcher only sees addable deliveries.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/deliveries" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "delivery_ids": [7 "{{delivery_id}}"8 ]9}'1{2 "delivery_ids": [3 "{{delivery_id}}"4 ]5}Path parameters
waybill_idRequiredVariable used inside the request path.
Request body fields
delivery_idsExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Deliveries added to waybill successfully",4 "data": {5 "attached": 16 }7}1{2 "success": false,3 "message": "Delivery has an active assignment. Unassign first before adding to waybill",4 "data": null5}Remove Delivery from Waybill
/delivery/waybills/{{waybill_id}}/deliveries/{{delivery_id}}Remove a delivery from a drafted waybill.
1curl --request DELETE "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/deliveries/{{delivery_id}}" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
delivery_idRequiredVariable used inside the request path.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Delivery removed from waybill successfully",4 "data": null5}1{2 "success": false,3 "message": "Delivery is not linked to this waybill",4 "data": null5}Seal Waybill
/delivery/waybills/{{waybill_id}}/sealSeal a drafted waybill. After this, membership is locked and no deliveries can be added/removed.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/seal" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill sealed successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "internal",19 "driver_id": "{{driver_id}}",20 "vehicle_id": "{{vehicle_id}}",21 "external_carrier_ref": null,22 "assigned_by": "{{user_id}}",23 "assignment_time": "2026-04-07T12:20:00Z",24 "status": "sealed",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": null,27 "received_at": null,28 "received_by": "{{receiver_user_id}}",29 "closed_at": null,30 "cancelled_at": null,31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:20:00Z",36 "driver": {37 "id": "{{driver_id}}",38 "status": "active",39 "user": {40 "id": "{{driver_user_id}}",41 "full_name": "John Driver",42 "email": "driver@example.com",43 "phone": "+9647500000000",44 "avatar_url": "https://example.com/driver.jpg"45 }46 },47 "vehicle": {48 "id": "{{vehicle_id}}",49 "name": "Van 101",50 "code": "VAN-101",51 "capacity_unit": 50,52 "image_url": "https://example.com/vehicles/van-101.jpg"53 },54 "origin_warehouse": {55 "id": "{{warehouse_id}}",56 "name": "Main Warehouse",57 "code": "WH-MAIN"58 },59 "destination_warehouse": null,60 "origin_zone": {61 "id": "{{origin_zone_id}}",62 "name": "Erbil Central",63 "code": "ERB-CENTRAL"64 },65 "destination_zone": {66 "id": "{{destination_zone_id}}",67 "name": "Erbil East",68 "code": "ERB-EAST"69 },70 "assigned_by_user": {71 "id": "{{user_id}}",72 "full_name": "Dispatcher User",73 "email": "dispatcher@example.com",74 "phone": "+9647511111111",75 "avatar_url": "https://example.com/users/dispatcher.jpg"76 },77 "received_by_user": {78 "id": "{{receiver_user_id}}",79 "full_name": "Warehouse Receiver",80 "email": "receiver@example.com",81 "phone": "+9647522222222",82 "avatar_url": "https://example.com/users/receiver.jpg"83 },84 "total_unit_size": 1,85 "deliveries": [86 {87 "id": "{{delivery_id}}",88 "delivery_code": 1533,89 "barcode": "DEL1533",90 "external_reference_id": "ORD-1533",91 "status": "pending",92 "pickup_location": {93 "full_address": "Origin warehouse",94 "latitude": 36.191,95 "longitude": 44.0196 },97 "delivery_location": {98 "full_address": "Customer address",99 "latitude": 36.1901,100 "longitude": 44.0091101 },102 "unit_size": 1,103 "payment_method": "cod",104 "cod_amount": 12000,105 "notes": "Handle with care",106 "created_at": "2026-04-07T11:40:00Z",107 "pickup_zone_id": "{{origin_zone_id}}",108 "dropoff_zone_id": "{{destination_zone_id}}",109 "pickup_warehouse_id": "{{warehouse_id}}",110 "dropoff_warehouse_id": null111 }112 ],113 "summary": {114 "total_deliveries": 1,115 "total_unit_size": 1,116 "status_breakdown": {117 "pending": 1118 }119 }120 }121}1{2 "success": false,3 "message": "Waybill must have at least one delivery to seal",4 "data": null5}Assign Driver to Waybill
/delivery/waybills/{{waybill_id}}/assignAssign an internal sealed waybill to a driver using the driver primary id from drivers.id. Backend derives the assigned vehicle from the driver's primary vehicle assignment and stores both ids on the waybill.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/assign" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "driver_id": "{{driver_id}}"7}'1{2 "driver_id": "{{driver_id}}"3}Path parameters
waybill_idRequiredVariable used inside the request path.
Request body fields
driver_idExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill assigned to driver successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "internal",19 "driver_id": "{{driver_id}}",20 "vehicle_id": "{{vehicle_id}}",21 "external_carrier_ref": null,22 "assigned_by": "{{user_id}}",23 "assignment_time": "2026-04-07T12:20:00Z",24 "status": "sealed",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": null,27 "received_at": null,28 "received_by": null,29 "closed_at": null,30 "cancelled_at": null,31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:20:00Z"36 }37}1{2 "success": false,3 "message": "Driver not found",4 "data": null5}1{2 "success": false,3 "message": "Waybill must be sealed before assigning a driver",4 "data": null5}Switch Waybill Driver
/delivery/waybills/{{waybill_id}}/switch-driverSwitch the assigned driver of an internal waybill. reason is mandatory, must be 1-500 characters, and is persisted in the driver_switched timeline event. Allowed in sealed, picked_up, and in_transit for dispatcher custody transfer. Backend derives the new vehicle from the new driver's primary vehicle assignment and records the previous/new driver and vehicle snapshots.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/switch-driver" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "driver_id": "{{new_driver_id}}",7 "reason": "Previous driver had vehicle issue"8}'1{2 "driver_id": "{{new_driver_id}}",3 "reason": "Previous driver had vehicle issue"4}Path parameters
waybill_idRequiredVariable used inside the request path.
Request body fields
driver_idExampleExample field from the request body.
reasonExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill driver switched successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "internal",19 "driver_id": "{{new_driver_id}}",20 "vehicle_id": "{{new_vehicle_id}}",21 "external_carrier_ref": null,22 "assigned_by": "{{user_id}}",23 "assignment_time": "2026-04-07T12:35:00Z",24 "status": "picked_up",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": "2026-04-07T12:30:00Z",27 "received_at": null,28 "received_by": null,29 "closed_at": null,30 "cancelled_at": null,31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:35:00Z",36 "driver": {37 "id": "{{new_driver_id}}",38 "status": "active",39 "user": {40 "id": "{{new_driver_user_id}}",41 "full_name": "Backup Driver",42 "email": "backup.driver@example.com",43 "phone": "+9647500000001",44 "avatar_url": "https://example.com/driver2.jpg"45 }46 },47 "vehicle": {48 "id": "{{new_vehicle_id}}",49 "name": "Van 202",50 "code": "VAN-202",51 "capacity_unit": 50,52 "image_url": "https://example.com/vehicles/van-202.jpg"53 },54 "origin_warehouse": {55 "id": "{{warehouse_id}}",56 "name": "Main Warehouse",57 "code": "WH-MAIN"58 },59 "destination_warehouse": null,60 "origin_zone": {61 "id": "{{origin_zone_id}}",62 "name": "Erbil Central",63 "code": "ERB-CENTRAL"64 },65 "destination_zone": {66 "id": "{{destination_zone_id}}",67 "name": "Erbil East",68 "code": "ERB-EAST"69 },70 "assigned_by_user": {71 "id": "{{user_id}}",72 "full_name": "Dispatcher User",73 "email": "dispatcher@example.com",74 "phone": "+9647511111111",75 "avatar_url": "https://example.com/users/dispatcher.jpg"76 },77 "received_by_user": null,78 "total_unit_size": 1,79 "deliveries": [80 {81 "id": "{{delivery_id}}",82 "delivery_code": 1533,83 "barcode": "DEL1533",84 "external_reference_id": "ORD-1533",85 "status": "picked_up",86 "pickup_location": {87 "full_address": "Origin warehouse",88 "latitude": 36.191,89 "longitude": 44.0190 },91 "delivery_location": {92 "full_address": "Customer address",93 "latitude": 36.1901,94 "longitude": 44.009195 },96 "unit_size": 1,97 "payment_method": "cod",98 "cod_amount": 12000,99 "notes": "Handle with care",100 "created_at": "2026-04-07T11:40:00Z",101 "pickup_zone_id": "{{origin_zone_id}}",102 "dropoff_zone_id": "{{destination_zone_id}}",103 "pickup_warehouse_id": "{{warehouse_id}}",104 "dropoff_warehouse_id": null105 }106 ],107 "summary": {108 "total_deliveries": 1,109 "total_unit_size": 1,110 "status_breakdown": {111 "picked_up": 1112 }113 }114 }115}1{2 "success": false,3 "message": "Field required",4 "details": [5 {6 "field": "reason",7 "message": "Field required"8 }9 ]10}1{2 "success": false,3 "message": "This driver is already assigned to the waybill",4 "data": null5}Unassign Waybill Driver
/delivery/waybills/{{waybill_id}}/unassignUnassign the current driver from an internal waybill. Allowed only while the waybill is sealed. After pickup, dispatcher must use switch-driver instead of unassign.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/unassign" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{}'1{}Path parameters
waybill_idRequiredVariable used inside the request path.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill driver unassigned successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "internal",19 "driver_id": null,20 "vehicle_id": null,21 "external_carrier_ref": null,22 "assigned_by": null,23 "assignment_time": null,24 "status": "sealed",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": null,27 "received_at": null,28 "received_by": null,29 "closed_at": null,30 "cancelled_at": null,31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:40:00Z",36 "driver": null,37 "vehicle": null,38 "origin_warehouse": {39 "id": "{{warehouse_id}}",40 "name": "Main Warehouse",41 "code": "WH-MAIN"42 },43 "destination_warehouse": null,44 "origin_zone": {45 "id": "{{origin_zone_id}}",46 "name": "Erbil Central",47 "code": "ERB-CENTRAL"48 },49 "destination_zone": {50 "id": "{{destination_zone_id}}",51 "name": "Erbil East",52 "code": "ERB-EAST"53 },54 "assigned_by_user": null,55 "received_by_user": null,56 "total_unit_size": 1,57 "deliveries": [58 {59 "id": "{{delivery_id}}",60 "delivery_code": 1533,61 "barcode": "DEL1533",62 "external_reference_id": "ORD-1533",63 "status": "pending",64 "pickup_location": {65 "full_address": "Origin warehouse",66 "latitude": 36.191,67 "longitude": 44.0168 },69 "delivery_location": {70 "full_address": "Customer address",71 "latitude": 36.1901,72 "longitude": 44.009173 },74 "unit_size": 1,75 "payment_method": "cod",76 "cod_amount": 12000,77 "notes": "Handle with care",78 "created_at": "2026-04-07T11:40:00Z",79 "pickup_zone_id": "{{origin_zone_id}}",80 "dropoff_zone_id": "{{destination_zone_id}}",81 "pickup_warehouse_id": "{{warehouse_id}}",82 "dropoff_warehouse_id": null83 }84 ],85 "summary": {86 "total_deliveries": 1,87 "total_unit_size": 1,88 "status_breakdown": {89 "pending": 190 }91 }92 }93}1{2 "success": false,3 "message": "Unassigning after pickup is not allowed",4 "data": null5}Dispatch Waybill (External Carrier)
/delivery/waybills/{{waybill_id}}/dispatchMove a non-internal waybill from sealed to in_transit. Internal carrier waybills should use driver-action instead.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/dispatch" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill dispatched successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "external",19 "driver_id": null,20 "vehicle_id": null,21 "external_carrier_ref": null,22 "assigned_by": "{{user_id}}",23 "assignment_time": "2026-04-07T12:20:00Z",24 "status": "in_transit",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": "2026-04-07T12:30:00Z",27 "received_at": null,28 "received_by": null,29 "closed_at": null,30 "cancelled_at": null,31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:20:00Z"36 }37}1{2 "success": false,3 "message": "Use driver action endpoint for internal carrier waybills",4 "data": null5}Receive Waybill (External Carrier)
/delivery/waybills/{{waybill_id}}/receiveComplete an external/prime carrier waybill. proof_of_delivery is optional. Send it only when proof data exists. Active child deliveries include pending, assigned, picked_up, and in_transit; every present child moves to delivered, including warehouse destinations. Missing warehouse-receive children keep their current status and receive discrepancy records. For internal driver flow, use driver-action instead.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/receive" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "proof_of_delivery": {7 "signature_url": "https://example.com/signature.png",8 "photo_urls": [9 "https://example.com/photo1.jpg"10 ],11 "notes": "Received in good condition"12 }13}'1{2 "proof_of_delivery": {3 "signature_url": "https://example.com/signature.png",4 "photo_urls": [5 "https://example.com/photo1.jpg"6 ],7 "notes": "Received in good condition"8 }9}Path parameters
waybill_idRequiredVariable used inside the request path.
Request body fields
proof_of_deliveryExampleExample field from the request body.
proof_of_delivery.signature_urlExampleExample field from the request body.
proof_of_delivery.photo_urlsExampleExample field from the request body.
proof_of_delivery.notesExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill received successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "external",19 "driver_id": null,20 "vehicle_id": null,21 "external_carrier_ref": null,22 "assigned_by": "{{user_id}}",23 "assignment_time": "2026-04-07T12:20:00Z",24 "status": "received",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": null,27 "received_at": "2026-04-07T14:00:00Z",28 "received_by": null,29 "closed_at": null,30 "cancelled_at": null,31 "proof_of_delivery": {32 "signature_url": "https://example.com/signature.png",33 "photo_urls": [34 "https://example.com/photo1.jpg"35 ],36 "notes": "Received in good condition"37 },38 "notes": "Batch for afternoon dispatch",39 "created_by": "{{user_id}}",40 "created_at": "2026-04-07T12:00:00Z",41 "updated_at": "2026-04-07T12:20:00Z"42 }43}1{2 "success": true,3 "message": "Waybill received successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "external",19 "driver_id": null,20 "vehicle_id": null,21 "external_carrier_ref": null,22 "assigned_by": "{{user_id}}",23 "assignment_time": "2026-04-07T12:20:00Z",24 "status": "received",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": null,27 "received_at": "2026-04-07T14:00:00Z",28 "received_by": null,29 "closed_at": null,30 "cancelled_at": null,31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:20:00Z"36 }37}1{2 "success": false,3 "message": "Invalid waybill status transition",4 "data": null5}Close Waybill
/delivery/waybills/{{waybill_id}}/closeClose a received waybill after reconciliation/audit is complete.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/close" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill closed successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "internal",19 "driver_id": "{{driver_id}}",20 "vehicle_id": "{{vehicle_id}}",21 "external_carrier_ref": null,22 "assigned_by": "{{user_id}}",23 "assignment_time": "2026-04-07T12:20:00Z",24 "status": "closed",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": null,27 "received_at": "2026-04-07T14:00:00Z",28 "received_by": null,29 "closed_at": "2026-04-07T14:15:00Z",30 "cancelled_at": null,31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:20:00Z"36 }37}1{2 "success": false,3 "message": "Invalid waybill status transition",4 "data": null5}Bulk Delete Empty Draft Waybills
/delivery/waybills/bulk-delete-empty-draftsPermanently delete empty drafted Waybills using exactly one scope. Selected scope: send waybill_ids with 1-100 IDs. All-empty scope: send { "all_empty_drafts": true } to delete every Waybill in the authenticated tenant that is exactly drafted and has zero attached deliveries. Do not send both fields. Missing both returns validation error waybill_bulk_delete_scope_required; sending both returns waybill_bulk_delete_scope_conflict. Frontend contract: - Ask the user to choose selected rows or all empty drafts and require confirmation before the request. - Remove only IDs returned in data.deleted_ids. - Use data.scope (selected or all_empty_drafts) to confirm which operation ran. - For selected scope, keep rows returned in data.skipped and use reason (not_drafted or has_deliveries) for feedback. - Treat data.not_found as stale selected rows. - A 409 waybill_bulk_delete_conflict means eligibility changed during deletion; refresh before retrying.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/bulk-delete-empty-drafts" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "waybill_ids": [7 "{{waybill_id}}",8 "{{waybill_id_2}}"9 ]10}'1{2 "waybill_ids": [3 "{{waybill_id}}",4 "{{waybill_id_2}}"5 ]6}Request body fields
waybill_idsExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Empty drafted Waybills processed successfully",4 "data": {5 "scope": "selected",6 "deleted_count": 2,7 "deleted_ids": [8 "{{waybill_id}}",9 "{{waybill_id_2}}"10 ],11 "skipped": [12 {13 "id": "{{waybill_id_3}}",14 "reason": "has_deliveries"15 }16 ],17 "not_found": []18 }19}1{2 "success": true,3 "message": "Empty drafted Waybills processed successfully",4 "data": {5 "scope": "all_empty_drafts",6 "deleted_count": 6,7 "deleted_ids": [8 "waybill-uuid-1",9 "waybill-uuid-2"10 ],11 "skipped": [12 {13 "id": "waybill-uuid-with-deliveries",14 "reason": "has_deliveries"15 }16 ],17 "not_found": []18 }19}Cancel Waybill
/delivery/waybills/{{waybill_id}}/cancelCancel a drafted or sealed waybill before active transport starts.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/cancel" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
waybill_idRequiredVariable used inside the request path.
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill cancelled successfully",4 "data": {5 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",6 "tenant_id": "{{tenant_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "carrier_type": "internal",19 "driver_id": null,20 "vehicle_id": null,21 "external_carrier_ref": null,22 "assigned_by": null,23 "assignment_time": null,24 "status": "cancelled",25 "sealed_at": "2026-04-07T12:15:00Z",26 "dispatched_at": null,27 "received_at": null,28 "received_by": null,29 "closed_at": null,30 "cancelled_at": "2026-04-07T12:25:00Z",31 "proof_of_delivery": null,32 "notes": "Batch for afternoon dispatch",33 "created_by": "{{user_id}}",34 "created_at": "2026-04-07T12:00:00Z",35 "updated_at": "2026-04-07T12:20:00Z"36 }37}1{2 "success": false,3 "message": "Waybill cannot be cancelled in its current status",4 "data": null5}Driver Action on Waybill
/delivery/waybills/{{waybill_id}}/driver-actionDriver-only endpoint for internal waybill execution. Allowed actions: picked_up, in_transit, received. Active child deliveries include pending, assigned, picked_up, and in_transit, and cascade with the waybill: picked_up -> picked_up, in_transit -> in_transit, and received -> delivered for every destination type. Returned and cancelled children are not overwritten. Cash side effects follow child delivery payer rules: location-origin picked_up creates a fee-only pickup collection when the sender pays cash; final location received creates a COD-only dropoff collection or one combined COD+fee dropoff collection when the receiver pays both. Warehouse-origin pickup does not create sender cash. For final received, proof fields are optional.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/{{waybill_id}}/driver-action" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "action": "picked_up",7 "current_latitude": 36.1901,8 "current_longitude": 44.0091,9 "notes": "Picked up from warehouse"10}'1{2 "action": "picked_up",3 "current_latitude": 36.1901,4 "current_longitude": 44.0091,5 "notes": "Picked up from warehouse"6}Path parameters
waybill_idRequiredVariable used inside the request path.
Request body fields
actionExampleExample field from the request body.
current_latitudeExampleExample field from the request body.
current_longitudeExampleExample field from the request body.
notesExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill action completed successfully",4 "data": {5 "waybill": {6 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",7 "tenant_id": "{{tenant_id}}",8 "waybill_number": "WB00001",9 "origin_type": "warehouse",10 "origin_warehouse_id": "{{warehouse_id}}",11 "origin_location": null,12 "destination_type": "location",13 "destination_warehouse_id": null,14 "destination_location": {15 "latitude": 36.1901,16 "longitude": 44.0091,17 "full_address": "Erbil, Kurdistan Region"18 },19 "carrier_type": "internal",20 "driver_id": "{{driver_id}}",21 "vehicle_id": "{{vehicle_id}}",22 "external_carrier_ref": null,23 "assigned_by": "{{user_id}}",24 "assignment_time": "2026-04-07T12:20:00Z",25 "status": "picked_up",26 "sealed_at": "2026-04-07T12:15:00Z",27 "dispatched_at": "2026-04-07T12:35:00Z",28 "received_at": null,29 "received_by": null,30 "closed_at": null,31 "cancelled_at": null,32 "proof_of_delivery": null,33 "notes": "Batch for afternoon dispatch",34 "created_by": "{{user_id}}",35 "created_at": "2026-04-07T12:00:00Z",36 "updated_at": "2026-04-07T12:20:00Z"37 },38 "deliveries": [39 {40 "id": "a1b2c3d4-0001-0000-0000-000000000001",41 "delivery_code": 1001,42 "external_reference_id": "EXT-001",43 "status": "picked_up",44 "unit_size": 2,45 "pickup_location": {46 "id": "{{address_id}}",47 "full_address": "Warehouse A, Erbil",48 "latitude": 36.19,49 "longitude": 44.0150 },51 "delivery_location": {52 "id": "{{address_id}}",53 "full_address": "Customer Street 12, Erbil",54 "latitude": 36.2,55 "longitude": 44.0256 },57 "customer": {58 "id": "{{customer_id}}",59 "full_name": "Ahmed Ali",60 "phone": "+9647501234567"61 }62 }63 ]64 }65}1{2 "success": true,3 "message": "Waybill action completed successfully",4 "data": {5 "waybill": {6 "id": "d0bb9c6b-25db-4e28-a5c1-1b709e3d11f1",7 "tenant_id": "{{tenant_id}}",8 "waybill_number": "WB00001",9 "origin_type": "warehouse",10 "origin_warehouse_id": "{{warehouse_id}}",11 "origin_location": null,12 "destination_type": "location",13 "destination_warehouse_id": null,14 "destination_location": {15 "latitude": 36.1901,16 "longitude": 44.0091,17 "full_address": "Erbil, Kurdistan Region"18 },19 "carrier_type": "internal",20 "driver_id": "{{driver_id}}",21 "vehicle_id": "{{vehicle_id}}",22 "external_carrier_ref": null,23 "assigned_by": "{{user_id}}",24 "assignment_time": "2026-04-07T12:20:00Z",25 "status": "received",26 "sealed_at": "2026-04-07T12:15:00Z",27 "dispatched_at": "2026-04-07T12:35:00Z",28 "received_at": "2026-04-07T13:15:00Z",29 "received_by": null,30 "closed_at": null,31 "cancelled_at": null,32 "proof_of_delivery": {33 "signature_url": "https://example.com/signature.png",34 "photo_urls": [35 "https://example.com/photo1.jpg"36 ],37 "notes": "Delivered successfully",38 "timestamp": "2026-04-07T13:15:00Z"39 },40 "notes": "Batch for afternoon dispatch",41 "created_by": "{{user_id}}",42 "created_at": "2026-04-07T12:00:00Z",43 "updated_at": "2026-04-07T12:20:00Z"44 },45 "deliveries": [46 {47 "id": "a1b2c3d4-0001-0000-0000-000000000001",48 "delivery_code": 1001,49 "external_reference_id": "EXT-001",50 "status": "delivered",51 "unit_size": 2,52 "pickup_location": {53 "id": "{{address_id}}",54 "full_address": "Warehouse A, Erbil",55 "latitude": 36.19,56 "longitude": 44.0157 },58 "delivery_location": {59 "id": "{{address_id}}",60 "full_address": "Customer Street 12, Erbil",61 "latitude": 36.2,62 "longitude": 44.0263 },64 "customer": {65 "id": "{{customer_id}}",66 "full_name": "Ahmed Ali",67 "phone": "+9647501234567"68 }69 }70 ]71 }72}1{2 "success": false,3 "message": "You are not the assigned driver for this waybill",4 "data": null5}Get Driver Waybills
/delivery/driver-waybills?page=1&limit=20&status=Driver-only list. Each waybill appears as one grouped job in the driver app. The response includes a complete statuses matrix for all waybill statuses, including statuses with a zero count. Matrix counts are for all waybills assigned to the authenticated driver and are not affected by the active status filter.
1curl --request GET "$ONDI_BASE_URL/delivery/driver-waybills?page=1&limit=20&status=" \2 --header "Authorization: Bearer {{access_token}}"Query parameters
pageOptional1
Page number
limitOptional20
Items per page
statusOptionalFilter by waybill status
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybills retrieved successfully",4 "data": [5 {6 "id": "{{waybill_id}}",7 "waybill_number": "WB00001",8 "origin_type": "warehouse",9 "origin_warehouse_id": "{{warehouse_id}}",10 "origin_location": null,11 "destination_type": "location",12 "destination_warehouse_id": null,13 "destination_location": {14 "latitude": 36.1901,15 "longitude": 44.0091,16 "full_address": "Erbil, Kurdistan Region"17 },18 "status": "sealed",19 "carrier_type": "internal",20 "assignment_time": "2026-04-07T12:20:00Z",21 "notes": "Batch for afternoon dispatch",22 "created_at": "2026-04-07T12:00:00Z",23 "updated_at": "2026-04-07T12:20:00Z",24 "item_count": 125 }26 ],27 "statuses": [28 {29 "status": "drafted",30 "label": "Drafted",31 "count": 032 },33 {34 "status": "sealed",35 "label": "Sealed",36 "count": 137 },38 {39 "status": "picked_up",40 "label": "Picked Up",41 "count": 042 },43 {44 "status": "in_transit",45 "label": "In Transit",46 "count": 047 },48 {49 "status": "received",50 "label": "Received",51 "count": 052 },53 {54 "status": "closed",55 "label": "Closed",56 "count": 057 },58 {59 "status": "cancelled",60 "label": "Cancelled",61 "count": 062 }63 ],64 "total": 1,65 "page": 1,66 "limit": 2067}1{2 "success": false,3 "message": "Driver not found",4 "data": null5}Get Driver Waybill Status Summary
/delivery/driver-waybills/status-summaryDriver-only status counts for waybill tabs/sections in the app. Returns the complete ordered status matrix with labels, including statuses with a zero count.
1curl --request GET "$ONDI_BASE_URL/delivery/driver-waybills/status-summary" \2 --header "Authorization: Bearer {{access_token}}"Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill status summary retrieved successfully",4 "statuses": [5 {6 "status": "drafted",7 "label": "Drafted",8 "count": 09 },10 {11 "status": "sealed",12 "label": "Sealed",13 "count": 214 },15 {16 "status": "picked_up",17 "label": "Picked Up",18 "count": 119 },20 {21 "status": "in_transit",22 "label": "In Transit",23 "count": 324 },25 {26 "status": "received",27 "label": "Received",28 "count": 429 },30 {31 "status": "closed",32 "label": "Closed",33 "count": 034 },35 {36 "status": "cancelled",37 "label": "Cancelled",38 "count": 039 }40 ]41}1{2 "success": false,3 "message": "Insufficient permissions",4 "data": null5}Return Waybill Children (Partial Return)
/delivery/waybills/:id/return-childrenMark one or more child deliveries on a waybill as RETURNED (partial-return). Allowed waybill statuses: sealed, picked_up, in_transit, received. Waybill must be internal carrier. Actor authorization: - Dispatcher: caller has manage:operations:tenant or manage:module:delivery permission. - Driver: caller has 'driver' role; only allowed when waybill status is picked_up/in_transit and the driver matches the assigned driver. Reason must be one of: refused, wrong_address, damaged, lost, undeliverable, cancelled_by_customer, qc_fail, rejected_at_destination, other. For each returned child: - A delivery_exceptions row is created (resolution_type=returned, exception_type=reason, waybill_id, unit_size_at_return). - Delivery status flips to 'returned'. - Driver capacity is released by the child's unit_size. - A receiving order is created at the waybill's origin warehouse when valid inventory items exist on the delivery (visible in the warehouse module; not returned in this response). If every child on the waybill ends up returned, the waybill is closed automatically — the returned data.waybill.status will be closed.
1curl --request POST "$ONDI_BASE_URL/delivery/waybills/:id/return-children" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "delivery_ids": [7 "<delivery_id_1>",8 "<delivery_id_2>"9 ],10 "reason": "refused",11 "notes": "Customer refused on doorstep",12 "photo_urls": [13 "https://example.com/photo1.jpg"14 ]15}'1{2 "delivery_ids": [3 "<delivery_id_1>",4 "<delivery_id_2>"5 ],6 "reason": "refused",7 "notes": "Customer refused on doorstep",8 "photo_urls": [9 "https://example.com/photo1.jpg"10 ]11}Path parameters
idRequired<waybill_id>
Waybill UUID
Request body fields
delivery_idsExampleExample field from the request body.
reasonExampleExample field from the request body.
notesExampleExample field from the request body.
photo_urlsExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Waybill children returned successfully",4 "data": {5 "waybill": {6 "id": "wb-uuid",7 "waybill_number": "WB000123",8 "status": "in_transit",9 "closed_at": null10 },11 "returnedDeliveries": [12 {13 "delivery_id": "d1",14 "delivery_code": "DEL-001",15 "status": "returned",16 "exception_id": "exc-uuid-1",17 "trigger_point": "in_transit"18 },19 {20 "delivery_id": "d2",21 "delivery_code": "DEL-002",22 "status": "returned",23 "exception_id": "exc-uuid-2",24 "trigger_point": "in_transit"25 }26 ]27 }28}1{2 "success": false,3 "message": "Waybill is not in a returnable state",4 "data": null5}1{2 "success": false,3 "message": "Insufficient permissions",4 "data": null5}List Waybill Returns
/delivery/waybills/:id/returns?page=1&limit=20List all child deliveries that have been returned for a waybill (joined with the corresponding delivery_exceptions row).
1curl --request GET "$ONDI_BASE_URL/delivery/waybills/:id/returns?page=1&limit=20" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
idRequired<waybill_id>
Waybill UUID
Query parameters
pageOptional1
limitOptional20
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Waybill returns retrieved successfully",4 "data": [5 {6 "id": "exc-uuid-1",7 "delivery_id": "d1",8 "waybill_id": "wb-uuid",9 "exception_type": "refused",10 "resolution_type": "returned",11 "unit_size_at_return": 2,12 "exception_details": {13 "reason_code": "refused",14 "trigger_point": "in_transit",15 "notes": "Customer refused",16 "photo_urls": []17 },18 "resolved_at": "2026-04-29T10:00:00Z",19 "delivery": {20 "id": "d1",21 "delivery_code": "DEL-001",22 "status": "returned",23 "unit_size": 224 }25 }26 ],27 "total": 1,28 "page": 1,29 "limit": 2030}