Skip to main content

COD Collections

8 API calls in this section.

List COD Collections​

Delivery & Last-Mile / COD Collections
GET/delivery/cod-collections

List physical cash collections with pagination, search, sorting, and column filters.

Drivers always see only their own collections; any supplied driver_id is ignored for driver callers. Dispatcher and tenant_admin roles see all tenant collections and may filter by driver_id. Authorization for this scope is role-only and does not use permissions. Other roles receive HTTP 403.

amount is the total cash held by the driver. allocations.cod / cod_amount is the goods/COD portion and allocations.delivery_fee / delivery_fee_amount is the delivery-fee portion. collection_stage is pickup or dropoff for new records.

Cash record rules

  • Sender pays delivery fee in cash: create a pickup record with {cod: 0, delivery_fee}.

  • Receiver pays COD while sender paid the fee: create a separate dropoff record with {cod, delivery_fee: 0}.

  • Receiver pays both COD and delivery fee in cash: create one dropoff record with {cod, delivery_fee}.

Frontend integration contract

Display amount as the amount held/remitted. Display cod_amount and delivery_fee_amount as first-class numeric columns and keep allocations for the original breakdown object. Use collection_stage and allocations for the collection point and breakdown. Status values remain collected, remitted, and settled_by_wallet.

Search example

?search=chirag matches rows where driver name, customer name, email, or address contains 'chirag'

Sort example

?sort_by=amount&sort_order=desc

Column Filters (column_filters as JSON)

Per-column filter object. Takes priority over direct query params for the same field when direct params are absent.

KeyTypeBehaviour
customer_namestringILIKE match
driver_namestringILIKE match
delivery_addressstringILIKE match
external_reference_idstringILIKE match
statusstringExact match (collected | remitted | settled_by_wallet)
delivery_codenumber or {min,max}Exact or range
amountnumber or {min,max}Exact cash amount or range
cod_amountnumber or {min,max}Exact COD allocation or range
delivery_fee_amountnumber or {min,max}Exact delivery-fee allocation or range
collected_at{from,to}Date range (day boundaries)
remitted_at{from,to}Date range (day boundaries)
settled_at{from,to}Date range (day boundaries)

Example

?column_filters={"customer_name":"john","cod_amount":{"min":50},"delivery_fee_amount":{"max":20},"collected_at":{"from":"2024-01-01","to":"2024-01-31"}}

Summary fields

  • total_collected — sum of collected status amounts

  • total_remitted — sum of remitted status amounts

  • total_settled_by_wallet — sum of settled_by_wallet status amounts

  • total_pending — same as total_collected (unremitted)

  • total_cod_collections — total count (ignores status filter)

Each row also returns settlement_payment_id (UUID or null). Rows settled after receipt support point to one saved batch; use this ID to reopen the receipt endpoint. Historical settled rows remain null until first print. Show Print Receipt for remitted/settled_by_wallet rows; POST /delivery/cod-collections/:id/receipt creates a receipt for that collection on demand. Do not infer historical batches from dates.

Query parameters

ParameterTypeDescription
pagestring

Page number (default: 1)

Example: 1

limitstring

Items per page (default: 20, max: 100)

Example: 20

searchstring

Case-insensitive partial match across delivery code, customer name, driver name, driver email, delivery address

sort_bystring

Sort column: delivery_code | amount | status | collected_at | remitted_at | settled_at | customer_name | driver_name (default: collected_at)

Example: collected_at

sort_orderstring

Sort direction: asc | desc (default: desc)

Example: desc

statusstring

Filter by status: collected | remitted | settled_by_wallet

driver_idstring

Filter by driver ID (Dispatcher and tenant_admin roles only; ignored for driver callers)

delivery_idstring

Filter by delivery ID

delivery_codestring

Filter by exact delivery code

amount_minstring

Filter amount >= value

amount_maxstring

Filter amount <= value

cod_amount_minstring

Filter allocations.cod >= value

cod_amount_maxstring

Filter allocations.cod <= value

delivery_fee_amount_minstring

Filter allocations.delivery_fee >= value

delivery_fee_amount_maxstring

Filter allocations.delivery_fee <= value

collected_at_fromstring

