Institution Transfer Manifest V1
52 API calls in this section.
G2G / Institution Transfer Manifest APIs. Covers processing points, institution branches, barcode batches, driver manifest lifecycle, dispatcher receiving/processing, exceptions, and event history. Use {{base_url}}/delivery/... for the standard generated collection. If calling the staging function proxy directly at https://staging-api.ondi.io/functions/v1/delivery, remove the /delivery path prefix.
Feature gate
every endpoint in this group requires tenant setting transfer_manifest.enabled to be true. When disabled, the API performs no operation and returns HTTP 403 with { "success": false, "code": "transfer_manifest_disabled", "message": "Transfer manifest is disabled for this tenant" }.
Tenant setting contract
GET /tenants/:tenantId/settings?keys=transfer_manifest returns delivery.transfer_manifest.settings. Supported settings include enabled, receiving_mode, allow_driver_select_processing_point, allow_driver_create_manifest_from_form, allow_driver_scan_institution_qr, allow_driver_scan_item_barcode, allow_warehouse_staging_without_assigned_driver, driver_scan_mode, default_delivery_service_id, delivery_fee_origin, reasons, and derived default_delivery_service when configured. allow_warehouse_staging_without_assigned_driver defaults to false; when true, an unassigned Transfer Manifest P&D inbound leg may use assignment_change_settings.default_driver_id during the existing warehouse staging operation. driver_scan_mode accepts continuous or manual; missing or invalid stored values are returned as continuous. delivery_fee_origin is processing_point (default) or source_location. It changes only the price basis when an item becomes an order: the order pickup location always remains the processing point, while source_location prices from the manifest's stored source address. reasons is the tenant-enabled array of { value, label, description } exception reasons that the frontend should show and manual exception endpoints accept. The three allow_driver_* workflow toggles are optional booleans, but at least one must be true; allow_driver_create_manifest_from_form defaults to true, while the scan toggles default to false. proof_settings is an object with { pickup: { photo_required, signature_required }, delivery: { photo_required, signature_required } } — all booleans. Defaults: pickup requires photo only; delivery requires both photo and signature.
Frontend contract
hide or disable transfer-manifest navigation and actions when the effective setting is disabled. If a stale screen still calls an endpoint. For proof capture, read proofRequirements from the manifest detail response to determine which fields to show/enforce at each lifecycle step, handle 403 with code transfer_manifest_disabled by stopping the action and returning the user to a non-transfer-manifest screen. Driver UI must show at least one enabled entry workflow. Use allow_driver_create_manifest_from_form to show manual manifest form creation, allow_driver_scan_institution_qr to show institution QR scanning, and allow_driver_scan_item_barcode to show item barcode scanning. Read driver_scan_mode to choose continuous or manual item capture; never infer mode from an error message. In Transfer Manifest Settings, submit delivery_fee_origin as either processing_point or source_location and driver_scan_mode as either continuous or manual; show backend HTTP 400 validation errors directly.
Processing Points - Create
/delivery/transfer-processing-pointsCreates a lightweight processing point. A processing point is not a warehouse; it is a receiving/sorting/data-entry location. code is unique per tenant.
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
name | string | — |
code | string | — |
address_id | string | — |
metadata | object | — |
metadata.source | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-processing-points" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "name": "G2G Processing Point",6 "code": "G2G-PP-001",7 "address_id": "{{source_address_id}}",8 "metadata": {9 "source": "postman"10 }11}'Replace {{placeholders}} with your own values before sending.
Response examples
1{2 "success": true,3 "message": "created_successfully",4 "data": {5 "id": "uuid",6 "name": "G2G Processing Point",7 "code": "G2G-PP-001",8 "is_active": true9 }10}Processing Points - List
/delivery/transfer-processing-pointsLists processing points for the authenticated tenant. Optional filters: is_active, search, and branch_id. When branch_id is provided, the branch's default processing point has is_default: true and is prioritized on page 1. Non-default items omit the is_default key.
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
is_activeOptional | string | Optional: true | false Example: |
branch_idOptional | string | Optional branch ID used to identify and prioritize its default processing point Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-processing-points?page=1&limit=20&is_active=true&branch_id=${SOURCE_BRANCH_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "data_retrieved_successfully",4 "data": [5 {6 "id": "{{processing_point_id}}",7 "name": "G2G Processing Point",8 "code": "G2G-PP-001",9 "is_active": true,10 "is_default": true11 }12 ],13 "pagination": {14 "page": 1,15 "limit": 20,16 "total": 1,17 "total_pages": 118 }19}Processing Points - Get Detail
/delivery/transfer-processing-points/{{processing_point_id}}Gets a processing point by id.
Path parameters
| Parameter | Type | Description |
|---|---|---|
processing_point_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-processing-points/${PROCESSING_POINT_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Processing Points - Update
/delivery/transfer-processing-points/{{processing_point_id}}Updates processing point fields. code must remain unique per tenant if changed.
Path parameters
| Parameter | Type | Description |
|---|---|---|
processing_point_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
name | string | — |
address_id | string | — |
metadata | object | — |
metadata.updated_from | string | — |
1curl --globoff --request PATCH "https://staging-api.ondi.io/functions/v1/delivery/transfer-processing-points/${PROCESSING_POINT_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "name": "G2G Processing Point Updated",6 "address_id": "{{source_address_id}}",7 "metadata": {8 "updated_from": "postman"9 }10}'Replace {{placeholders}} with your own values before sending.
Response examples
No saved response example. Use Try it to inspect a staging response.
Processing Points - Deactivate
/delivery/transfer-processing-points/{{processing_point_id}}/deactivateSoft-deactivates a processing point. Fails if non-terminal manifests reference it.
Path parameters
| Parameter | Type | Description |
|---|---|---|
processing_point_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-processing-points/${PROCESSING_POINT_ID}/deactivate" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{}'Response examples
No saved response example. Use Try it to inspect a staging response.
Institutions - List
/delivery/institutionsLists tenant users whose tenant_user_type is institution. Use a returned id as institution_user_id.
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
searchOptional | string | Optional search by name, email, or phone |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institutions?page=1&limit=20&search=" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Institutions - Get Detail
/delivery/institutions/{{institution_user_id}}Gets an institution tenant_user by id.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Institution Branches - Create
/delivery/institutions/{{institution_user_id}}/branchesCreates a branch under an institution. institution_user_id comes from the path, not the body. Branch code is unique per tenant/institution.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
name | string | — |
code | string | — |
address_id | string | — |
default_processing_point_id | string | — |
contact_info | object | — |
contact_info.phone | string | — |
metadata | object | — |
metadata.source | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/branches" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "name": "G2G Branch",6 "code": "G2G-BR-001",7 "address_id": "{{source_address_id}}",8 "default_processing_point_id": "{{processing_point_id}}",9 "contact_info": {10 "phone": "+10000000000"11 },12 "metadata": {13 "source": "postman"14 }15}'Replace {{placeholders}} with your own values before sending.
Response examples
1{2 "success": true,3 "message": "created_successfully",4 "data": {5 "id": "uuid",6 "institution_user_id": "uuid",7 "name": "G2G Branch",8 "code": "G2G-BR-001"9 }10}Institution Branches - List
/delivery/institutions/{{institution_user_id}}/branchesLists branches for an institution. Optional filters: is_active, search.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
is_active | string | Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/branches?page=1&limit=20&is_active=true" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Institution Branches - Tenant-wide List
/delivery/institution-branchesLists active branch/location records across all institutions in the tenant. Optional filters: institution_user_id, is_active, search, page, limit. Use this for the destination modal's Institution locations combobox. Response includes branch address and institution user basic profile.
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
is_active | string | Example: |
institution_user_idOptional | string | Example: |
searchOptional | string | Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institution-branches?page=1&limit=20&is_active=true" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Institution Branches - Lookup by Code
/delivery/institution-branches/by-code/{{branch_code}}Exact lookup for driver branch QR scanning. The QR should contain the branch code, URL-encoded if needed. By default only active branches are returned. Response includes branch detail, address, default processing point, and institution_user. If the same code exists for multiple institutions in the tenant, the API returns 409 branch_code_ambiguous with matching branch/institution summaries.
Path parameters
| Parameter | Type | Description |
|---|---|---|
branch_codeRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
include_inactiveOptional | string | Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institution-branches/by-code/${BRANCH_CODE}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Institution Branches - Get Detail
/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}Gets a branch owned by the institution.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
branch_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/branches/${BRANCH_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Institution Branches - Update
/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}Updates branch fields.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
branch_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
name | string | — |
default_processing_point_id | string | — |
metadata | object | — |
metadata.updated_from | string | — |
1curl --globoff --request PATCH "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/branches/${BRANCH_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "name": "G2G Branch Updated",6 "default_processing_point_id": "{{processing_point_id}}",7 "metadata": {8 "updated_from": "postman"9 }10}'Replace {{placeholders}} with your own values before sending.
Response examples
No saved response example. Use Try it to inspect a staging response.
Institution Branches - Deactivate
/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}/deactivateSoft-deactivates a branch. Fails when non-terminal manifests reference it.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
branch_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/branches/${BRANCH_ID}/deactivate" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{}'Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - Generate Batch
/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}/barcode-batchesGenerates postal-grade G2G barcode identities for an institution branch. prefix is optional; when omitted or blank, the backend uses the branch code as the prefix. The effective prefix must be exactly G + governorate letter + 5-digit Pickup Location ID (PLI), for example GE00001. The backend atomically reserves a 6-digit serial per governorate/PLI and appends a MOD 11 check digit calculated from PLI + serial. The first three values for GE00001 are GE000010000017, GE000010000025, and GE000010000033. A governorate/PLI cannot be assigned to another branch. Max quantity is 5000. Does not create driver tasks. Frontend: send quantity; send prefix only when overriding the branch code. Error code remains machine-readable (invalid_g2g_prefix, invalid_g2g_batch_quantity, g2g_pickup_location_already_assigned, g2g_serial_exhausted, or g2g_branch_not_available), while message is localized using language or Accept-Language. Branch on code and display the returned plain-language message.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
branch_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
quantity | number | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/branches/${BRANCH_ID}/barcode-batches" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "quantity": 36}'Response examples
1{2 "success": true,3 "message": "Created successfully",4 "data": {5 "batch_id": "uuid",6 "prefix": "GE00001",7 "start_sequence": 1,8 "end_sequence": 3,9 "quantity": 3,10 "status": "generated",11 "print_file_url": null12 }13}Barcodes - List Batches
/delivery/institutions/{{institution_user_id}}/barcode-batchesLists barcode batches for an institution.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
statusOptional | string | Optional: draft | generated | printed | voided Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/barcode-batches?page=1&limit=20&status=generated" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - List Branch Barcodes
/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}/barcodesLists individual barcodes for a branch. Pick an available barcode_value for manifest scanning.
Path parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_idRequired | string | Variable used inside the request path. |
branch_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
statusOptional | string | Optional barcode status filter Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institutions/${INSTITUTION_USER_ID}/branches/${BRANCH_ID}/barcodes?page=1&limit=20&status=available" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - Lookup Barcode
/delivery/institution-barcodes/{{barcode_value}}Looks up a scanned G2G barcode by barcode_value. The value must be a valid 14-character postal barcode with a matching MOD 11 check digit; malformed or checksum-invalid input returns HTTP 400 with stable code=invalid_barcode and a localized plain-language message before lookup. Frontend must branch on code and display message.
Path parameters
| Parameter | Type | Description |
|---|---|---|
barcode_valueRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/institution-barcodes/${BARCODE_VALUE}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - Get Batch Detail
/delivery/barcode-batches/{{batch_id}}Gets batch detail plus individual barcodes.
Path parameters
| Parameter | Type | Description |
|---|---|---|
batch_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/barcode-batches/${BATCH_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - List Batch Barcodes
/delivery/barcode-batches/{{batch_id}}/barcodesTenant-scoped batch barcode list. page is 1-based; limit defaults to 50 and is capped at 100. Optional status and search filters apply before pagination. Returns {success, message, data: [{id, barcode_value, status, ...}], pagination: {page, limit, total, total_pages}} ordered by barcode_value ascending. Full-batch CSV: fetch all pages without search/status filters; verify unique IDs/values and count against pagination.total and batch.quantity before downloading. Selected CSV: use the same paginated list and include only selected IDs; fail if any selected record is missing. CSV is generated in the frontend and does not update printed_at, status, or print_file_url. Errors: 400 invalid filters/missing tenant, 404 missing batch, 500 unexpected error.
Path parameters
| Parameter | Type | Description |
|---|---|---|
batch_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/barcode-batches/${BATCH_ID}/barcodes?page=1&limit=100" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - Print Batch
/delivery/barcode-batches/{{batch_id}}/printGenerates a printable PDF for a barcode batch. Send an empty body or { "print_mode": "all" } to print all barcodes; this stores the returned file URL on institution_barcode_batches.print_file_url and marks the batch printed. Send print_mode=selective with barcode_ids, barcode_values, or barcodes to print only selected barcodes; this returns the PDF URL and updates institution_item_barcodes.printed_at only for selected rows without changing the batch print_file_url. Barcode row status remains the lifecycle status (available, in_manifest, etc.) so printed but unused barcodes can still be scanned. Full exports fetch every page and verify the stored count against the batch quantity before rendering. Larger batches are rendered in bounded chunks and merged into one PDF before upload. Every export has a unique file URL; selective exports never overwrite the saved full-batch file. The response data contains batch_id, print_mode, status, print_file_url, printed_at, printed_count (actual count in both modes), and barcode_ids (selected IDs or null for all). Frontend: open print_file_url for either mode, but update the cached batch download URL/status only for print_mode=all. A 500 response with code=barcode_export_incomplete means the count or uniqueness checks failed; do not report success or download a partial file. Existing errors: 400 for missing tenant/selection, 404 for missing batch or requested barcode, 409 for a voided batch, and localized 500 for rendering, upload, or bookkeeping failure.
Path parameters
| Parameter | Type | Description |
|---|---|---|
batch_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
print_mode | string | — |
barcode_ids | array<string> | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/barcode-batches/${BATCH_ID}/print" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "print_mode": "selective",6 "barcode_ids": [7 "{{barcode_id}}"8 ]9}'Replace {{placeholders}} with your own values before sending.
Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - Void Single Barcode
/delivery/institution-barcodes/{{barcode_id}}/voidVoids a single barcode only when status is available.
Path parameters
| Parameter | Type | Description |
|---|---|---|
barcode_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/institution-barcodes/${BARCODE_ID}/void" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{}'Response examples
No saved response example. Use Try it to inspect a staging response.
Barcodes - Void Batch
/delivery/barcode-batches/{{batch_id}}/voidVoids an entire batch only if all barcodes are unused (available or already void).
Path parameters
| Parameter | Type | Description |
|---|---|---|
batch_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/barcode-batches/${BATCH_ID}/void" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{}'Response examples
No saved response example. Use Try it to inspect a staging response.
Driver - Create Draft Manifest
/delivery/transfer-manifestsDriver creates a draft transfer manifest for an institution branch. Normally driver_id resolves from the driver token; body driver_id is included here for explicit testing.
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
institution_user_id | string | — |
source_branch_id | string | — |
processing_point_id | string | — |
driver_id | string | — |
notes | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "institution_user_id": "{{institution_user_id}}",6 "source_branch_id": "{{branch_id}}",7 "processing_point_id": "{{processing_point_id}}",8 "driver_id": "{{driver_id}}",9 "notes": "Postman transfer manifest test"10}'Replace {{placeholders}} with your own values before sending.
Response examples
1{2 "success": true,3 "message": "created_successfully",4 "data": {5 "id": "uuid",6 "manifest_number": "TM-...",7 "status": "draft"8 }9}Driver - Scan Item Barcode
/delivery/transfer-manifests/{{manifest_id}}/items/scanScans a barcode into a draft or picked_up manifest. The claim, manifest-item insert, barcode custody update, and audit event are atomic. barcode_value must be a valid 14-character G2G postal barcode with a matching MOD 11 check digit. Optional entry_method accepts only manual or camera and defaults to camera when omitted. The normalized value is persisted as payload.entry_method on the atomic item_scanned event; item status and the success response remain unchanged. Invalid values return HTTP 400 with code=invalid_entry_method and a localized message. Every barcode failure returns { success: false, code, message }; mobile must classify by code, not translated message. Codes/statuses: invalid_barcode (400), barcode_not_found (404), barcode_institution_mismatch (400), barcode_branch_mismatch (400), barcode_voided (409), barcode_already_scanned (409 when the barcode already belongs to this manifest), barcode_already_used (409 when it belongs to another manifest/workflow), and internal_server_error (500). Concurrent duplicate scans return the same stable conflict codes. Frontend integration: send entry_method=manual only when the operator typed the barcode; otherwise send camera or omit the field.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
barcode_value | string | — |
entry_method | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/scan" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "barcode_value": "{{barcode_value}}",6 "entry_method": "camera"7}'Replace {{placeholders}} with your own values before sending.
Response examples
1{2 "success": true,3 "message": "item_added_successfully",4 "data": {5 "id": "uuid",6 "barcode_value": "GE000010000017",7 "status": "scanned"8 }9}Driver - Remove Item Before Submit
/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}Removes a scanned item only while the manifest is still draft. The operation is atomic: it returns the barcode to available, deletes the manifest item, reconciles expected_item_count to the actual remaining row count, and records item_removed in manifest history. A success response guarantees that the database item row was deleted.
Frontend integration
call DELETE with the manifest ID and item ID from the current manifest item. On HTTP 200, remove that item from the local list and use data.remaining_item_count as the authoritative count. Handle 404 as a stale/missing manifest or item, 409 as a manifest that is no longer editable, and 500 as a failed removal; do not remove the item locally for non-200 responses.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
item_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request DELETE "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/${ITEM_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "item_removed_successfully",4 "data": {5 "id": "{{item_id}}",6 "manifest_id": "{{manifest_id}}",7 "barcode_value": "SPB00100000008",8 "remaining_item_count": 19 }10}Driver - Submit Pickup
/delivery/transfer-manifests/{{manifest_id}}/submit-pickupLocks the scan list and moves manifest draft -> picked_up. Items move scanned -> picked_up. Requires at least one item. Accepts optional photo_urls (string[]) and signature_url (string) for proof of pickup. Required fields depend on tenant proof_settings (transfer_manifest > proof_settings.pickup).
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
photo_urls | array<string> | — |
signature_url | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/submit-pickup" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "photo_urls": [6 "https://cdn.example.com/photos/pickup_1.jpg"7 ],8 "signature_url": "https://cdn.example.com/signatures/pickup_sig.png"9}'Response examples
No saved response example. Use Try it to inspect a staging response.
Driver - Driver Action
/delivery/transfer-manifests/{{manifest_id}}/driver-actionGeneric driver action endpoint for transfer manifests. Supported action values: submit_pickup, arrive_processing. Accepts optional photo_urls (string[]) and signature_url (string) for proof capture at the relevant lifecycle stage. Required fields depend on tenant proof_settings (transfer_manifest > proof_settings.pickup/delivery).
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
action | string | — |
photo_urls | array<string> | — |
signature_url | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/driver-action" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "action": "submit_pickup",6 "photo_urls": [7 "https://cdn.example.com/photos/pickup_1.jpg"8 ],9 "signature_url": "https://cdn.example.com/signatures/pickup_sig.png"10}'Response examples
No saved response example. Use Try it to inspect a staging response.
Driver - Arrive Processing
/delivery/transfer-manifests/{{manifest_id}}/arrive-processingMarks the manifest as awaiting receipt at the processing point. Accepts optional photo_urls (string[]) and signature_url (string) for proof of delivery. Required fields depend on tenant proof_settings (transfer_manifest > proof_settings.delivery).
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
photo_urls | array<string> | — |
signature_url | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/arrive-processing" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "photo_urls": [6 "https://cdn.example.com/photos/delivery_1.jpg"7 ],8 "signature_url": "https://cdn.example.com/signatures/delivery_sig.png"9}'Response examples
No saved response example. Use Try it to inspect a staging response.
App - Change Manifest Status
/delivery/transfer-manifests/{{manifest_id}}/statusMoves a Transfer Manifest through its forward transport stages or cancels it. Receiving, destination assignment/order creation, and completion remain dedicated actions after arrival.
Legacy flat
photo_urlsandsignature_urlremain accepted when the request crosses only one proof stage.
Forward state machine
draft -> picked_up -> in_transit -> awaiting_receipt.
A request may target any later transport state. The backend runs every missing intermediate transition and records the same submitted reason and notes on each transition event.
Cancellation
cancelledis allowed fromdraft,picked_up,in_transit, orawaiting_receipt.Cancellation uses the existing atomic cancellation operation: non-order-created items become
voidand their linked barcodes return toavailable.Cancellation is rejected after receiving starts or when an order has already been created.
The dedicated
POST /delivery/transfer-manifests/{id}/cancelendpoint remains supported for compatibility.
After awaiting_receipt, use the existing dedicated actions:
Start receiving:
POST /delivery/transfer-manifests/{id}/receive/start.Receive scanned items:
POST /delivery/transfer-manifests/{id}/receive/items.Complete receiving:
POST /delivery/transfer-manifests/{id}/receive/complete.Assign destinations/create orders: the existing item destination or bulk destination endpoints.
Complete manifest:
POST /delivery/transfer-manifests/{id}/complete.
Success response data contains id, previous_status, requested_status, authoritative status, submitted reason, optional notes, reached_target, ordered executed_transitions, and allowed_next_statuses. Transport responses include every later transport target plus cancelled while cancellation remains available. A cancellation response also includes voided_count.
Important errors
HTTP 400
invalid_manifest_status: missing or unknown status;data.allowed_statusescontainspicked_up,in_transit,awaiting_receipt, andcancelled.HTTP 400
manifest_status_reason_required:reasonis missing or blank.HTTP 400 for oversized reason/notes or required pickup/delivery proof; display the localized
message.HTTP 404
manifest_not_found.HTTP 409
invalid_manifest_status_transition: backward, same-state, or post-arrival target.HTTP 409
manifest_cannot_be_cancelledormanifest_cannot_be_cancelled_orders_created: cancellation business rule failed.
Frontend integration contract
Always collect and send non-blank
reason; sendnotesonly when provided.Render status actions from
data.allowed_next_statuses, including the literalcancelledaction.After HTTP 200, use
data.statusas authoritative and do not update optimistically.At
awaiting_receipt, use the existing receiving/processing buttons for later work;cancelledremains available only if returned by the backend.Display localized
messageand branch on stablecode. No navigation action is returned.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
statusRequired | string |
|
reasonRequired | string | (required, max 2000 characters): a non-blank operator reason recorded on every executed status event. |
notesOptional | string | (optional, max 2000 characters): additional audit context recorded with the reason. |
proofs | object | — |
proofs.pickupOptional | object | optional |
proofs.pickup.photo_urls | array | — |
proofs.pickup.signature_url | null | — |
proofs.deliveryOptional | object | optional |
proofs.delivery.photo_urls | array | — |
proofs.delivery.signature_url | null | — |
1curl --globoff --request PATCH "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/status" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "status": "awaiting_receipt",6 "reason": "Manifest reached the destination processing point",7 "notes": "Optional dispatcher note",8 "proofs": {9 "pickup": {10 "photo_urls": [],11 "signature_url": null12 },13 "delivery": {14 "photo_urls": [],15 "signature_url": null16 }17 }18}'Response examples
1{2 "success": true,3 "message": "Transfer manifest status updated successfully",4 "data": {5 "id": "manifest-uuid",6 "previous_status": "draft",7 "requested_status": "awaiting_receipt",8 "status": "awaiting_receipt",9 "reason": "Manifest reached the destination processing point",10 "notes": "Optional dispatcher note",11 "reached_target": true,12 "executed_transitions": [13 {14 "from_status": "draft",15 "to_status": "picked_up"16 },17 {18 "from_status": "picked_up",19 "to_status": "in_transit"20 },21 {22 "from_status": "in_transit",23 "to_status": "awaiting_receipt"24 }25 ],26 "allowed_next_statuses": [27 "cancelled"28 ]29 }30}Driver - List My Transfer Manifests
/delivery/driver/transfer-manifestsDriver-scoped manifest list. Returns only manifests assigned to the authenticated driver. Optional search matches the manifest number OR a contained item barcode (case-insensitive partial matching), while preserving tenant and driver scope, counts, and pagination. Returns each matching manifest once; no match returns an empty list.
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
search | string | Case-insensitive partial search by manifest number OR any item barcode in the manifest. Accepts a full barcode or a suffix such as the last 6 digits. Returns each matching manifest once. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/driver/transfer-manifests?page=1&limit=20&search=" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Driver - Get My Transfer Manifest
/delivery/driver/transfer-manifests/{{manifest_id}}Driver-scoped manifest detail. Returns 404 if the manifest belongs to another driver.
Requires
Authorization: Bearer {{access_token}}for the assigned driver.
Successful response
datacontains the transfer manifest header, five maintained counts (expected_item_count,received_item_count,exception_item_count,order_created_count,voided_item_count), institution user, processing point,source_branch,branch, andproofRequirements.data.cancel_reasonisnullfor active manifests and containspayload.reasonfrom the latestmanifest_cancelledevent whendata.statusiscancelled.proofRequirements(object):{ pickup: { photo_required, signature_required }, delivery: { photo_required, signature_required } }— tells the app what proof must be captured at each stage based on tenant settings.data.branchis the source branch information object and mirrorsdata.source_branchfor frontend convenience.Branch fields include
id,tenant_id,institution_user_id,address_id,name,code,contact_info,default_processing_point_id,is_active,metadata,address, anddefault_processing_point.When proof has been captured,
data.proof_of_pickupand/ordata.proof_of_deliveryare present with{ photos, signature_url, captured_at, captured_by }.
Frontend integration contract
Use the five count fields directly; do not derive them from a paginated item list.
Use
data.cancel_reasonto display cancellation reason on cancelled manifests.Use
data.branchordata.source_branchto render source branch name/code and branch address.Continue using
data.source_branch_idas the stable entity ID for follow-up API calls.Read
proofRequirementsto determine which capture fields to show/enforce at pickup and delivery stages.On HTTP 404, navigate away from the manifest detail screen or show a stale/unauthorized manifest state.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/driver/transfer-manifests/${MANIFEST_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - List Transfer Manifests
/delivery/transfer-manifestsDispatcher list with tenant-scoped server-side filters, exact filtered pagination totals, and deterministic sorting. Existing page, limit, search, status, institution_user_id, source_branch_id, processing_point_id, date_from, date_to, and barcode_value behavior remains supported. Every populated column_filters value is AND-combined with the standalone filters and search before count and pagination. Empty values are ignored; populated unsupported keys and invalid UUID, number, range, or YYYY-MM-DD date values return HTTP 400. Date to values include the complete UTC day. search remains top-level and is not read from column_filters. Tenant cannot be overridden through column_filters.
Supported column filters
manifest_number: case-insensitive contains.status: exact string.institution_user_id,processing_point_id: exact UUID.expected_item_count,received_item_count,exception_item_count,order_created_count: inclusive{ min?, max? }non-negative numeric range.picked_up_at,received_at,arrived_at,completed_at,created_at: inclusive{ from?, to? }YYYY-MM-DD range.
Examples
Text:
column_filters={"manifest_number":"TM"}Exact status:
column_filters={"status":"receiving"}Autocomplete UUID:
column_filters={"institution_user_id":"11111111-1111-4111-8111-111111111111"}Numeric range:
column_filters={"expected_item_count":{"min":1,"max":100}}Date range:
column_filters={"created_at":{"from":"2026-08-01","to":"2026-08-31"}}Sorted response:
sort_by=processing_point_id&sort_order=ascsorts by processing-point name, with nulls last andid DESCas the deterministic secondary order.
Allowed sort_by: manifest_number, status, institution_user_id, processing_point_id, the four count fields, the five timestamp fields, and created_at. Missing or invalid sort_by uses created_at DESC; invalid sort_order returns HTTP 400 invalid_sort_order.
The response structure remains unchanged
data, status_matrix, and pagination. pagination.total is the filtered count before limit/offset. Each row includes the five maintained item counts, received_by, received_by_user (id, full_name, email), institution_user (id, full_name, email, phone, avatar_url), and processing_point (id, name, code, address_id) relationship objects. received_item_count is the durable number of items with received_at; it remains populated after those items become orders.
Frontend integration contract
JSON-encode column_filters; keep global search in search; use IDs from autocomplete selections; omit empty filters; send only documented sort_by values and asc/desc; retain the existing response mapper; display localized HTTP 400 message and use code for branching. Render Received By from received_by_user and Received Time from received_at; no extra user lookup is required.
Global search
send only search for manifest-number or item-barcode lookup. Both are OR-combined within the authenticated tenant before filtering, exact counts, status_matrix, sorting, and pagination. Matching multiple items does not duplicate a manifest; a barcode in multiple manifests returns every matching manifest. Full and partial barcodes (including the last 6 digits) are supported. No match returns data: [] and zero pagination totals. Default sorting remains newest first. The separate barcode_value filter remains supported and is AND-combined when explicitly supplied. No new response fields or permissions are required. Frontend: keep sending search and label the input "Search manifest number or item barcode...".
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
statusOptional | string | Optional manifest status |
institution_user_idOptional | string | Optional institution |
source_branch_idOptional | string | Optional source branch id |
processing_point_idOptional | string | Optional processing point id |
date_fromOptional | string | Optional |
date_toOptional | string | Optional |
search | string | Case-insensitive partial search by manifest number OR any item barcode in the manifest. Accepts a full barcode or a suffix such as the last 6 digits. Returns each matching manifest once. |
barcode_valueOptional | string | Optional case-insensitive partial G2G barcode filter. Returns manifests containing a matching item barcode. |
column_filtersOptional | string | Optional JSON-encoded column filters. Supported keys: Example: |
sort_byOptional | string | Optional whitelisted sort column. Example: |
sort_orderOptional | string | Optional asc or desc. Defaults to desc when a valid Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests?page=1&limit=20&status=&institution_user_id=&source_branch_id=&processing_point_id=&date_from=&date_to=&search=&barcode_value=&column_filters=%7B%22status%22%3A%22receiving%22%2C%22expected_item_count%22%3A%7B%22min%22%3A1%2C%22max%22%3A100%7D%2C%22created_at%22%3A%7B%22from%22%3A%222026-08-01%22%2C%22to%22%3A%222026-08-31%22%7D%7D&sort_by=created_at&sort_order=desc" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": false,3 "code": "invalid_column_filters_json",4 "message": "Invalid column_filters JSON",5 "details": [6 {7 "field": "column_filters",8 "message": "Invalid column_filters JSON"9 }10 ]11}Dispatcher - Get Manifest Detail
/delivery/transfer-manifests/{{manifest_id}}Manifest detail with source branch, processing point, source address, driver, creator, and receiver embeds.
Requires
Authorization: Bearer {{access_token}}.
Successful response
datacontains the transfer manifest header and five database-maintained counts:expected_item_count,received_item_count,exception_item_count,order_created_count, andvoided_item_count. Counts are recalculated after every item write, including empty manifests.received_item_countis historical custody evidence based on itemreceived_at, so it does not fall back to zero after order creation.Every received manifest includes
received_at,received_by, andreceived_by_user. Legacy manifests that previously skipped receipt remain readable; the backend does not invent missing custody data.data.cancel_reasonisnullfor active manifests and containspayload.reasonfrom the latestmanifest_cancelledevent whendata.statusiscancelled.data.branchis the source branch information object and mirrorsdata.source_branchfor frontend convenience.Branch fields include
id,tenant_id,institution_user_id,address_id,name,code,contact_info,default_processing_point_id,is_active,metadata,address, anddefault_processing_point.data.source_addressremains the manifest's stored source address snapshot/reference.
Frontend integration contract
Use the five count fields directly; do not derive them from the paginated item list.
Render Received By from
data.received_by_userand Received Time fromdata.received_at.Use
data.cancel_reasonto display cancellation reason on cancelled manifests.Use
data.branchordata.source_branchto render source branch name/code and branch address without an extra branch lookup.Continue using
data.source_branch_idas the stable branch entity ID for filters and follow-up API calls.On HTTP 404, show a missing/stale manifest state; on HTTP 400, tenant context is missing.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - List Manifest Items
/delivery/transfer-manifests/{{manifest_id}}/itemsReturns paginated items for one transfer manifest. Search matches either the G2G barcode or the denormalized delivery code written when the item becomes an order. Barcode matching uses the submitted search text unchanged. Delivery-code matching removes a leading DEL prefix when present, so DEL1911, DEL19, 1911, and 19 can match delivery_code 1911. Existing linked items are backfilled from deliveries. PostgREST control characters are escaped by the backend.
requires Authorization: Bearer {{access_token}}.
Filters
statusfilters the primary manifest-item status. Usestatus=order_createdto list items promoted to delivery orders.delivery_statusoptionally filters the linked delivery's exact status. It is tenant- and manifest-scoped and applied in the database before the exact count and page range.destination_addedfilters whether the item has a stored destination-address snapshot.
Success
HTTP 200 with data and exact pagination fields page, applied limit, requested_limit, limit_capped, max_limit, total, and total_pages. Promoted items include delivery_code, delivery_id, delivery, and destination_address. destination_address is the JSON snapshot copied from the current linked delivery and is returned directly without reading the addresses table. destination_address_id remains the optional address-book reference and can be null for custom map or Places locations. Each item also returns can_change_destination and destination_change_block_code. The action is allowed for users with manage:operations:tenant, manage:module:delivery, or system-admin access while the linked order is not delivered, returned, or cancelled. Manifest completion does not disable the action because manifest status represents order-creation processing, not final delivery. When a requested limit exceeds 200, the backend returns up to 200 rows, sets pagination.limit=200, pagination.requested_limit to the submitted number, pagination.limit_capped=true, pagination.max_limit=200, top-level code=manifest_items_page_limit_applied, and a localized explanatory message. Normal requests set limit_capped=false and omit the top-level code.
Errors
HTTP 400 when tenant context is missing, HTTP 404 when the manifest is missing, and HTTP 500 for database failures.
Frontend integration contract
continue rendering data[].destination_address.full_address. Show the Change destination row action only when data[].can_change_destination=true; do not derive availability from the manifest status. destination_change_block_code is null when allowed and otherwise explains the permission or order-state refusal. Use pagination.limit as the applied page size. When pagination.limit_capped=true or code=manifest_items_page_limit_applied, show the localized message and reconcile the grid page size to pagination.limit. For a manifest Delivery Orders view, send status=order_created, use search for order-code or item-barcode search, and send delivery_status for the Order Status filter. Use data[].delivery.id to open the existing order detail surface. No navigation action is returned by this endpoint.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Page number. Default: 1. Example: |
limit | string | Items per page. Default: 50; maximum: 200. Example: |
search | string | Case-insensitive partial search against |
statusOptional | string | Optional exact manifest-item status. |
delivery_statusOptional | string | Optional exact status of the linked delivery. Applied in the database before counting and pagination. |
destination_addedOptional | string | Optional boolean filter based on whether the manifest item has a stored |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items?page=1&limit=50&search=&status=&delivery_status=&destination_added=" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Start Receiving
/delivery/transfer-manifests/{{manifest_id}}/receive/startBegins receipt at the processing point. The manifest must be in awaiting_receipt, which confirms that arrival has been completed. Any other current status returns HTTP 409 with { "success": false, "message": <localized invalid manifest status transition message> }, and receiving does not start.
Success
HTTP 200 returns { "success": true, "message": <localized success message>, "data": { "id": <manifest_id>, "status": "receiving" } }.
Frontend integration contract
enable Start Receiving only when the manifest status is exactly awaiting_receipt. On HTTP 409, keep the current manifest state and display the returned localized message. No request fields or navigation behavior change.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/receive/start" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{}'Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Receive Items
/delivery/transfer-manifests/{{manifest_id}}/receive/itemsMarks submitted items received in scan_each_item mode and supports partial batch success. Optional top-level entry_method accepts only manual or camera, applies to every barcode in this request, and defaults to camera when omitted.
Business rules
The manifest must be in
receivingstatus.Only manifest items in
scanned,picked_up, orin_transitstatus can be newly received.Item state, barcode state,
received_at, one item-levelitem_receivedevent per item, and the aggregateitems_receivedevent are written atomically in one database call. User-driven events persist the normalized value aspayload.entry_method; automated count-only and bulk receipts do not fabricate an entry method.Invalid
entry_methodreturns HTTP 400 withcode=invalid_entry_methodand a localizedmessage; no submitted item is changed.data.receivedcontains only barcodes newly received by this request.data.received_countalways equalsdata.received.length; already-received barcodes never appear here, preventing count inflation.data.already_processedcontains submitted barcodes already inreceivedor another non-receivable item status. These are completed items, not invalid barcodes, so they do not appear indata.invalid_barcodes.data.not_in_manifestcontains every submitted barcode absent from this transfer manifest.data.not_foundis the subset ofnot_in_manifestthat is also absent from the tenant barcode registry.data.invalid_barcodesgives the exact per-barcode reason, includinginvalid_barcode,unknown_barcode,not_part_of_this_manifest,wrong_branch,wrong_institution,already_used_in_another_manifest. Classification lists intentionally overlap where useful: for example, an unknown barcode appears in bothnot_in_manifestandnot_found.A malformed barcode is classified without stopping the rest of the batch, and its response message uses the localized
invalid_barcodetranslation.Valid receivable barcodes are committed even when other submitted barcodes fail. A mixed result returns HTTP
200,success=true, localized messagePartially completed, the newly received barcodes inreceived, and all failures in the other lists.When no barcode is newly received and failures remain, the endpoint returns HTTP
409,success=false. An already-processed-only request uses the localized already-processed message; a malformed-only request also returnscode=invalid_barcode.
Frontend integration contract
Send
entry_method=manualonly when the operator typed the submitted barcode values; otherwise sendcameraor omit the field.Treat each response list as the source of truth; do not infer the whole batch result from only the HTTP status.
Add only
data.receivedto the newly received UI state and increment by exactlydata.received_count.Do not add
data.already_processedagain or show it under Invalid Barcodes; show it under Already Processed with the localized messageThis item has already been processedin English.Show
data.not_in_manifest,data.not_found, anddata.invalid_barcodes[]as per-barcode failures.data.invalid_barcodes[]contains only actual validation failures.On HTTP
200withmessage=Partially completed, retain the failed barcodes for correction while applying the successfulreceivedentries.On HTTP
409, no submitted barcode was newly received. No navigation change is required.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
barcode_values | array<string> | — |
entry_method | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/receive/items" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "barcode_values": [6 "{{barcode_value}}"7 ],8 "entry_method": "camera"9}'Replace {{placeholders}} with your own values before sending.
Response examples
1{2 "success": true,3 "message": "Items received successfully",4 "data": {5 "received_count": 1,6 "received": [7 "GE000010000017"8 ],9 "invalid_barcodes": [],10 "not_in_manifest": [],11 "not_found": [],12 "already_processed": []13 }14}Dispatcher - Complete Receiving
/delivery/transfer-manifests/{{manifest_id}}/receive/completeCompletes receipt. In scan_each_item mode, remaining unreceived items become missing_at_receipt exceptions. In count_only mode, open items are atomically marked received with one item-level item_received event per item before the manifest receipt completes.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
notes | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/receive/complete" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "notes": "Receipt completed from Postman"6}'Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Assign Item Destination
/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/destinationAssigns destination address and delivery service to one received item, then immediately creates the delivery order using institution wallet payment with payer_type=sender. destination_branch_id is optional; remove it or leave blank if not applicable. delivery_service_id is optional when G2G settings has default_delivery_service_id configured; otherwise it is required. Destination branches must be active and have an address. Fails if item is not received or is terminal.
The created order always uses the manifest processing point as its pickup location. transfer_manifest.delivery_fee_origin controls only the fee calculation: processing_point prices from that pickup location; source_location prices from the manifest's stored source address. When source_location is selected but the source address is unavailable, the endpoint returns HTTP 400 with source_address_unresolved.
Delivery creation honors the effective policy of the selected delivery service, including pricing fallback, payment policy, and warehouse staging policy. For a staged Pickup and Delivery or Delivery order with no package items, the backend creates one fallback warehouse inventory item named from the delivery code and customer name. Non-delivery service types can still fail with warehouse_staging_only_supported_for_pickup_and_delivery. A staged P&D promotion commits its parent, A/B legs, inventory item, receiving order, and sequence plan atomically; an internal creation failure leaves no promotable partial order, and a retry will not accept a historical staged parent without a complete A/B sequence plan. Automatically allocated inventory item codes skip codes already claimed manually.
Event
an item_destination_set event is recorded with payload.barcode_value set to the item's barcode.
Manifest origin and label behavior
The operational pickup remains the manifest processing point; receiver/dropoff behavior is unchanged.
At order creation, the backend stores
source_transfer_manifest_meta.snapshot_version=manifest_origin_v1with the manifest number, item barcode, source institution ID/name, item source branch ID/name/code, cleaned branch address, branch phone when available, processing-point ID, and existing pickup/pricing audit fields. The source comes from each manifest item, not from the processing point.A warehouse-staged parent stores the manifest ID, manifest item ID, and snapshot. Its inbound/outbound A/B legs store the manifest ID and the same snapshot, but not the item ID, preserving the one-order-per-manifest-item constraint.
The canonical direct/parent order uses the dedicated
manifest_shipment_labelassignment. A/B operational legs keep their existing operational labels. Label generation reads the stored snapshot without joining manifest, branch, institution, or address tables; normal deliveries keep the existingshipment_labelpath.
Frontend integration contract
no request fields, response fields, actions, or navigation behavior change. Continue using the returned delivery exactly as before; the generated label URL now points to the manifest-specific label for newly promoted canonical manifest orders.
For each created G2G delivery order, an omitted unit_size with no usable measurements is resolved by general.unit_size.settings.missing_unit_size_fallback. The configured value may select the service minimum, half of the service maximum, the service maximum, or reject creation.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
item_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
destination_address_id | string | — |
delivery_service_id | string | — |
destination_branch_id | string | — |
1curl --globoff --request PATCH "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/${ITEM_ID}/destination" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "destination_address_id": "{{destination_address_id}}",6 "delivery_service_id": "{{delivery_service_id}}",7 "destination_branch_id": "{{destination_branch_id}}"8}'Replace {{placeholders}} with your own values before sending.
Response examples
1{2 "success": false,3 "code": "manifest_destination_branch_required",4 "message": "A destination branch is required for manifest orders",5 "details": [6 {7 "field": "destination_branch_id",8 "code": "required",9 "message": "A destination branch is required for manifest orders"10 }11 ]12}Dispatcher - Bulk Assign Destination
/delivery/transfer-manifests/{{manifest_id}}/items/bulk-assign-destinationAssigns the same destination and service to multiple received items, then creates delivery orders using institution wallet payment with payer_type=sender. Delivery creation uses bounded parallel processing. Successful promotions are finalized by one database operation that links deliveries, items, and barcodes and updates the manifest state and bulk event once.
Request selectors (at least one is required)
item_ids: non-empty array of transfer manifest item UUIDs.barcode_values: non-empty array of scanned or manually entered barcode strings. Values are trimmed, normalized to uppercase, and deduplicated.Both arrays may be sent; matching eligible items are combined and deduplicated before order creation.
HTTP 400 validation error
item_ids_or_barcode_values_requiredis returned when neither array contains a usable value.
delivery_service_id is optional when G2G settings has default_delivery_service_id configured; otherwise it is required. Send either destination_branch_id or destination_address_id. Destination branches must be active and have an address. Only items under the path manifest with status received and no linked delivery are eligible.
Barcode validation follows the receiving contract
data.invalid_barcodescontains one object per rejected barcode with its exact machine-readable reason:invalid_barcode,unknown_barcode,not_part_of_this_manifest,wrong_branch,wrong_institution,already_used_in_another_manifest, oralready_processed.An
unknown_barcodeentry also includes localizedmessage. In English it isThis barcode is not in this manifest; the frontend must displaymessageand keepreasononly for branching.data.not_in_manifestcontains every submitted barcode absent from the path transfer manifest.data.not_foundis the subset ofnot_in_manifestalso absent from the tenant barcode registry. Classification lists intentionally overlap; an unknown barcode appears in both lists and has aninvalid_barcodesentry.data.already_processedcontains same-manifest barcodes that are no longer eligible or already have a linked delivery. The matchinginvalid_barcodesobject includesitem_statusanddelivery_id; these barcodes are never executed again.data.validation_failed_countequalsdata.invalid_barcodes.length.failed_countcontinues to count only eligible items that reached order promotion and failed there.Every
data.created[]and promotiondata.failed[]entry includesbarcode_value, allowing the caller to show the exact barcode as added or failed.Valid received barcodes are still executed when other submitted barcodes fail validation. A mixed result returns HTTP 200,
success=true, localizedpartial_success, successful orders increated, and all rejected barcodes in the validation lists.When no selector is eligible and barcode validation failures exist, the endpoint returns HTTP 409,
success=false, and the same complete validation lists. A malformed-only request also returnscode=invalid_barcodewith the localizedinvalid_barcodemessage; an already-processed-only request uses the localized already-processed message; and a not-in-manifest-only request uses localizedThis barcode is not in this manifestin English.Item-ID selectors retain their existing behavior. If there are no eligible item IDs and no barcode classification errors, the endpoint returns HTTP 400
no_ready_items.
The created orders always use the manifest processing point as their pickup location. transfer_manifest.delivery_fee_origin controls only the fee calculation: processing_point prices from that pickup location; source_location prices from the manifest's stored source address. If the source address is unavailable, affected items fail with source_address_unresolved.
Delivery creation honors the effective policy of the selected delivery service, including pricing fallback, payment policy, and warehouse staging policy. For a staged Pickup and Delivery or Delivery order with no package items, the backend creates one fallback warehouse inventory item named from the delivery code and customer name. Non-delivery service types can still fail with warehouse_staging_only_supported_for_pickup_and_delivery. Each staged P&D promotion commits its parent, A/B legs, inventory item, receiving order, and sequence plan atomically; one failed item does not leave a promotable partial order, and retries will not accept a historical staged parent without a complete A/B sequence plan. Automatically allocated inventory item codes skip codes already claimed manually.
Event
a bulk items_destination_bulk_set event is recorded only for successfully promoted items, with each item's barcode_value in the payload.
Frontend integration contract
For scan or manual-code entry, submit selected codes in
barcode_values;item_idsremains supported for existing selection flows.Add only
data.createdto the successfully added/executed UI state and use each entry'sbarcode_valueto show that it was added. Never adddata.already_processedagain; show those barcodes as already processed.Show
data.invalid_barcodes[].messagewhen present; never renderdata.invalid_barcodes[].reasonas user-facing text. Continue usingreasonas the stable machine code.Show
data.not_in_manifest,data.not_found, anddata.invalid_barcodes[]as per-barcode failures.On HTTP 200 with the localized partial-success message, apply
data.createdand retain rejected barcodes for correction. On HTTP 409, no submitted selector was executed.Keep the existing destination and delivery-service fields. No navigation change is required.
Manifest origin and label behavior
The operational pickup remains the manifest processing point; receiver/dropoff behavior is unchanged.
At order creation, the backend stores
source_transfer_manifest_meta.snapshot_version=manifest_origin_v1with the manifest number, item barcode, source institution ID/name, item source branch ID/name/code, cleaned branch address, branch phone when available, processing-point ID, and existing pickup/pricing audit fields. The source comes from each manifest item, not from the processing point.A warehouse-staged parent stores the manifest ID, manifest item ID, and snapshot. Its inbound/outbound A/B legs store the manifest ID and the same snapshot, but not the item ID, preserving the one-order-per-manifest-item constraint.
The canonical direct/parent order uses the dedicated
manifest_shipment_labelassignment. A/B operational legs keep their existing operational labels. Label generation reads the stored snapshot without joining manifest, branch, institution, or address tables; normal deliveries keep the existingshipment_labelpath.
Frontend integration contract
no request fields, response fields, actions, or navigation behavior change. Continue using the returned delivery exactly as before; the generated label URL now points to the manifest-specific label for newly promoted canonical manifest orders.
For each created G2G delivery order, an omitted unit_size with no usable measurements is resolved by general.unit_size.settings.missing_unit_size_fallback. The configured value may select the service minimum, half of the service maximum, the service maximum, or reject creation.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
barcode_values | array<string> | — |
destination_address_id | string | — |
delivery_service_id | string | — |
destination_branch_id | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/bulk-assign-destination" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "barcode_values": [6 "{{barcode_value}}"7 ],8 "destination_address_id": "{{destination_address_id}}",9 "delivery_service_id": "{{delivery_service_id}}",10 "destination_branch_id": "{{destination_branch_id}}"11}'Replace {{placeholders}} with your own values before sending.
Response examples
1{2 "success": false,3 "code": "manifest_destination_branch_required",4 "message": "A destination branch is required for manifest orders",5 "details": [6 {7 "field": "destination_branch_id",8 "code": "required",9 "message": "A destination branch is required for manifest orders"10 }11 ]12}Dispatcher - Change Manifest Item Destination
/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/change-destinationChanges the destination branch of one existing delivery order linked to an order_created manifest item. Requires manage:operations:tenant, manage:module:delivery, or system-admin access.
The existing delivery is updated in place through the canonical delivery update engine; no second order is created. Pending, assigned, picked-up, and in-transit orders may be changed. Delivered orders return delivery_already_delivered; returned or cancelled orders return manifest_destination_change_not_allowed. The database repeats the status/link/branch checks under deterministic row locks, so a concurrent completion or stale request cannot change a completed order.
A real change recalculates the destination zone and fee, reconciles wallet payment state, updates the staged outbound leg when present, synchronizes the exact branch/address/contact snapshot to the manifest item, and marks an existing shipment label needs_reprint. It appends the normal order_edited event plus an atomic manifest item_destination_changed event containing actor, barcode, old/new branch snapshots, old/new address IDs, and delivery status. Repeating an already-applied identical change returns success without another event.
Success
HTTP 200 with data.item_id, barcode_value, delivery_id, delivery_code, delivery_status, destination_branch_id, destination_address_id, and shipment_label_status.
Frontend integration contract
use the existing institution/branch picker, send the branch ID, and keep the current delivery service selected. Display the localized message; branch on stable code. After success, use the returned IDs/status and refetch the Manifest Items page so its destination snapshot and action flag match the committed order.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
item_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
destination_branch_idRequired | string | required active tenant branch UUID. The branch must have a registered address. Its address and merged address/branch contact details become the delivery destination snapshot. |
delivery_service_idOptional | string | optional compatibility field for the reused picker. When supplied it must equal the order's current service; changing service or delivery structure from this action is rejected. |
reason | string | optional trimmed edit reason, maximum 500 characters; required when the tenant delivery-order setting requires edit reasons. |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/${ITEM_ID}/change-destination" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "destination_branch_id": "{{destination_branch_id}}",6 "delivery_service_id": "{{delivery_service_id}}",7 "reason": "Corrected destination branch"8}'Replace {{placeholders}} with your own values before sending.
Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Bulk Change Manifest Item Destination
/delivery/transfer-manifests/{{manifest_id}}/items/bulk-change-destinationChanges one registered destination branch for up to 200 selected order_created manifest items. Authentication, permission, branch, service-compatibility, status, pricing, wallet, staged-order, label-reprint, exact-branch, audit, and retry rules are the same as the single endpoint. Duplicate item_ids are accepted once and results preserve first-seen request order.
Performance
the handler reads the selected manifest items in one tenant/manifest-scoped query, reads their linked deliveries in one primary-key batch, resolves the destination branch/address once, caches effective service policies and identical pricing inputs, then performs at most four atomic item updates concurrently. Each item remains its own transaction so mixed eligibility returns truthful partial success without rolling back valid corrections.
Success/partial success
HTTP 200 when at least one item succeeds. data contains requested_count, succeeded_count, failed_count, ordered succeeded[], and ordered failed[]. Every failed entry contains item_id, stable code, and localized message. A mixed result uses the localized partial-success message. HTTP 409 is returned when no selected item can be changed.
Frontend integration contract
show the bulk action when at least one selected row has can_change_destination=true. Send the selected manifest item IDs and one branch ID. Keep the current delivery service selected; a different service returns manifest_destination_service_change_not_supported. Display failed[].message, branch on failed[].code, and show the returned succeeded/failed counts. Refetch the Manifest Items page after any success.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
item_ids | array<string> | — |
destination_branch_id | string | — |
delivery_service_id | string | — |
reason | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/bulk-change-destination" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "item_ids": [6 "{{item_id}}"7 ],8 "destination_branch_id": "{{destination_branch_id}}",9 "delivery_service_id": "{{delivery_service_id}}",10 "reason": "Corrected destination branch"11}'Replace {{placeholders}} with your own values before sending.
Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - List Exception Reasons
/delivery/transfer-manifest-exception-reasonsReturns the tenant-configured Transfer Manifest exception reasons for frontend dropdowns. Values come from tenant_settings.setting_key = transfer_manifest, field exception_reasons, filtered to backend-supported canonical values.
Requires
Authorization: Bearer {{access_token}}.
Successful response
data.reasonscontains the tenant-enabled{ value, label, description }options. Usereason.valueasexception_reason.
Frontend integration contract
Populate Mark Exception dropdown options from
data.reasons.Submit only
reason.valueasexception_reasonto the single or bulk exception endpoint.On HTTP 400, show the backend validation message; do not display it as unauthorized.
Important errors
HTTP 400 when tenant context is missing.
HTTP 401 when authentication is missing or invalid.
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-exception-reasons" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Bulk Flag Item Exceptions
/delivery/transfer-manifests/{{manifest_id}}/items/bulk-exceptionMoves one or more eligible manifest items to exception by barcode value. Authentication is required.
Backend-supported reasons
missing_at_receipt, duplicate_barcode, barcode_unreadable, wrong_branch_or_institution, damaged, opened_envelope, restricted_destination, destination_unknown, manual_hold, other. The tenant-enabled subset comes from transfer_manifest.exception_reasons.
Eligibility and duplicate protection
Only items currently in
scanned,picked_up,in_transit,received, orprocessingcan be newly flagged.Items already in
exception,order_created,void, or another ineligible status are never updated or audited again.The conditional database update repeats the eligible-status rule. A concurrent duplicate request is returned as already processed rather than being added twice.
Only rows actually changed appear in
data.flagged, update their institution barcode, and appear in theitem_exceptionevent.
Per-barcode validation
data.invalid_barcodescontains each rejected barcode with its exact reason:invalid_barcode,unknown_barcode,not_part_of_this_manifest,wrong_branch,wrong_institution,already_used_in_another_manifest, oralready_processed.data.not_in_manifestcontains every submitted barcode absent from the path transfer manifest.data.not_foundis the subset ofnot_in_manifestalso absent from the tenant barcode registry. Lists intentionally overlap where useful.data.already_processedcontains same-manifest barcodes that cannot be added again.data.skippedremains the backward-compatible duplicate list and contains the same rejected duplicate/concurrent values.Malformed-barcode failures use localized
invalid_barcode; an already-processed-only request uses localizeditem_already_processed; and a not-in-manifest-only request uses the localized not-in-manifest message.
Partial and error behavior
Valid eligible barcodes are committed even when other submitted barcodes fail validation.
A mixed result returns HTTP
200,success=true, localizedpartial_success, newly added barcodes indata.flagged, and rejected barcodes in the validation lists.When no barcode is newly flagged and validation failures remain, the endpoint returns HTTP
409,success=false. A malformed-only request also returnscode=invalid_barcode.A fully successful request returns HTTP
200,success=true, localizeditem_added_successfully.data.flagged_countalways equalsdata.flagged.length;data.validation_failed_countequalsdata.invalid_barcodes.length.
Event
one bulk item_exception event is recorded only when at least one item is newly flagged. Its barcode list and count contain only newly changed items.
Frontend integration contract
Use
GET /delivery/transfer-manifest-exception-reasonsfor the reason dropdown.Submit barcode strings in
barcode_valuesand the selected reasonvalueinexception_reason.Add only
data.flaggedto exception state and show those barcodes as added.Never add
data.already_processedordata.skippedagain.Show
data.invalid_barcodes,data.not_in_manifest, anddata.not_foundas per-barcode failures.On partial HTTP 200, apply
data.flaggedand retain rejected barcodes. On HTTP 409, no submitted barcode was added. No navigation change is required.
Important errors
HTTP 400 for an invalid body, a reason not enabled for the tenant, or missing tenant context.
HTTP 404 when the manifest is not found.
HTTP 409 when every submitted barcode fails validation or was already processed.
HTTP 401 when authentication is missing or invalid.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
barcode_valuesRequired | array<string> | required non-empty array of barcode strings. Values are trimmed, normalized to uppercase, and deduplicated. |
exception_reasonRequired | string | required tenant-enabled canonical reason value. |
exception_notesOptional | string | optional note, max 2000 characters. |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/bulk-exception" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "barcode_values": [6 "{{barcode_value}}"7 ],8 "exception_reason": "missing_at_receipt",9 "exception_notes": "Item was not in the physical handoff"10}'Replace {{placeholders}} with your own values before sending.
Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Flag Item Exception
/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/exceptionMoves one open manifest item to exception.
Backend-supported values
missing_at_receipt, duplicate_barcode, barcode_unreadable, wrong_branch_or_institution, damaged, opened_envelope, restricted_destination, destination_unknown, manual_hold, other. The tenant-enabled subset comes from transfer_manifest.exception_reasons.
Duplicate-processing rules
Only items currently in
scanned,picked_up,in_transit,received, orprocessingcan be flagged.An item already in
exceptionorvoidreturns HTTP409with the localizeditem_already_processedmessage. An item inorder_createdreturns HTTP409withorder_already_created.The database update repeats the eligible-status condition. If another request processes the item first, this request returns HTTP
409and does not update the barcode or record a duplicate event.
Successful response
HTTP
200with{ success: true, message: <localized item_added_successfully> }; English isItem added successfully.The stored
transfer_manifest_items.exception_reasonis the submitted canonical value.
Event
one item_exception event is recorded only after the item status and institution barcode are successfully updated.
Frontend integration contract
Use
GET /delivery/transfer-manifest-exception-reasonsto populate the reason dropdown.Submit selected reason
valueasexception_reason.Show the returned localized
Item added successfullymessage after HTTP200.On HTTP
409, do not add or execute the item again; show the returned already-processed/order-created message. No navigation change is required.
Important errors
HTTP 400 for invalid body, reason not enabled for the tenant, or missing tenant context.
HTTP 404 when the manifest or item is not found.
HTTP 409 when the item has already been processed.
HTTP 401 when authentication is missing or invalid.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
item_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
exception_reasonRequired | string | required tenant-enabled canonical reason value. |
exception_notesOptional | string | optional note, max 2000 characters. |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/${ITEM_ID}/exception" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "exception_reason": "manual_hold",6 "exception_notes": "Held for manual review"7}'Response examples
No saved response example. Use Try it to inspect a staging response.
Exceptions - List Unresolved Transfer Manifest Exceptions
/delivery/transfer-manifest-exceptionsLists manifest items currently in exception status.
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
manifest_idOptional | string | Optional manifest id Example: |
exception_reasonOptional | string | Optional reason filter |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-exceptions?page=1&limit=20&manifest_id=${MANIFEST_ID}&exception_reason=" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Exceptions - Resolve Exception As Reprocess
/delivery/transfer-manifest-exceptions/{{item_id}}/resolveResolves an exception by returning the item to received so destination/order creation can continue. When the resolved item is the last remaining exception, a manifest currently in received_with_exceptions automatically returns to received. If every manifest item is then order_created or void, the manifest automatically becomes completed.
Events
an exception_resolved event is recorded with payload.barcode_value, payload.resolution, and payload.notes; the manifest status correction records manifest_status_changed with payload.reason=all_exceptions_resolved.
Path parameters
| Parameter | Type | Description |
|---|---|---|
item_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
resolution | string | — |
notes | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-exceptions/${ITEM_ID}/resolve" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "resolution": "reprocess",6 "notes": "Corrected and ready for processing"7}'Response examples
No saved response example. Use Try it to inspect a staging response.
Exceptions - Resolve Exception As Void
/delivery/transfer-manifest-exceptions/{{item_id}}/resolveResolves an exception by voiding the item/barcode. If the voided item is the last remaining exception, a manifest currently in received_with_exceptions automatically returns to received when other non-terminal items remain. If every manifest item is order_created or void, the manifest automatically becomes completed.
Events
an exception_resolved event is recorded with payload.barcode_value, payload.resolution, and payload.notes; manifest status changes are recorded as manifest_status_changed.
Path parameters
| Parameter | Type | Description |
|---|---|---|
item_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
resolution | string | — |
notes | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-exceptions/${ITEM_ID}/resolve" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "resolution": "void",6 "notes": "Voided after review"7}'Response examples
No saved response example. Use Try it to inspect a staging response.
Events - Manifest Timeline
/delivery/transfer-manifests/{{manifest_id}}/eventsReturns append-only event history for a manifest. Expected happy-path events include manifest_created, item_scanned, manifest_picked_up, manifest_arrived, receiving_started, item_received, items_received, receiving_completed, order_created, manifest_status_changed, and manifest_completed. Each item_received and order_created event includes manifest_item_id, from_status, and to_status, preserving the item sequence before order creation. Other item-level events (item_destination_set, item_exception, exception_resolved, item_scanned, item_removed) include barcode_value in the payload. New item_scanned events include payload.entry_method as manual or camera; historical events without this field must be treated as camera. User-driven item_received and aggregate items_received events also include the submitted entry method, while automated count-only or bulk receipt events can omit it. Frontend integration: render Manual Entry only when an item_scanned event has payload.entry_method=manual; otherwise render Scanned. Exception events include reason and notes in the payload. The automatic status correction after the last exception is resolved uses manifest_status_changed with from_status=received_with_exceptions, to_status=received, and payload.reason=all_exceptions_resolved.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | string | Example: |
limit | string | Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/events?page=1&limit=50" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Cancel Manifest
/delivery/transfer-manifests/{{manifest_id}}/cancelCancels a manifest before receiving/order creation. Allowed only while status is draft, picked_up, in_transit, or awaiting_receipt. Once receiving has started (receiving, received, or received_with_exceptions), the API returns HTTP 409 manifest_cannot_be_cancelled. Non-order-created items become void and linked barcodes return to available.
The stored manifest notes use note when supplied, otherwise reason. Successful response: data contains { id, status: "cancelled", reason, note, notes }, where notes is the exact value stored on transfer_manifests.notes. Event: a manifest_cancelled event is recorded with payload.reason and payload.note.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
reasonRequired | string | Reason for cancellation; trimmed and limited to 2000 characters. |
noteOptional | string | Additional cancellation note, limited to 2000 characters. |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/cancel" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "reason": "Duplicate pickup manifest",6 "note": "Cancelled before receiving started"7}'Response examples
1{2 "success": true,3 "message": "updated_successfully",4 "data": {5 "id": "manifest-uuid",6 "status": "cancelled",7 "reason": "Duplicate pickup manifest",8 "note": "Cancelled before receiving started",9 "notes": "Cancelled before receiving started"10 }11}Dispatcher - Void Manifest Item (Remove from Manifest)
/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/voidVoids (removes) a manifest item with a required reason. Works on non-draft manifests for items not yet order_created or void. The item's barcode is freed back to available. An individual item_voided event is recorded on the manifest timeline.
Allowed item statuses
any except order_created and void.
Errors
item_not_found404order_already_created409item_already_processed409
Event
item_voided with payload.reason and payload.barcode_value.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
item_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
reason | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/items/${ITEM_ID}/void" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "reason": "Item damaged during processing"6}'Response examples
No saved response example. Use Try it to inspect a staging response.
Dispatcher - Complete Manifest (Mark as Completed)
/delivery/transfer-manifests/{{manifest_id}}/completeManually marks a manifest as completed. Automatic completion never occurs while any item remains in exception; resolve the exception by reprocessing or voiding it first. If exception items remain during this explicit manual action, each is voided individually with its own item_voided event entry (who, when, why) before the manifest transitions to completed. If all items are already terminal (order_created or void), the manifest completes directly.
Allowed manifest statuses
received_with_exceptions and processing.
Guard
Returns 409 if any non-terminal, non-exception items exist (e.g., received items that haven't been processed yet).
Event
manifest_completed with payload.voided_count and payload.reason. Each voided exception item gets an individual item_voided event.
Path parameters
| Parameter | Type | Description |
|---|---|---|
manifest_idRequired | string | Variable used inside the request path. |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
Content-Type | string | Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
reason | string | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifests/${MANIFEST_ID}/complete" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3 --header "Content-Type: application/json" \4 --data-raw '{5 "reason": "All items resolved or processed"6}'Response examples
No saved response example. Use Try it to inspect a staging response.