POST /v1/delivery/quote
POST /v1/delivery/quote
| Scope | Idempotency-Key | Operation ID |
|---|---|---|
quotes.create | Optional | createQuote |
Authoritative quote with expiry and pricing version.
The caller supplies intent and coordinates, never a distance or price (any
server-controlled field is SERVER_CONTROLLED_FIELD). The server resolves both pins, applies the tenant's gateways, zones and vehicle types, checks the vehicle
for this delivery, measures the verified road distance and prices it
with the ACTIVE pricing version. Quote creation is audited. Past the
tenant's maximum verified distance the
quote is LOCATION_NOT_SUPPORTED (reason: max_distance). If routing fails, a
pre-approved fallback may price it; with none, PRICING_UNAVAILABLE. The quote
expires at expires_at by the server clock; after that it cannot be confirmed
(QUOTE_EXPIRED). breakdown appears only when the tenant has detailed pricing
visibility. Idempotency-Key optional: a retry with the same key replays the same
quote instead of issuing another.
Request
Signed with your API credential: see Authentication.
| Parameter | In | Required | Description |
|---|---|---|---|
Idempotency-Key | header | No | One key per user intent, reused for every retry of that intent. See Idempotency. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
pickup | object | Yes | |
pickup.latitude | number | Yes | WGS84; precision is judged as sent |
pickup.longitude | number | Yes | |
pickup.accuracy_m | number | No | |
dropoff | object | Yes | |
dropoff.latitude | number | Yes | WGS84; precision is judged as sent |
dropoff.longitude | number | Yes | |
dropoff.accuracy_m | number | No | |
vehicle_type | string | Yes | A catalogue code available for this delivery (GET /v1/vehicle-types) |
service_type | string | Yes | One of: EXPRESS, PRIORITY, STANDARD, NEXT_DAY. |
external_order_reference | string | No | The tenant's own order handle; IDM stores nothing else about the order Pattern ^[A-Za-z0-9][A-Za-z0-9._:/#-]{0,63}$. |
Responses
200
The quote.
| Field | Type | Required | Description |
|---|---|---|---|
quote_reference | string | Yes | Pattern ^QT-[0-9A-HJKMNP-TV-Z]{8}$. |
currency | string | Yes | One of: GHS. |
delivery_fee | string | Yes | Exact decimal with two places; never a JSON number. Pattern ^-?[0-9]+\.[0-9]{2}$. |
classification | string | Yes | One of: INTRA_ZONE, INTER_ZONE, INTER_GATEWAY. |
vehicle_type | string | Yes | |
service_type | string | Yes | One of: EXPRESS, PRIORITY, STANDARD, NEXT_DAY. |
pricing_version | string | Yes | |
expires_at | string, date-time | Yes | Server clock; the quote cannot be confirmed after it |
pickup | object | Yes | |
pickup.suburb | object | Yes | |
pickup.suburb.reference | string | Yes | Pattern ^SUB-[0-9A-HJKMNP-TV-Z]{8}$. |
pickup.suburb.name | string | Yes | |
pickup.description | string | Yes | |
pickup.approximate | boolean | Yes | |
dropoff | object | Yes | |
dropoff.suburb | object | Yes | |
dropoff.suburb.reference | string | Yes | Pattern ^SUB-[0-9A-HJKMNP-TV-Z]{8}$. |
dropoff.suburb.name | string | Yes | |
dropoff.description | string | Yes | |
dropoff.approximate | boolean | Yes | |
estimated | object | Yes | |
estimated.pickup_window_min | integer or null | Yes | Null until dispatch supply data can support it; never an invented figure |
estimated.delivery_duration_min | integer or null | Yes | From the route's duration; null when a fallback priced the quote |
external_order_reference | string or null | Yes | |
breakdown | object | No | Returned only with detailed pricing visibility. Distances 2 dp, rates and modifiers 4 dp. |
breakdown.verified_distance_km | string or null | Yes | |
breakdown.included_distance_km | string | Yes | |
breakdown.chargeable_distance_km | string or null | Yes | |
breakdown.base_fee | string or null | Yes | |
breakdown.distance_rate | string or null | Yes | |
breakdown.distance_surcharge | string or null | Yes | |
breakdown.zone_multiplier | string | Yes | |
breakdown.peak_modifier | string | Yes | |
breakdown.season_modifier | string | Yes | |
breakdown.classification_multiplier | string or null | Yes | Null when multiplier enforcement is off for the scope |
breakdown.fallback_applied | boolean | Yes | An approved fallback priced the quote |
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.
404
No such route, or no such resource visible to the caller.
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.