Skip to main content

G2G Transfer Manifest Items — Bulk Scan

6 API calls in this section.

Dispatcher-panel bulk workflow for processing G2G manifest items at the processing point.

Typical flow

  1. GET /search — autocomplete as the dispatcher scans / types barcodes.

  2. POST /bulk/validate — pre-flight check for a batch of identifiers (UUIDs or barcode strings).

  3. POST /bulk/set-destination — in one frontend action, start receiving when needed, receive the selected items, complete receiving when every manifest item is accounted for, then set destination and create delivery orders.

  4. POST /bulk/resolve-exceptions — resolve selected exception queue items, or all exception items under one manifest, as reprocess or void.

Driver arrival is never skipped. A manifest still in draft, picked_up, or in_transit is rejected with its manifest number and current status, leaving the driver arrival/photo/signature step available. awaiting_receipt starts receiving inside the same call; receiving continues receiving; received, received_with_exceptions, and processing are receipt-safe retry states.

Barcode strings passed to /bulk/validate must be valid 14-character G2G postal barcodes with a matching MOD 11 check digit. A malformed or checksum-invalid input returns a localized per-item invalid_barcode result without a database barcode lookup.

All endpoints are tenant-scoped via the Authorization bearer token. Search exposes unpromoted picked_up, in_transit, and received items. Validation inspects found items regardless of lifecycle status so rejected rows can name their manifest and current state.

Feature gate

these endpoints require tenant setting transfer_manifest.enabled to be true. When disabled, no validation, search, update, exception resolution, or order creation runs; the API returns HTTP 403 with { "success": false, "code": "transfer_manifest_disabled", "message": "Transfer manifest is disabled for this tenant" }.

Frontend contract

keep one action/button and call bulk/set-destination once. Do not add a separate receiving action. Handle the stable error codes and display their localized messages.

Search Manifest Items​

Delivery & Last-Mile / G2G Transfer Manifest Items — Bulk Scan
GET/delivery/transfer-manifest-items/search

Tenant-wide manifest item search for autocomplete / barcode scanner input.

Returns only unpromoted post-pickup items with status picked_up, in_transit, or received and no existing delivery_id. Excludes scanned, processing, order_created, and void items. Returns enriched rows including manifest context (manifest_number, manifest_status), institution user, and source branch.

Query parameters

ParameterTypeDescription
qstring

Search term. If a valid UUID, performs an exact id match. Otherwise, performs a case-insensitive partial match on barcode_value. Leave empty to list recent items.

Example: BC-001

limitstring

Max results to return. Range 1–100. Default 20.

Example: 20

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-items/search?q=BC-001&limit=20" \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      "manifest_item_id": "item-uuid",7      "barcode_value": "BC-001",8      "status": "received",9      "manifest_id": "manifest-uuid",10      "manifest_number": "MF-2026-0042",11      "manifest_status": "received",12      "institution": {13        "id": "user-uuid",14        "full_name": "City Hospital",15        "phone": "+9647001234567"16      },17      "source_branch": {18        "id": "branch-uuid",19        "name": "Main Branch",20        "code": "MB-01"21      },22      "destination_branch_id": null,23      "destination_address_id": null,24      "delivery_id": null,25      "already_has_order": false26    }27  ]28}

Bulk Validate — using object identifiers​

Delivery & Last-Mile / G2G Transfer Manifest Items — Bulk Scan
POST/delivery/transfer-manifest-items/bulk/validate

Same as the plain-string variant but uses the { type, value } object shape. The type field is ignored server-side; routing is determined by the value format.

A found item is valid when it can safely enter the one-call flow

awaiting_receipt or receiving with recorded driver arrival and required delivery proof, or receipt-safe retry status received, received_with_exceptions, or processing with complete receipt fields and an item still in received. Pre-arrival, terminal, inconsistent, or already-promoted rows return valid: false with a stable error_key, localized error_message, manifest number, manifest status, and current item status. The overall batch remains HTTP 200 so valid and invalid identifiers can be returned together.

