Event: Quote Request
delivery_provider.quote_request — pricing a delivery while the customer is still at checkout.
Event: Quote Request
event_type: delivery_provider.quote_request
Sent while a customer is at checkout and the channel needs a delivery price. It is a question, not a commitment: most quotes are never dispatched, and an unused quote costs nothing.
Request
{
"event_id": "9c2f4b71-0e3a-4d55-8f21-6b7c8d9e0a1b",
"event_type": "delivery_provider.quote_request",
"event_timestamp": 1785062400,
"user_id": 12,
"data": {
"brand_id": null,
"brand_guid": null,
"external_store_id": "PZ-0031",
"provider_store_id": "STORE-8871",
"pickup": {
"name": "Pizza Place Hillcrest",
"address": "10 Old Main Road, Hillcrest, 3610",
"latitude": "-29.778100",
"longitude": "30.762200",
"phone_number": "+27317650000",
"ready_at": null,
"deadline_at": null
},
"dropoff": {
"name": "Jane Roe",
"address": "25 Dovehouse Road, Hillcrest 3650",
"latitude": -29.7779,
"longitude": 30.7889,
"phone_number": "+27825550100",
"ready_at": null,
"deadline_at": null
},
"manifest": {
"total_value_cents": 10590
}
}
}data
data| Field | Type | Notes |
|---|---|---|
brand_id | null | Internal to YUMBI Gateway. Always null for you. |
brand_guid | null | Internal to YUMBI Gateway. Always null for you. |
external_store_id | string | YUMBI Gateway's store identifier. |
provider_store_id | string | null | Your identifier for the store. Prefer this. |
pickup | object | Where the food is collected. See below. |
dropoff | object | Where it goes. See below. |
manifest.total_value_cents | integer | null | Gross value of the order in cents, as the channel reported it at checkout. |
pickup and dropoff
pickup and dropoffBoth use the same shape.
| Field | Type | Notes |
|---|---|---|
name | string | null | Store name on pickup; customer name on dropoff. |
address | string | null | One line. The store's address is composed from its address lines, city and postal code. |
latitude | number | string | null | Decimal degrees. |
longitude | number | string | null | Decimal degrees. |
phone_number | string | null | Normalised to E.164 before it reaches you. |
ready_at | ISO 8601 | null | When the order will be ready. Usually null at quote time. |
deadline_at | ISO 8601 | null | Latest acceptable time. Usually null at quote time. |
Coordinates may be numbers or stringsPickup coordinates come from YUMBI Gateway's own store record and serialise as decimal strings (
"-29.778100"). Dropoff coordinates come from the channel's request and are usually JSON numbers. Parse both defensively — do not assume either type.
Pickup details are taken from YUMBI Gateway's store record, with the channel's copy as a fallback. Both sides hold the same store and either can be stale, but the store record is the one dispatch will also build its pickup block from, so a quote and its dispatch always describe the same pickup point.
Phone numbers are normalised to E.164 before we send them, against the brand's country. If a number cannot be normalised it is sent as-is rather than dropped — your own validation is the honest failure at that point.
Response
Return 200 with:
{
"provider_quote_id": "prv_qt_abc123",
"currency_type": "ZAR",
"fee_in_cents": 4500,
"pickup_duration_in_minutes": 5,
"duration_to_reach_dropoff_in_minutes": 22,
"dropoff_eta": "2026-08-07T14:32:00+02:00",
"dropoff_deadline": "2026-08-07T14:50:00+02:00",
"expiration": "2026-08-07T14:15:00+02:00"
}| Field | Type | Notes |
|---|---|---|
provider_quote_id | string | null | Your reference for this price. Returned to you on the dispatch that honours it. |
currency_type | string | null | ISO 4217, e.g. ZAR. |
fee_in_cents | integer | null | What you will charge for the delivery. |
pickup_duration_in_minutes | integer | null | Until a driver reaches the store. |
duration_to_reach_dropoff_in_minutes | integer | null | From pickup to dropoff. |
dropoff_eta | ISO 8601 | null | When the customer receives it. |
dropoff_deadline | ISO 8601 | null | Latest you will commit to. |
expiration | ISO 8601 | null | When this price lapses. |
Every field is optional and unknown fields are ignored, but a quote with no fee_in_cents gives the channel nothing to show the customer.
Quote reuse — why expiration matters
expiration mattersCheckout re-quotes constantly: a customer editing their basket or address can fire a dozen requests in a minute, and several can arrive within milliseconds of each other. YUMBI Gateway absorbs that so you do not have to.
Caching. A quote is reused, without calling you again, when the channel, store, provider and a content hash of the request all match. That hash covers the pickup coordinates and address, the dropoff coordinates and address, and manifest.total_value_cents — coordinates rounded to six decimal places, addresses whitespace- and case-normalised. Timestamps are deliberately excluded, so a second or two of drift between repeat clicks does not invalidate anything, while a changed address or basket total does.
The reuse window is driven by your expiration:
- With an
expiration, the quote is reused until 30 seconds before it lapses, so a caller always has a realistic chance of dispatching before your offer expires. - With no
expiration, the quote is reused for two minutes from when it was issued. - A quote already linked to a dispatch is never reused.
Concurrency. Identical simultaneous requests are serialised behind a lock, so a burst produces one call to you rather than one per request. This matters most where quoting has a side effect on your side — reserving capacity, or creating a provisional job — but it saves everyone the load.
The practical consequence: set expiration honestly. Too long and customers see a price you will not honour. Too short and we re-quote you on every checkout keystroke.
Declining
Return any non-2xx. Declining is expected and is not treated as a fault.
HTTP/1.1 422 Unprocessable Entity
{ "error": "no_drivers_available", "message": "No couriers within range of the store" }The channel receives a 200 carrying is_successful: false and your body under provider_response, and shows the customer that delivery is unavailable. Nothing is retried, and no order is affected — at quote time there is no order yet.
Common reasons to decline: no drivers in range, dropoff outside your service area, store closed on your side, order value above or below what you carry.
If you do not quote
Some providers have no pricing API — the delivery fee is whatever the brand charges, agreed commercially. That is a supported arrangement.
If that is you, either return fee_in_cents: 0 with the other fields null, or tell us during onboarding and we will not register a quote webhook at all. With no webhook registered, YUMBI Gateway records a placeholder quote and never calls you — the channel gets a quote with no fee, and dispatch proceeds normally.
Updated about 17 hours ago
