Skip to main content

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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-processing-points

Creates 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

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
namestring—
codestring—
address_idstring—
metadataobject—
metadata.sourcestring—
Staging
Request
curl
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

201Created
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/transfer-processing-points

Lists 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

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

is_activeOptionalstring

Optional: true | false

Example: true

branch_idOptionalstring

Optional branch ID used to identify and prioritize its default processing point

Example: {{source_branch_id}}

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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

200OK
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/transfer-processing-points/{{processing_point_id}}

Gets a processing point by id.

Path parameters

ParameterTypeDescription
processing_point_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
PATCH/delivery/transfer-processing-points/{{processing_point_id}}

Updates processing point fields. code must remain unique per tenant if changed.

Path parameters

ParameterTypeDescription
processing_point_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
namestring—
address_idstring—
metadataobject—
metadata.updated_fromstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-processing-points/{{processing_point_id}}/deactivate

Soft-deactivates a processing point. Fails if non-terminal manifests reference it.

Path parameters

ParameterTypeDescription
processing_point_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/institutions

Lists tenant users whose tenant_user_type is institution. Use a returned id as institution_user_id.

Query parameters

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

searchOptionalstring

Optional search by name, email, or phone

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/institutions/{{institution_user_id}}

Gets an institution tenant_user by id.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/institutions/{{institution_user_id}}/branches

Creates a branch under an institution. institution_user_id comes from the path, not the body. Branch code is unique per tenant/institution.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
namestring—
codestring—
address_idstring—
default_processing_point_idstring—
contact_infoobject—
contact_info.phonestring—
metadataobject—
metadata.sourcestring—
Staging
Request
curl
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

201Created
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/institutions/{{institution_user_id}}/branches

Lists branches for an institution. Optional filters: is_active, search.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

is_activestring

Example: true

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/institution-branches

Lists 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

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

is_activestring

Example: true

institution_user_idOptionalstring

Example: {{institution_user_id}}

searchOptionalstring

Example: main

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/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

ParameterTypeDescription
branch_codeRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
include_inactiveOptionalstring

Example: true

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}

Gets a branch owned by the institution.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

branch_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
PATCH/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}

Updates branch fields.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

branch_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
namestring—
default_processing_point_idstring—
metadataobject—
metadata.updated_fromstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}/deactivate

Soft-deactivates a branch. Fails when non-terminal manifests reference it.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

branch_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}/barcode-batches

Generates 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

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

branch_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
quantitynumber—
Staging
Request
curl
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

201Created
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/institutions/{{institution_user_id}}/barcode-batches

Lists barcode batches for an institution.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

statusOptionalstring

Optional: draft | generated | printed | voided

Example: generated

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/institutions/{{institution_user_id}}/branches/{{branch_id}}/barcodes

Lists individual barcodes for a branch. Pick an available barcode_value for manifest scanning.

Path parameters

ParameterTypeDescription
institution_user_idRequiredstring

Variable used inside the request path.

branch_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

statusOptionalstring

Optional barcode status filter

Example: available

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/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

ParameterTypeDescription
barcode_valueRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/barcode-batches/{{batch_id}}

Gets batch detail plus individual barcodes.

Path parameters

ParameterTypeDescription
batch_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/barcode-batches/{{batch_id}}/barcodes

Tenant-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

ParameterTypeDescription
batch_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 100

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/barcode-batches/{{batch_id}}/print

Generates 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

ParameterTypeDescription
batch_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
print_modestring—
barcode_idsarray<string>—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/institution-barcodes/{{barcode_id}}/void

Voids a single barcode only when status is available.

Path parameters

ParameterTypeDescription
barcode_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/barcode-batches/{{batch_id}}/void

Voids an entire batch only if all barcodes are unused (available or already void).

Path parameters

ParameterTypeDescription
batch_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests

Driver 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

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
institution_user_idstring—
source_branch_idstring—
processing_point_idstring—
driver_idstring—
notesstring—
Staging
Request
curl
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

201Created
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/items/scan

Scans 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
barcode_valuestring—
entry_methodstring—
Staging
Request
curl
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

201Created
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
DELETE/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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

item_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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

200OK
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/submit-pickup

Locks 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
photo_urlsarray<string>—
signature_urlstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/driver-action

Generic 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
actionstring—
photo_urlsarray<string>—
signature_urlstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/arrive-processing

Marks 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
photo_urlsarray<string>—
signature_urlstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
PATCH/delivery/transfer-manifests/{{manifest_id}}/status

