Skip to main content

POST /v1/bulk-deliveries/{ref}/quote

POST /v1/bulk-deliveries/{ref}/quote

ScopeIdempotency-KeyOperation ID
quotes.createOptionalquoteBulkDelivery

Quote every confirmed child; the total is their sum.

(Re)quotes every active child: each from the shared pickup to its own confirmed drop-off, with its own vehicle and service, by the same Quotation service as a single delivery, for the Bulk's partner. The total is the plain sum of the child quotes: no Bulk price, distance or discount. Allowed before the sender confirms, once every active recipient has confirmed their location (else BULK_RECIPIENTS_PENDING); after confirmation BULK_STATE_CHANGED, once cancelled BULK_CANCELLED. Routing runs outside any lock; a child whose drop-off changed meanwhile is RETRYABLE. A failed quote leaves the Bulk as it was. The quote revision moves on with every quote: confirm names the revision reviewed. The tenant is sent bulk.quote_ready. Idempotency-Key optional (a repeat quotes again). Audited (bulk.quote).

Request​

Signed with your API credential: see Authentication.

ParameterInRequiredDescription
Idempotency-KeyheaderNoOne key per user intent, reused for every retry of that intent. See Idempotency.
refpathYesPattern ^BK-[0-9A-HJKMNP-TV-Z]{8}$.

Responses​

200​

Quoted; the total and the new revision.

FieldTypeRequiredDescription
bulk_referencestringYesPattern ^BK-[0-9A-HJKMNP-TV-Z]{8}$.
statusstringYesOne of: BULK_DRAFT, BULK_AWAITING_RECIPIENTS, BULK_PARTIALLY_CONFIRMED, BULK_READY_FOR_QUOTE, BULK_AWAITING_SENDER_CONFIRMATION, BULK_DISPATCHING, BULK_IN_PROGRESS, BULK_PARTIALLY_COMPLETED, BULK_COMPLETED, BULK_CANCELLED, BULK_EXCEPTION.
recipient_countintegerYes2–5.
active_recipient_countintegerYes0–5.
confirmed_countintegerYes0–5.
quote_revisionintegerYes
totalstring or nullYesThe sum of the children's quotes, null until every active child is quoted.
currencystringYesOne of: GHS.
childrenarray of objectYes
children[].positionintegerYes1–5.
children[].delivery_referencestringYesPublic reference of a delivery job or Bulk child. Pattern ^DX-[0-9A-HJKMNP-TV-Z]{8}$.
children[].statusstringYesThe child request's status (request-level states; REMOVED once removed)
children[].location_confirmedbooleanYesThe recipient confirmed the drop-off
children[].recipientobjectYes
children[].recipient.first_namestringYes
children[].recipient.last_namestringYes
children[].recipient.phonestringYesMasked: the last three digits only
children[].link_expires_atstring or null, date-timeYesWhen the child's live link stops working; null once revoked
children[].resends_remaininginteger or nullYesResends left while the recipient is awaited, else null
children[].resend_available_atstring or null, date-timeYesWhen the resend cooldown ends while the recipient is awaited, else null
children[].quoteobject or nullYesThe child's own quote: the server's total only, never its arithmetic. expired is judged by the server clock. Null before the child is quoted.
children[].quote.referencestringYesPattern ^QT-[0-9A-HJKMNP-TV-Z]{8}$.
children[].quote.totalstringYesExact decimal with two places; never a JSON number. Pattern ^-?[0-9]+\.[0-9]{2}$.
children[].quote.currencystringYesOne of: GHS.
children[].quote.expires_atstring, date-timeYes
children[].quote.expiredbooleanYes
children[].customer_statusstring or nullYesThe child's delivery status as tracking shows it, once dispatched
children[].tracking_linksobjectNoThe child's tracking links, shown once on the tenant's confirming response: the sender's link confirms the handover
children[].tracking_links.sender_urlstringYes
children[].tracking_links.recipient_urlstringYes
children[].tracking_links.expires_atstring, date-timeYes
cancellationsarray of objectNoAfter dispatch, each child's answer to the cancellation; present only on that answer.
cancellations[].delivery_referencestringYesPublic reference of a delivery job or Bulk child. Pattern ^DX-[0-9A-HJKMNP-TV-Z]{8}$.
cancellations[].cancelledbooleanYes
cancellations[].reasonstring or nullYesWhy the stage policy left it, e.g. after_pickup
created_atstring, date-timeYes

400​

Structural validation failed or an Idempotency-Key is missing.

The error envelope: code, message, detail, request_id.

401​

Unknown, revoked or wrong-environment credential, bad signature, or expired session.

The error envelope: code, message, detail, request_id.

403​

Tenant access denied (existence is not disclosed), insufficient scope, MFA/step-up required, partner blocked or module disabled.

The error envelope: code, message, detail, request_id.

409​

State changed, race lost, or idempotency conflict. Refetch before deciding again.

The error envelope: code, message, detail, request_id.

422​

Semantically invalid (location, vehicle, server-controlled field, bulk limits).

The error envelope: code, message, detail, request_id.

429​

Rate limit reached; honour Retry-After.

The error envelope: code, message, detail, request_id.

500​

Unexpected failure. Only code and request_id are returned.

The error envelope: code, message, detail, request_id.

503​

Pricing/routing unavailable, request timeout, retryable contention, or an operator must act first (ACCOUNTING_PERIOD_UNAVAILABLE, outcome REQUIRES_ADMIN), or the payment provider cannot start a payment (PAYMENT_PROVIDER_UNAVAILABLE, outcome REQUIRES_PAYMENT; nothing charged).

The error envelope: code, message, detail, request_id.