Firm Quotes
Every quote Vulcx serves carries aquoteId — a short-lived commitment to the exact route and
price you were shown. Hand it back when you build the swap and the engine replays that route
instead of silently re-quoting, with your minimum-out anchored to the quoted price. Within a short
window you can go further and redeem the quote firm: slippage collapses to a few basis points
around the quoted price, and if the market moved past that, the API refuses before you pay a
transaction fee.
Firm redemption is price-or-fail, not a fill guarantee. If the pool genuinely moved, your
request fails cleanly with a
409 and you re-quote — you never execute at a worse price than you
committed to.The three ways to build a swap
| Mode | Request | What’s enforced | Window |
|---|---|---|---|
| Re-quote (default) | no quoteId | A fresh quote at build time; min-out = fresh quote − slippageBps | — |
| Route-pinned | quoteId | The exact quoted route; min-out = quoted price − slippageBps | validForMs (~3 s) |
| Firm | quoteId + "firm": true | The exact quoted route; min-out = quoted price − firm margin (~10 bps). Drift past the margin fails with 409 before building | firmForMs (~400 ms) |
Where quoteIds come from
GET /api/v1/quote responses and every WebSocket quote push include:
The commitment ID, e.g.
q_b15372a8d82a93d1e328ae24e5d3669a. Omitted when the quote can’t be
pinned (e.g. split routes).How long the
quoteId stays redeemable (default 3000).How long it stays redeemable with
firm: true (default 400).quoteId minted over REST is bound to your API key — only requests authenticated with the same
key can redeem it. Pair, amount, and swapMode must match the original quote exactly.
Route pinning (pass quoteId)
minAmountOut is computed from the quoted amountOut, not from a
fresh re-quote — what the user approved is what the chain enforces. Your slippageBps still
applies on top, so a route-pinned swap behaves exactly like today’s flow when the price hasn’t
moved, and refuses to quietly degrade when it has.
Firm redemption ("firm": true)
Within firmForMs of the quote, add "firm": true to the same request. The engine re-evaluates
the pinned route against live pool state:
- Price held (or improved) → the swap builds with slippage collapsed to the server’s firm
margin (default 10 bps) around the quoted price. Your
slippageBpsis ignored. - Price drifted past the margin →
409 Conflict, no transaction is built, and you can re-quote and retry in one round-trip. Favorable drift always passes.
POST /api/v1/swap and POST /api/v1/instructions accept
quoteId and firm identically.
Error contract
| Status | Meaning | What to do |
|---|---|---|
410 Gone | quoteId expired (past validForMs, or past firmForMs for firm), evicted, or unknown | Re-quote, retry with the fresh quoteId |
409 Conflict | Pinned route no longer exists — or, with firm, price drifted past the margin | Re-quote, retry; for firm, retry immediately |
403 Forbidden | quoteId was minted under a different API key | Re-quote with your own key |
400 Bad Request | Pair, amount, or swapMode don’t match the quote — or firm without a quoteId | Send the exact quoted request |
QuoteExpiredError (410) and QuoteStaleError (409) — both
non-retryable as-is; catch them, re-quote, and retry with the new quoteId. The
widget does this automatically.