Quotes
A quote is a short-lived, binding price — orders are always placed against one, so the amount is fixed before you commit.
A quote locks a binding price for one purchase. Orders are always placed against a quote — never against a product directly — so the amount your wallet is debited is fixed before you commit. Quoting requires the quotes.create scope.
Create a quote
POST /api/v1/quotes
{
"productId": "0198d72d-99d6-75a6-9f12-971050ba7a5f",
"variantId": "0198d72d-a15b-7cbf-ab69-b95410e98636",
"value": null,
"quantity": 1,
"currency": "USD"
}| Field | Rules |
|---|---|
productId | Required. A product from your catalog. |
variantId | Required iff the product has variants. |
value | Required iff the product is a value-range product; must land on the product's minimumValue/maximumValue/valueStep grid. |
quantity | 1–20. |
currency | Must equal the product's sell currency. |
A valid request returns 200 OK:
{
"id": "0198d72d-a6ce-77c6-9586-fc36708731d0",
"productId": "0198d72d-99d6-75a6-9f12-971050ba7a5f",
"variantId": "0198d72d-a15b-7cbf-ab69-b95410e98636",
"quantity": 1,
"total": 52.50,
"currency": "USD",
"expiresAtUtc": "2026-09-05T12:05:00Z"
}There is no quote-retrieval endpoint — persist the id and total from this response if you need them later. (That is also why the response is 200 and not 201 with a Location: there is nothing to dereference.)
The rules that keep pricing honest
totalis final. It is the exact amount order creation will reserve and, on fulfillment, debit from your wallet. No fees are added later.- Quotes expire.
expiresAtUtcis typically a few minutes out. An order against an expired quote is rejected — quote at the moment of purchase, not at page-render time. - One quote, one order. Reusing a quote for a second order is rejected; idempotent retries of the same order are handled by the
Idempotency-Key, not by re-quoting. - Quotes are workspace-bound. A quote created by one workspace's key can never be ordered by another.
Displaying prices without quoting
For catalog display, use the variant price fields from the catalog — they are your live sell prices. Reserve quoting for the checkout step. If you cache display prices, keep the cache short-lived: catalog prices move with the market, and the quote at checkout is the only price that binds.
Common rejections
| Status | code | Why |
|---|---|---|
| 400 | invalid_request | Quantity outside 1–20, missing/contradictory variantId/value, off-grid value, wrong currency. |
| 404 | not_found | The product is not in your catalog. |
| 409 | (conflict code) | The product or variant became unavailable between display and quote. |
Handle quote rejection as a normal user-facing event ("this item just became unavailable") rather than an exceptional error — availability is re-verified at every step by design.
Updated about 2 hours ago