Filter collected_at >= date (ISO, normalized to day start). Alias: from_date

collected_at_tostring

Filter collected_at <= date (ISO, normalized to day end). Alias: to_date

remitted_at_fromstring

Filter remitted_at >= date (ISO)

remitted_at_tostring

Filter remitted_at <= date (ISO)

settled_at_fromstring

Filter settled_at >= date (ISO)

settled_at_tostring

Filter settled_at <= date (ISO)

column_filtersstring

JSON object for per-column filtering. Supported keys: customer_name (ilike), driver_name (ilike), delivery_address (ilike), external_reference_id (ilike), status (exact string), delivery_code (number or {min,max}), amount (number or {min,max}), cod_amount (number or {min,max}), delivery_fee_amount (number or {min,max}), collected_at ({from,to} date range), remitted_at ({from,to} date range), settled_at ({from,to} date range). Example: {"customer_name":"john","cod_amount":{"min":50},"delivery_fee_amount":{"max":20},"collected_at":{"from":"2024-01-01","to":"2024-01-31"}}

tenant_idOptionalstring

Tenant ID (optional if in auth token)

languagestring

Response language

Example: en

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/cod-collections?page=1&limit=20&search=&sort_by=collected_at&sort_order=desc&status=&driver_id=&delivery_id=&delivery_code=&amount_min=&amount_max=&cod_amount_min=&cod_amount_max=&delivery_fee_amount_min=&delivery_fee_amount_max=&collected_at_from=&collected_at_to=&remitted_at_from=&remitted_at_to=&settled_at_from=&settled_at_to=&column_filters=&tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"

Response examples

200OK
Response body
json
1{2  "success": true,3  "message": "COD collections retrieved successfully",4  "cod": {5    "collections": [6      {7        "id": "uuid",8        "delivery_id": "uuid",9        "driver_id": "uuid",10        "amount": 60,11        "allocations": {12          "cod": 50,13          "delivery_fee": 1014        },15        "cod_amount": 50,16        "delivery_fee_amount": 10,17        "status": "collected",18        "collected_at": "2023-01-01T10:00:00Z",19        "remitted_at": null,20        "settled_at": null,21        "delivery_code": 1001,22        "delivery_details": {23          "delivery_number": "DEL-001",24          "customer_name": "John Doe",25          "delivery_address": "456 Oak Ave, City"26        },27        "driver_info": {28          "full_name": "Driver Name",29          "email": "driver@email.com",30          "avatar": "https://avatar.url"31        },32        "settlement_payment_id": null33      }34    ],35    "pagination": {36      "page": 1,37      "limit": 20,38      "total": 1539    },40    "summary": {41      "total_collected": 500,42      "total_remitted": 300,43      "total_pending": 200,44      "total_cod_collections": 2545    }46  }47}

Get COD Summary​

Delivery & Last-Mile / COD Collections
GET/delivery/cod-summary

Get driver's COD summary for wallet dashboard display. Shows unremitted amounts and pending collection counts.

  • Drivers always see only their own summary; any supplied driver_id is ignored for driver callers

  • Dispatcher and tenant_admin roles can fetch a specific driver's summary only when that driver belongs to their tenant

  • Other roles receive HTTP 403

Query parameters

ParameterTypeDescription
driver_idOptionalstring

Same-tenant driver ID to fetch summary for (Dispatcher and tenant_admin roles only; ignored for driver callers)

tenant_idOptionalstring