Moves 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_urls and signature_url remain 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

  • cancelled is allowed from draft, picked_up, in_transit, or awaiting_receipt.

  • Cancellation uses the existing atomic cancellation operation: non-order-created items become void and their linked barcodes return to available.

  • Cancellation is rejected after receiving starts or when an order has already been created.

  • The dedicated POST /delivery/transfer-manifests/{id}/cancel endpoint 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_statuses contains picked_up, in_transit, awaiting_receipt, and cancelled.

  • HTTP 400 manifest_status_reason_required: reason is 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_cancelled or manifest_cannot_be_cancelled_orders_created: cancellation business rule failed.

Frontend integration contract

  • Always collect and send non-blank reason; send notes only when provided.

  • Render status actions from data.allowed_next_statuses, including the literal cancelled action.

  • After HTTP 200, use data.status as authoritative and do not update optimistically.

  • At awaiting_receipt, use the existing receiving/processing buttons for later work; cancelled remains available only if returned by the backend.

  • Display localized message and branch on stable code. No navigation action is returned.

Path parameters

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
statusRequiredstring

picked_up, in_transit, awaiting_receipt, or cancelled.

reasonRequiredstring

(required, max 2000 characters): a non-blank operator reason recorded on every executed status event.

notesOptionalstring

(optional, max 2000 characters): additional audit context recorded with the reason.

proofsobject—
proofs.pickupOptionalobject

optional photo_urls and signature_url; required values depend on tenant pickup-proof settings.

proofs.pickup.photo_urlsarray—
proofs.pickup.signature_urlnull—
proofs.deliveryOptionalobject

optional photo_urls and signature_url; required values depend on tenant delivery-proof settings.

proofs.delivery.photo_urlsarray—
proofs.delivery.signature_urlnull—
Staging
Request
curl
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

200OK
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/driver/transfer-manifests

Driver-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

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

searchstring

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

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/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

  • data contains 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, and proofRequirements.

  • data.cancel_reason is null for active manifests and contains payload.reason from the latest manifest_cancelled event when data.status is cancelled.

  • 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.branch is the source branch information object and mirrors data.source_branch for 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, and default_processing_point.

  • When proof has been captured, data.proof_of_pickup and/or data.proof_of_delivery are 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_reason to display cancellation reason on cancelled manifests.

  • Use data.branch or data.source_branch to render source branch name/code and branch address.

  • Continue using data.source_branch_id as the stable entity ID for follow-up API calls.

  • Read proofRequirements to 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/transfer-manifests

Dispatcher 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=asc sorts by processing-point name, with nulls last and id DESC as 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

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

statusOptionalstring

Optional manifest status

institution_user_idOptionalstring

Optional institution tenant_user id

source_branch_idOptionalstring

Optional source branch id

processing_point_idOptionalstring

Optional processing point id

date_fromOptionalstring

Optional created_at from

date_toOptionalstring

Optional created_at to

searchstring

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_valueOptionalstring

Optional case-insensitive partial G2G barcode filter. Returns manifests containing a matching item barcode.

column_filtersOptionalstring

Optional JSON-encoded column filters. Supported keys: manifest_number, status, institution_user_id, processing_point_id, expected_item_count, received_item_count, exception_item_count, order_created_count, picked_up_at, received_at, arrived_at, completed_at, created_at.

Example: {"status":"receiving","expected_item_count":{"min":1,"max":100},"created_at":{"from":"2026-08-01","to":"2026-08-31"}}

sort_byOptionalstring

Optional whitelisted sort column. institution_user_id sorts by institution user full_name; processing_point_id sorts by processing point name. Invalid values fall back to created_at DESC.

Example: created_at

sort_orderOptionalstring

Optional asc or desc. Defaults to desc when a valid sort_by is supplied.

Example: desc

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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

400Malformed column_filters JSON
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
GET/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

  • data contains the transfer manifest header and five database-maintained counts: expected_item_count, received_item_count, exception_item_count, order_created_count, and voided_item_count. Counts are recalculated after every item write, including empty manifests. received_item_count is historical custody evidence based on item received_at, so it does not fall back to zero after order creation.

  • Every received manifest includes received_at, received_by, and received_by_user. Legacy manifests that previously skipped receipt remain readable; the backend does not invent missing custody data.

  • data.cancel_reason is null for active manifests and contains payload.reason from the latest manifest_cancelled event when data.status is cancelled.

  • data.branch is the source branch information object and mirrors data.source_branch for 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, and default_processing_point.

  • data.source_address remains 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_user and Received Time from data.received_at.

  • Use data.cancel_reason to display cancellation reason on cancelled manifests.

  • Use data.branch or data.source_branch to render source branch name/code and branch address without an extra branch lookup.

  • Continue using data.source_branch_id as 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/transfer-manifests/{{manifest_id}}/items