Frontend integration contract

use each result's valid boolean. Display error_message; use error_key only for branching. Keep one Execute action.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
identifiersarray<object>—
identifiers.typestring—
identifiers.valuestring—
Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-items/bulk/validate" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3  --header "Content-Type: application/json" \4  --data-raw '{5  "identifiers": [6    {7      "type": "barcode",8      "value": "GE000010000017"9    },10    {11      "type": "id",12      "value": "item-uuid-003"13    }14  ]15}'

Response examples

200OK
Response body
json
1{2  "success": true,3  "message": "Manifest item validation completed",4  "data": {5    "results": [6      {7        "input": "GE000090000020",8        "valid": false,9        "error_key": "manifest_bulk_order_creation_not_allowed",10        "error_message": "Manifest TM-MREX5VCN-ZQD2 is picked_up. Bulk order creation is not allowed in this status.",11        "manifest_item_id": "item-uuid",12        "barcode_value": "GE000090000020",13        "manifest_id": "manifest-uuid",14        "manifest_number": "TM-MREX5VCN-ZQD2",15        "manifest_status": "picked_up",16        "current_status": "picked_up",17        "allowed_manifest_statuses": [18          "awaiting_receipt",19          "receiving",20          "received",21          "received_with_exceptions",22          "processing"23        ]24      }25    ],26    "total_valid": 0,27    "total_failed": 128  }29}

Bulk Set Destination & Create Orders​

Delivery & Last-Mile / G2G Transfer Manifest Items — Bulk Scan
POST/delivery/transfer-manifest-items/bulk/set-destination

Tenant-wide one-call receiving and order-creation endpoint. It accepts manifest item IDs from any manifest under the tenant and creates delivery orders with institution wallet payment and payer_type=sender. COD is not used.

  • One of destination_branch_id or destination_address_id.

State behavior

  • draft, picked_up, in_transit, completed, and cancelled are rejected before any receipt/order write. The localized message names the manifest and current status.

  • awaiting_receipt: verifies arrived_at and required delivery photo/signature, records receiving_started, and fills received_by.

  • receiving: does not start receiving again; it requires the existing receiver record.

  • Selected picked_up/in_transit items are atomically changed to received, receive received_at, update their barcode, and get item-level item_received events.

  • If any manifest item remains unaccounted for, that manifest stays receiving; its selected items remain received but no order is created yet. The response uses manifest_receiving_incomplete.

  • When every item is accounted for, receiving is completed first (received_at, received_by, durable received count, receiving_completed), then orders are created.

  • received, received_with_exceptions, and processing allow retry only for items still in received with complete receipt fields.

  • Every promotion is protected again in the shared service and database, so picked_up → order_created is impossible.

Ordering contract

receipt.received_item_ids, receipt.ready_item_ids, per-manifest item_ids, created, and failed follow the first-seen item_ids order, independent of database row order or parallel completion timing. Before bounded parallel creation starts, the backend atomically reserves parent delivery codes in that same order. Invalid or ineligible items are skipped without changing the relative order of the remaining items. Passing the returned created delivery codes to Generate Shipment Labels in response order therefore produces page 1 for the first successfully scanned item, page 2 for the next, and so on. Retries reuse an existing delivery or its durable reservation.

Existing promotion contract preserved

every created order stores the immutable source snapshot with snapshot_version=manifest_origin_v1. The parent delivery stores the manifest and item IDs; A/B legs store the manifest ID and the same snapshot, but not the item ID. Canonical manifest orders use the dedicated manifest_shipment_label assignment; normal deliveries keep the existing shipment_label path. When package measurements and an explicit unit size are both absent, the shared resolver uses the configured missing_unit_size_fallback.

Processing and performance