Tenant ID (optional if in auth token) Tenant ID (defaults to authenticated user's tenant)

languageOptionalstring

Preferred language for response messages

Example: en

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/cod-summary?driver_id=&tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"

Response examples

200OK
Response body
json
1{2  "success": true,3  "summary": {4    "total_unremitted": 200,5    "pending_collections_count": 5,6    "oldest_unremitted_date": "2023-01-01T10:00:00Z"7  }8}

Bulk Remit COD Collections​

Delivery & Last-Mile / COD Collections
POST/delivery/cod-collections/remit

Mark physical cash collections as remitted after a dispatcher receives cash from the driver.

Atomic business rules

  • COD deliveries credit the delivery customer/merchant wallet at delivery completion and mark the COD_COLLECTION payment SUCCESS immediately.

  • Cash remittance only marks each collection remitted and records who received the driver cash. It does not credit the customer/merchant wallet.

  • The delivery-fee allocation is not moved to a wallet in cash-remittance mode.

  • If any wallet/payment/collection update fails, the whole remittance fails.

Frontend integration contract

For selected rows, submit only scope=selected and cod_collection_ids; do not send driver_id. For remit-all, submit scope=all and driver_id when the actor is dispatcher/admin. Show total_cash_remitted, total_cod_remitted, and total_delivery_fee_remitted separately. Handle HTTP 400 when a selection is mixed-driver, invalid, no longer pending, or missing the required driver for remit-all.

Persistent settlement receipt

The settlement and one DELIVERY / COD_SETTLEMENT payment are saved atomically. The payment snapshots the driver, actor/receiver, timestamp, reference, exact settled collections, per-order COD/delivery-fee breakdown, and totals. The PDF is generated asynchronously; PDF failure never repeats or reverses settlement. A successful response adds settlement_payment_id, receipt_status (pending, in_process, success, or failure), and currency. The returned date is the persisted settlement date. Cash currency uses the tenant currency setting; wallet currency is the actual driver wallet currency.

Send one stable Idempotency-Key (up to 200 characters) per submission and reuse it for network retries. Its receipt identity is durable. Replaying the same request returns the original batch even for scope=all; reusing the same key with changed input returns HTTP 409 and code settlement_idempotency_conflict. A new intended settlement requires a new key.

Receipt integration

Open GET /delivery/cod-settlements/:settlement_payment_id/receipt. HTTP 202 means pending/in_process; poll briefly or reopen later. HTTP 200 supplies a fresh signed url. HTTP 409 with settlement_receipt_failed means settlement succeeded but PDF failed; retry only POST /delivery/cod-settlements/:settlement_payment_id/receipt, never resubmit settlement to print. For history rows with settlement_payment_id=null, first print uses POST /delivery/cod-collections/:id/receipt to save a receipt for that collection only.

Query parameters

ParameterTypeDescription
tenant_idOptionalstring

Tenant ID (optional if in auth token)

languagestring

Preferred language for response messages

Example: en

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
scopestring

selected or all.

cod_collection_idsarray<string>

required when scope=selected. The backend derives the driver from these rows and rejects mixed-driver selections.

remitted_to_user_idOptionalstring

optional receiver/dispatcher user ID; defaults to the current user.

notesstring—
referencestring—
driver_idstring

required only for dispatcher/admin scope=all. Driver users settle their own rows from auth context.

Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/cod-collections/remit?tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3  --header "Content-Type: application/json" \4  --data-raw '{5  "scope": "selected",6  "cod_collection_ids": [7    "uuid1",8    "uuid2",9    "uuid3"10  ],11  "remitted_to_user_id": "dispatcher-uuid",12  "notes": "Weekly remittance batch",13  "reference": "REM-REF-001"14}'

Response examples

200OK
Response body
json
1{2  "success": true,3  "data": {4    "scope": "selected",5    "remitted_collections": [6      {7        "cod_collection_id": "uuid1",8        "amount": 60,9        "allocations": {10          "cod": 50,11          "delivery_fee": 1012        },13        "delivery_code": 1001,14        "delivery_number": "DEL-001"15      }16    ],17    "total_remitted": 60,18    "total_cash_remitted": 60,19    "total_cod_remitted": 50,20    "total_delivery_fee_remitted": 10,21    "remitted_count": 1,22    "failed_count": 0,23    "remitted_at": "2023-01-01T12:00:00Z",24    "settlement_payment_id": "91000000-0000-4000-8000-000000000001",25    "receipt_status": "pending",26    "currency": "IQD"27  }28}

Settle COD by Wallet​

Delivery & Last-Mile / COD Collections
POST/delivery/cod-collections/settle-by-wallet

Settle cash collections using the driver's wallet.

Atomic business rules

  • Debit the driver wallet by total collection amount.

  • COD deliveries already credit customer/merchant wallets at delivery completion. Settlement does not credit the customer/merchant wallet.

  • Credit the tenant wallet with allocations.delivery_fee.

  • Mark collections settled_by_wallet.

Frontend integration contract

For selected rows, submit only scope=selected and cod_collection_ids; do not send driver_id. For settle-all, submit scope=all and driver_id when the actor is dispatcher/admin. Show total_cash_settled, total_cod_settled, and total_delivery_fee_settled separately. Handle HTTP 400 for insufficient balance, mixed-driver selections, invalid collections, missing driver for settle-all, or amount mismatch.

Persistent settlement receipt

The settlement and one DELIVERY / COD_SETTLEMENT payment are saved atomically. The payment snapshots the driver, actor/receiver, timestamp, reference, exact settled collections, per-order COD/delivery-fee breakdown, and totals. The PDF is generated asynchronously; PDF failure never repeats or reverses settlement. A successful response adds settlement_payment_id, receipt_status (pending, in_process, success, or failure), and currency. The returned date is the persisted settlement date. Cash currency uses the tenant currency setting; wallet currency is the actual driver wallet currency.

Send one stable Idempotency-Key (up to 200 characters) per submission and reuse it for network retries. Its receipt identity is durable. Replaying the same request returns the original batch even for scope=all; reusing the same key with changed input returns HTTP 409 and code settlement_idempotency_conflict. A new intended settlement requires a new key.

Receipt integration

Open GET /delivery/cod-settlements/:settlement_payment_id/receipt. HTTP 202 means pending/in_process; poll briefly or reopen later. HTTP 200 supplies a fresh signed url. HTTP 409 with settlement_receipt_failed means settlement succeeded but PDF failed; retry only POST /delivery/cod-settlements/:settlement_payment_id/receipt, never resubmit settlement to print. For history rows with settlement_payment_id=null, first print uses POST /delivery/cod-collections/:id/receipt to save a receipt for that collection only.

Query parameters

ParameterTypeDescription
tenant_idOptionalstring

Tenant ID (optional if in auth token)

languagestring

Preferred language for response messages

Example: en

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Content-Typestring

Example: application/json

Body parameters

ParameterTypeDescription
scopestring

selected or all.

notesstring—
referencestring—
driver_idstring

required only for dispatcher/admin scope=all. Driver users settle their own rows from auth context.

cod_collection_idsstring

required when scope=selected. The backend derives the driver from these rows and rejects mixed-driver selections.

settlement_amountOptionalstring

optional guard amount; when supplied it must match the selected/all cash total.

Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/cod-collections/settle-by-wallet?tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3  --header "Content-Type: application/json" \4  --data-raw '{5  "scope": "all",6  "notes": "Settled all collected CODs using wallet balance",7  "reference": "INV-2024-001",8  "driver_id": "driver-uuid"9}'

Response examples

200OK
Response body
json
1{2  "success": true,3  "message": "COD collections settled successfully",4  "settlement": {5    "scope": "all",6    "settled_collections": [7      {8        "cod_collection_id": "uuid1",9        "amount": 60,10        "allocations": {11          "cod": 50,12          "delivery_fee": 1013        },14        "delivery_code": 1001,15        "delivery_number": "DEL-001"16      }17    ],18    "total_settled": 60,19    "total_cash_settled": 60,20    "total_cod_settled": 50,21    "total_delivery_fee_settled": 10,22    "settled_at": "2023-01-01T12:00:00Z",23    "settlement_payment_id": "91000000-0000-4000-8000-000000000001",24    "receipt_status": "pending",25    "currency": "USD"26  }27}

Remit Single COD Collection​

Delivery & Last-Mile / COD Collections
POST/delivery/cod-collections/:codId/remit

Remit a single COD collection. Requires admin permissions.

  • Requires manage:operations:tenant permission or system admin

Path parameters

ParameterTypeDescription
codIdRequiredstring

ID of the COD collection to remit

Example: uuid

Query parameters

ParameterTypeDescription
tenant_idOptionalstring

Tenant ID (optional if in auth token) Tenant ID (defaults to authenticated user's tenant)

languageOptionalstring

Preferred language for response messages

Example: en

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/cod-collections/${CODID}/remit?tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}" \3  --header "Content-Type: application/json" \4  --data-raw '{}'

Response examples

200OK
Response body
json
1{2  "success": true,3  "message": "COD collection remitted successfully",4  "data": {5    "id": "uuid",6    "delivery_id": "uuid",7    "driver_id": "uuid",8    "amount": "50.00",9    "delivery_code": 1001,10    "collected_at": "2023-01-01T10:00:00Z",11    "remitted_at": "2023-01-01T12:00:00Z",12    "status": "remitted"13  }14}

Get COD Settlement Receipt​

Delivery & Last-Mile / COD Collections
GET/delivery/cod-settlements/:payment_id/receipt

Access the saved settlement batch receipt. Requires authentication. Dispatcher/tenant_admin roles or manage:operations:tenant may access their tenant's settlements; drivers may access only their own. Other roles receive 403; unknown/out-of-tenant/out-of-driver scope returns 404. payment_id is the settlement_payment_id returned by either settlement action or a COD collection row.

GET reads status and signs an existing PDF. POST returns the saved PDF when available, reuses an active job, or retries missing/failed PDF generation; it never changes cash, wallet balances, collection status, batch identity, or immutable receipt amounts. No request body is required.

Responses

  • 200: {success:true,data:{settlement_payment_id,receipt_status:"success",url,expires_in:3600}}

  • 202: {success:true,data:{settlement_payment_id,receipt_status:"pending"|"in_process"}}

  • 409: {success:false,code:"settlement_receipt_failed",message,data:{settlement_payment_id,receipt_status:"failure"}}. Use POST to retry.

  • 400: invalid payment UUID.

  • 403: insufficient permissions.

  • 404: payment missing or outside caller scope.

  • 500: unexpected server or storage error.

Display localized message; use code for branching. Signed URLs expire, so reopen this endpoint for a new URL. Bound polling and offer reopen/retry when generation takes longer. Both endpoints send Cache-Control:no-store.

Printed receipt contract

one database-assigned human-readable number (for example CS-1000) is stored in metadata.receipt_snapshot.receipt_number and remains unchanged on retries/reprints. The payment UUID remains the API/storage identifier. The shared cash/wallet template includes the issuer, driver and phone, UTC settlement date, cash receiver or wallet processor, currency, exact COD/fee/order totals, distinct order and collection counts, and optional entered reference, notes and external order references. Internal payment/wallet UUIDs remain in the stored payload rather than the printed layout. No wallet or settlement API response changes are required.

Frontend Print action

call POST once on click to open a saved PDF or retry a failed receipt automatically. Use GET for subsequent status polling; never POST from a polling loop. Initial successful-settlement confirmation may use GET because the backend already queues generation. Repeated/concurrent requests reuse the same payment and active PDF job.

Path parameters

ParameterTypeDescription
payment_idRequiredstring

Example: 91000000-0000-4000-8000-000000000001

Query parameters

ParameterTypeDescription
tenant_idstring—
languagestring

Example: en

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/delivery/cod-settlements/${PAYMENT_ID}/receipt?tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"

Response examples

202Accepted
Response body
json
1{2  "success": true,3  "data": {4    "settlement_payment_id": "91000000-0000-4000-8000-000000000001",5    "receipt_status": "pending"6  }7}

Retry COD Settlement Receipt​

Delivery & Last-Mile / COD Collections
POST/delivery/cod-settlements/:payment_id/receipt

Access the saved settlement batch receipt. Requires authentication. Dispatcher/tenant_admin roles or manage:operations:tenant may access their tenant's settlements; drivers may access only their own. Other roles receive 403; unknown/out-of-tenant/out-of-driver scope returns 404. payment_id is the settlement_payment_id returned by either settlement action or a COD collection row.

GET reads status and signs an existing PDF. POST returns the saved PDF when available, reuses an active job, or retries missing/failed PDF generation; it never changes cash, wallet balances, collection status, batch identity, or immutable receipt amounts. No request body is required.

Responses

  • 200: {success:true,data:{settlement_payment_id,receipt_status:"success",url,expires_in:3600}}

  • 202: {success:true,data:{settlement_payment_id,receipt_status:"pending"|"in_process"}}

  • 409: {success:false,code:"settlement_receipt_failed",message,data:{settlement_payment_id,receipt_status:"failure"}}. Use POST to retry.

  • 400: invalid payment UUID.

  • 403: insufficient permissions.

  • 404: payment missing or outside caller scope.

  • 500: unexpected server or storage error.

Display localized message; use code for branching. Signed URLs expire, so reopen this endpoint for a new URL. Bound polling and offer reopen/retry when generation takes longer. Both endpoints send Cache-Control:no-store.

Frontend Print action

call POST once on click to open a saved PDF or retry a failed receipt automatically. Use GET for subsequent status polling; never POST from a polling loop. Initial successful-settlement confirmation may use GET because the backend already queues generation. Repeated/concurrent requests reuse the same payment and active PDF job.

Path parameters

ParameterTypeDescription
payment_idRequiredstring

Example: 91000000-0000-4000-8000-000000000001

Query parameters

ParameterTypeDescription
tenant_idstring—
languagestring

Example: en

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/cod-settlements/${PAYMENT_ID}/receipt?tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"

Response examples

202Accepted
Response body
json
1{2  "success": true,3  "data": {4    "settlement_payment_id": "91000000-0000-4000-8000-000000000001",5    "receipt_status": "pending"6  }7}

Print COD Collection Settlement Receipt​

Delivery & Last-Mile / COD Collections
POST/delivery/cod-collections/:collection_id/receipt

Print a settled collection receipt on demand. POST requires authentication and no body. Dispatcher/tenant_admin or manage:operations:tenant users may access their tenant records; drivers only their own. Other roles receive 403.

If settlement_payment_id already exists, reuse that saved settlement (including its full original batch). Otherwise, lock the historical collection and create one COD_SETTLEMENT receipt payment for this collection only, link it, and use the existing receipt number, HTML template, PDF queue and storage. Concurrent/repeated clicks cannot create duplicate receipts. No bulk historical backfill occurs.

Historical receipts preserve recorded collection amount, COD/fee allocations, method and original remitted_at. The requester is recorded separately from the original receiver/processor. Current profile names are used because historical names were not captured. The original settlement batch is not reconstructed. Receipt creation never changes settlement status/date, order payments, wallet balances or wallet transactions.

Response matches the settlement receipt endpoint

200 supplies data.settlement_payment_id, receipt_status=success, url and expires_in=3600; 202 supplies payment ID and pending/in_process; 409 supplies settlement_receipt_failed and failure status. A saved PDF is reused, an active job is reused, and missing/failed generation is queued. Cache-Control:no-store.

Frontend contract

show the existing print icon and Print Receipt menu action for remitted or settled_by_wallet collections. When no payment ID exists, POST this endpoint once on click. Retain returned settlement_payment_id and poll GET /delivery/cod-settlements/:payment_id/receipt with bounded retries. Later prints may use the payment endpoint POST; even stale rows that still call this collection endpoint reuse the saved receipt. Never resubmit cash/wallet settlement to generate a receipt.

Currency uses the unique matching original driver wallet debit for wallet receipts, or one unambiguous currency from the original successful order payments for cash receipts. It never falls back to current tenant settings. Missing or ambiguous original currency returns 409 with settlement_receipt_history_incomplete and a localized explanation.

Errors

400 invalid UUID or invalid_cod_collections (unsettled or incomplete historical data); 403 insufficient_permissions; 404 cod_collection_not_found for missing/out-of-tenant/out-of-driver rows; 500 unexpected server/storage error. Show localized message, branch on code.

Path parameters

ParameterTypeDescription
collection_idRequiredstring

Example: 018ce2e7-7165-432d-8ff3-7d7dff7b8ec7

Query parameters

ParameterTypeDescription
tenant_idstring—
languagestring

Example: en

Headers

ParameterTypeDescription
Authorizationstring

Example: Bearer {{access_token}}

Staging
Request
curl
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/delivery/cod-collections/${COLLECTION_ID}/receipt?tenant_id=&language=en" \2  --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"

Response examples

202Accepted
Response body
json
1{2  "success": true,3  "data": {4    "settlement_payment_id": "91000000-0000-4000-8000-000000000001",5    "receipt_status": "pending"6  }7}