Documentation

Quotes

A quote is a priced, time-bound snapshot. It binds the offers, quantities, currency, discount, FX snapshot and total for 15 minutes. It is not a payment and it does not reserve stock.

Code
POST /v1/quotes

Required scope: catalog:read in the current handler. The target contract uses quotes:write; include both on a key that creates quotes during the rollout.

Request

JSONCode
{ "currency": "USD", "items": [ { "offerId": "11111111-1111-4111-8111-111111111111", "quantity": 2 } ] }
FieldRule
currencyUSD, EUR or GBP. Defaults to USD when omitted.
itemsAt least one line. Maximum 200 lines.
offerIdOpaque id from GET /v1/catalog.
quantityInteger, at least 1. Total across lines must be 1 to 5,000.

Agent defaults are 50 lines and 500 units per order unless the principal raises them. Those caps are part of the target agent contract and are not enforced by the current quote handler.

Idempotency-Key is not required on quote creation. If you send one, it is included in the signature but does not deduplicate quotes. A retry creates another quote with a new id.

Response

JSONCode
{ "quoteId": "22222222-2222-4222-8222-222222222222", "status": "open", "currency": "USD", "totalMinor": 1618, "expiresAt": "2026-11-04T03:15:00.000Z", "fxAsOf": "2026-11-04T02:59:00.000Z", "capped": false, "lines": [ { "offerId": "11111111-1111-4111-8111-111111111111", "quantity": 2, "listUnitMinor": 899, "finalUnitMinor": 809, "discountUnitMinor": 90, "requestedPercent": 10, "appliedPercent": 10, "capped": false } ] }
FieldMeaning
quoteIdUse this in POST /v1/orders or GET /v1/quotes?id=.
statusopen until accepted or expired.
totalMinorSum of finalUnitMinor * quantity.
expiresAtAbsolute expiry, 15 minutes after creation.
fxAsOfFX snapshot used for EUR or GBP conversion.
cappedTrue when any line was raised to the margin floor.
linesPublic line items. Upstream identifiers are omitted.

Read a quote

GET /v1/quotes?id={quoteId} returns the same public shape. This helper is Preview: it is implemented but not yet in the published OpenAPI document. It requires catalog:read and only returns quotes owned by the calling partner.

The target contract also describes GET /v1/quotes/{id}. Use the query form until that path is published.

Expiry and capped prices

  • A quote expires 15 minutes after creation. An order with an expired quote returns 409 quote_expired.
  • capped: true means the partner's requested discount would breach the contribution-margin floor. finalUnitMinor was raised to the floor. Do not recompute the total from requestedPercent.
  • A quote can be accepted once. A second order with the same quote returns 404 quote_not_found because the quote is no longer open.

What the quote does not do

  • It does not reserve stock.
  • It does not debit the wallet.
  • It does not guarantee that the upstream product will still be available at order time.
  • It does not lock the FX rate beyond its own expiry.

The order rechecks the current price and availability against the quote snapshot. A mismatch returns 409 price_changed, and no order is created and no funds are debited.

One-call alternative

POST /v1/orders accepts currency, items and expectedTotalMinor instead of quoteId. The API creates an internal quote, checks the expected total and proceeds. Use this shape only when the agent has a clear mandate and a maximum total. See Orders.

Errors

StatusCodeMeaning
400validation_errorMissing items, bad currency, non-integer quantity, more than 200 lines or more than 5,000 units.
409out_of_stockAt least one offer is unavailable.
409quote_expiredThe quote is older than 15 minutes.
503fx_unavailableEUR or GBP rate missing or stale.
429rate_limited / quota_exceededQuote limit reached. No quote row was created.