receipt is one tenant-scoped database RPC with deterministic row locks and batch writes. Receipt-safe items/manifests are then loaded with focused batch queries. One short reservation RPC allocates the full contiguous code block before creation. Up to 20 ready items use the existing bounded creation path directly. A larger request is split into ordered parts of at most 20 and sent through at most two fresh Edge invocations at once; each part limits delivery creation concurrency to two, keeping total database concurrency equivalent to the previous path while resetting the 2-second CPU budget per part. Retryable 502/503/504/546 part failures are retried up to three times. If a child committed but its response was lost, the coordinator reconciles only items durably finalized as order_created. The public request and response shapes do not change. There is no per-item reservation or receipt/event query. Existing origin snapshot, label, pricing-origin, delivery-policy, warehouse-staging, and missing-unit fallback behavior remains unchanged.

Response shape

{ created_count, failed_count, created, failed, receipt }. receipt contains requested_count, received_count, received_item_ids, ready_item_ids, and per-manifest status/results.

Frontend integration contract

keep the existing request and one Execute action. Preserve the returned created order when passing delivery codes to Generate Shipment Labels. Do not call Start Receiving or Receive Items separately from this screen. Display localized message/failed[].error_message; branch on stable codes such as invalid_uuid, manifest_bulk_order_creation_not_allowed, manifest_arrival_required, manifest_delivery_proof_required, manifest_bulk_receipt_incomplete, and manifest_receiving_incomplete. On an incomplete manifest, keep the user in the workflow because selected items were received but orders were intentionally not created.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
item_idsRequiredarray<string>

required array of manifest item UUID strings. At least 1. Duplicates are deduplicated; the first occurrence defines the item's execution position.

destination_address_idstring—
delivery_service_idOptionalstring

optional when G2G settings has default_delivery_service_id; otherwise required.

destination_branch_idstring—
Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-items/bulk/set-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_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

200OK
Response body
json
1{2  "success": true,3  "message": "Orders created successfully",4  "data": {5    "created_count": 2,6    "failed_count": 0,7    "created": [8      {9        "item_id": "item-uuid-1",10        "delivery": {11          "id": "delivery-uuid",12          "delivery_code": "2501",13          "status": "pending"14        }15      },16      {17        "item_id": "item-uuid-2",18        "delivery": {19          "id": "delivery-uuid-2",20          "delivery_code": "2502",21          "status": "pending"22        }23      }24    ],25    "failed": [],26    "receipt": {27      "requested_count": 2,28      "received_count": 2,29      "received_item_ids": [30        "item-uuid-1",31        "item-uuid-2"32      ],33      "ready_item_ids": [34        "item-uuid-1",35        "item-uuid-2"36      ],37      "manifests": [38        {39          "manifest_id": "manifest-uuid",40          "manifest_number": "TM-001",41          "status": "received",42          "remaining_count": 0,43          "ready": true44        }45      ]46    }47  }48}

Bulk Set Destination — with address ID directly​

Delivery & Last-Mile / G2G Transfer Manifest Items — Bulk Scan
POST/delivery/transfer-manifest-items/bulk/set-destination

Same one-call receipt-safe endpoint, passing destination_address_id directly instead of destination_branch_id. delivery_service_id can be omitted when the G2G default is configured. Driver arrival remains mandatory; the backend starts/continues receiving, records item-level receipt, completes a fully accounted manifest, and only then creates orders. Receipt-safe retries from received, received_with_exceptions, or processing do not duplicate receiving events. First-seen item_ids order controls execution results and atomically reserved delivery codes even though order creation remains parallel; invalid or ineligible items are skipped without reordering the survivors. Existing institution-wallet, manifest-origin snapshot, label, pricing-origin, delivery-policy, warehouse-staging, and missing-unit fallback behavior remains unchanged. The immutable source snapshot uses snapshot_version=manifest_origin_v1; A/B legs store the manifest ID and the same snapshot, but not the item ID. Canonical manifest orders use the dedicated manifest_shipment_label assignment, while normal deliveries keep the existing shipment_label path. The shared resolver uses the configured missing_unit_size_fallback when package measurements and an explicit unit size are absent.

Frontend integration contract