Returns 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

  • status filters the primary manifest-item status. Use status=order_created to list items promoted to delivery orders.

  • delivery_status optionally 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_added filters 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
pagestring

Page number. Default: 1.

Example: 1

limitstring

Items per page. Default: 50; maximum: 200.

Example: 50

searchstring

Case-insensitive partial search against barcode_value using the submitted text, or the linked order's stored delivery_code after removing a leading DEL prefix when present. Example: DEL1911, DEL19, 1911, and 19 can match delivery_code 1911.

statusOptionalstring

Optional exact manifest-item status.

delivery_statusOptionalstring

Optional exact status of the linked delivery. Applied in the database before counting and pagination.

destination_addedOptionalstring

Optional boolean filter based on whether the manifest item has a stored destination_address JSON snapshot.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/receive/start

Begins 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/receive/items

Marks 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 receiving status.

  • Only manifest items in scanned, picked_up, or in_transit status can be newly received.

  • Item state, barcode state, received_at, one item-level item_received event per item, and the aggregate items_received event are written atomically in one database call. User-driven events persist the normalized value as payload.entry_method; automated count-only and bulk receipts do not fabricate an entry method.

  • Invalid entry_method returns HTTP 400 with code=invalid_entry_method and a localized message; no submitted item is changed.

  • data.received contains only barcodes newly received by this request. data.received_count always equals data.received.length; already-received barcodes never appear here, preventing count inflation.

  • data.already_processed contains submitted barcodes already in received or another non-receivable item status. These are completed items, not invalid barcodes, so they do not appear in data.invalid_barcodes.

  • data.not_in_manifest contains every submitted barcode absent from this transfer manifest.

  • data.not_found is the subset of not_in_manifest that is also absent from the tenant barcode registry.

  • data.invalid_barcodes gives the exact per-barcode reason, including invalid_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 both not_in_manifest and not_found.

  • A malformed barcode is classified without stopping the rest of the batch, and its response message uses the localized invalid_barcode translation.

  • Valid receivable barcodes are committed even when other submitted barcodes fail. A mixed result returns HTTP 200, success=true, localized message Partially completed, the newly received barcodes in received, 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 returns code=invalid_barcode.

Frontend integration contract

  • Send entry_method=manual only when the operator typed the submitted barcode values; otherwise send camera or 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.received to the newly received UI state and increment by exactly data.received_count.

  • Do not add data.already_processed again or show it under Invalid Barcodes; show it under Already Processed with the localized message This item has already been processed in English.

  • Show data.not_in_manifest, data.not_found, and data.invalid_barcodes[] as per-barcode failures. data.invalid_barcodes[] contains only actual validation failures.

  • On HTTP 200 with message=Partially completed, retain the failed barcodes for correction while applying the successful received entries.

  • On HTTP 409, no submitted barcode was newly received. No navigation change is required.

Path parameters

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
barcode_valuesarray<string>—
entry_methodstring—
Staging
Request
curl
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

200OK
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/receive/complete

Completes 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
notesstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
PATCH/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/destination

Assigns 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_v1 with 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_label assignment. 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 existing shipment_label path.

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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

item_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
destination_address_idstring—
delivery_service_idstring—
destination_branch_idstring—
Staging
Request
curl
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

400Bad Request
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/items/bulk-assign-destination

Assigns 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_required is 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_barcodes contains 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, or already_processed.

  • An unknown_barcode entry also includes localized message. In English it is This barcode is not in this manifest; the frontend must display message and keep reason only for branching.

  • data.not_in_manifest contains every submitted barcode absent from the path transfer manifest.

  • data.not_found is the subset of not_in_manifest also absent from the tenant barcode registry. Classification lists intentionally overlap; an unknown barcode appears in both lists and has an invalid_barcodes entry.

  • data.already_processed contains same-manifest barcodes that are no longer eligible or already have a linked delivery. The matching invalid_barcodes object includes item_status and delivery_id; these barcodes are never executed again.

  • data.validation_failed_count equals data.invalid_barcodes.length. failed_count continues to count only eligible items that reached order promotion and failed there.

  • Every data.created[] and promotion data.failed[] entry includes barcode_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, localized partial_success, successful orders in created, 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 returns code=invalid_barcode with the localized invalid_barcode message; an already-processed-only request uses the localized already-processed message; and a not-in-manifest-only request uses localized This barcode is not in this manifest in 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_ids remains supported for existing selection flows.

  • Add only data.created to the successfully added/executed UI state and use each entry's barcode_value to show that it was added. Never add data.already_processed again; show those barcodes as already processed.

  • Show data.invalid_barcodes[].message when present; never render data.invalid_barcodes[].reason as user-facing text. Continue using reason as the stable machine code.

  • Show data.not_in_manifest, data.not_found, and data.invalid_barcodes[] as per-barcode failures.

  • On HTTP 200 with the localized partial-success message, apply data.created and 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_v1 with 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_label assignment. 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 existing shipment_label path.

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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
barcode_valuesarray<string>—
destination_address_idstring—
delivery_service_idstring—
destination_branch_idstring—
Staging
Request
curl
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

400Bad Request
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/change-destination

Changes 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

item_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
destination_branch_idRequiredstring

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_idOptionalstring

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.

reasonstring

optional trimmed edit reason, maximum 500 characters; required when the tenant delivery-order setting requires edit reasons.

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/items/bulk-change-destination

Changes 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
item_idsarray<string>—
destination_branch_idstring—
delivery_service_idstring—
reasonstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/transfer-manifest-exception-reasons

Returns 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.reasons contains the tenant-enabled { value, label, description } options. Use reason.value as exception_reason.

Frontend integration contract

  • Populate Mark Exception dropdown options from data.reasons.

  • Submit only reason.value as exception_reason to 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

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/items/bulk-exception

Moves 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, or processing can 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 the item_exception event.

Per-barcode validation

  • data.invalid_barcodes contains 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, or already_processed.

  • data.not_in_manifest contains every submitted barcode absent from the path transfer manifest.

  • data.not_found is the subset of not_in_manifest also absent from the tenant barcode registry. Lists intentionally overlap where useful.

  • data.already_processed contains same-manifest barcodes that cannot be added again. data.skipped remains 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 localized item_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, localized partial_success, newly added barcodes in data.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 returns code=invalid_barcode.

  • A fully successful request returns HTTP 200, success=true, localized item_added_successfully.

  • data.flagged_count always equals data.flagged.length; data.validation_failed_count equals data.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-reasons for the reason dropdown.

  • Submit barcode strings in barcode_values and the selected reason value in exception_reason.

  • Add only data.flagged to exception state and show those barcodes as added.

  • Never add data.already_processed or data.skipped again.

  • Show data.invalid_barcodes, data.not_in_manifest, and data.not_found as per-barcode failures.

  • On partial HTTP 200, apply data.flagged and 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
barcode_valuesRequiredarray<string>

required non-empty array of barcode strings. Values are trimmed, normalized to uppercase, and deduplicated.

exception_reasonRequiredstring

required tenant-enabled canonical reason value.

exception_notesOptionalstring

optional note, max 2000 characters.

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/exception

Moves 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, or processing can be flagged.

  • An item already in exception or void returns HTTP 409 with the localized item_already_processed message. An item in order_created returns HTTP 409 with order_already_created.

  • The database update repeats the eligible-status condition. If another request processes the item first, this request returns HTTP 409 and does not update the barcode or record a duplicate event.

Successful response

  • HTTP 200 with { success: true, message: <localized item_added_successfully> }; English is Item added successfully.

  • The stored transfer_manifest_items.exception_reason is 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-reasons to populate the reason dropdown.

  • Submit selected reason value as exception_reason.

  • Show the returned localized Item added successfully message after HTTP 200.

  • 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

item_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
exception_reasonRequiredstring

required tenant-enabled canonical reason value.

exception_notesOptionalstring

optional note, max 2000 characters.

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/transfer-manifest-exceptions

Lists manifest items currently in exception status.

Query parameters

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 20

manifest_idOptionalstring

Optional manifest id

Example: {{manifest_id}}

exception_reasonOptionalstring

Optional reason filter

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifest-exceptions/{{item_id}}/resolve

Resolves 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

ParameterTypeDescription
item_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
resolutionstring—
notesstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifest-exceptions/{{item_id}}/resolve

Resolves 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

ParameterTypeDescription
item_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
resolutionstring—
notesstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
GET/delivery/transfer-manifests/{{manifest_id}}/events

Returns 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Query parameters

ParameterTypeDescription
pagestring

Example: 1

limitstring

Example: 50

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/cancel

Cancels 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
reasonRequiredstring

Reason for cancellation; trimmed and limited to 2000 characters.

noteOptionalstring

Additional cancellation note, limited to 2000 characters.

Staging
Request
curl
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

200OK
Response body
json
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/items/{{item_id}}/void

Voids (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_found 404

  • order_already_created 409

  • item_already_processed 409

Event

item_voided with payload.reason and payload.barcode_value.

Path parameters

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

item_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
reasonstring—
Staging
Request
curl
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 & Last-Mile / Institution Transfer Manifest V1
POST/delivery/transfer-manifests/{{manifest_id}}/complete

Manually 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

ParameterTypeDescription
manifest_idRequiredstring

Variable used inside the request path.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
reasonstring—
Staging
Request
curl
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.