keep the same request and one Execute action, preserve the returned created order when requesting labels, and use the localized receipt/order errors described on the primary example.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
item_idsarray<string>—
destination_address_idstring—
Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-items/bulk/set-destination" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3  --header "Content-Type: application/json" \4  --data-raw '{5  "item_ids": [6    "item-uuid-1",7    "item-uuid-2"8  ],9  "destination_address_id": "address-uuid"10}'

Response examples

No saved response example. Use Try it to inspect a staging response.

Bulk Resolve Exceptions​

Delivery & Last-Mile / G2G Transfer Manifest Items — Bulk Scan
POST/delivery/transfer-manifest-items/bulk/resolve-exceptions

Bulk resolution endpoint for dispatcher exception queues. The user can resolve selected exception item IDs from GET /delivery/transfer-manifest-exceptions, or resolve all exception items under one manifest.

Selected items body

  • item_ids — array of transfer manifest item UUIDs.

  • resolution — optional, reprocess or void. Defaults to reprocess.

  • notes — optional note stored on the resolved items.

All exceptions under manifest body

  • manifest_id — transfer manifest UUID.

  • all_exceptions — must be true to explicitly resolve every current exception under the manifest.

  • resolution — optional, reprocess or void. Defaults to reprocess.

  • notes — optional note stored on the resolved items.

Behavior

  • Only items currently in exception status are resolved.

  • reprocess moves item and barcode back to received, clears exception_reason, and makes the item eligible for bulk destination/order creation.

  • void moves item and barcode to void, terminally excluding it from order creation.

  • When the last exception under a manifest is resolved, a manifest in received_with_exceptions returns to received if non-terminal items remain. If every item is order_created or void, the manifest becomes completed.

  • Non-exception selected items are returned in skipped; missing selected IDs are returned in not_found.

Events

an exception_resolved event is recorded per resolved item with payload.barcode_value, payload.resolution, and payload.notes; automatic manifest correction is recorded as manifest_status_changed.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
item_idsarray<string>—
resolutionstring—
notesstring—
Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-items/bulk/resolve-exceptions" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3  --header "Content-Type: application/json" \4  --data-raw '{5  "item_ids": [6    "{{exception_item_id}}"7  ],8  "resolution": "reprocess",9  "notes": "Resolved from dispatcher exception queue"10}'

Replace {{placeholders}} with your own values before sending.

Response examples

200OK
Response body
json
1{2  "success": true,3  "message": "Updated successfully",4  "data": {5    "resolved_count": 2,6    "resolved": [7      {8        "item_id": "item-uuid-1",9        "from_status": "exception",10        "to_status": "received"11      },12      {13        "item_id": "item-uuid-2",14        "from_status": "exception",15        "to_status": "received"16      }17    ],18    "skipped": [],19    "not_found": []20  }21}

Bulk Resolve All Exceptions Under Manifest​

Delivery & Last-Mile / G2G Transfer Manifest Items — Bulk Scan
POST/delivery/transfer-manifest-items/bulk/resolve-exceptions

Resolves every current exception item under one transfer manifest. Requires all_exceptions: true so the client cannot accidentally resolve a whole manifest when it meant to send selected item IDs. When this resolves the last exception, a manifest in received_with_exceptions returns to received if non-terminal items remain, or becomes completed when every item is order_created or void.

Events

an exception_resolved event is recorded per resolved item with payload.barcode_value, payload.resolution, and payload.notes; automatic manifest correction is recorded as manifest_status_changed.

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
manifest_idstring—
all_exceptionsboolean—
resolutionstring—
notesstring—
Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/transfer-manifest-items/bulk/resolve-exceptions" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3  --header "Content-Type: application/json" \4  --data-raw '{5  "manifest_id": "{{manifest_id}}",6  "all_exceptions": true,7  "resolution": "void",8  "notes": "Void all unresolved exceptions under this manifest"9}'

Replace {{placeholders}} with your own values before sending.

Response examples

No saved response example. Use Try it to inspect a staging response.