Quotes and pricing
Design 0Pools quote UX around indicative quotes, firm quote locks, expiry, spread, fees, and execution.
Quotes are the product contract of 0Pools. They turn a volatile fiat/stablecoin market into a bounded partner-visible offer: rate, fees, side, amount, network, delivery target, and expiry.
Quote ladder
Indicative vs firm
| Quote type | Persisted | Executable | Best for |
|---|---|---|---|
indicative | No | No | Live price preview while the user edits. |
firm | Yes | Yes, once | The exact terms the user accepts. |
Do not transact an indicative quote. It has no quoteId and no inventory lock.
What the quote locks
| Locked field | Why |
|---|---|
| Pool id | Prevents switching route after user acceptance. |
| Side | Defines amount semantics. |
| Fiat and crypto currencies | Defines pair. |
| Amounts | Prevents browser tampering. |
| Network | Keeps execution on the quoted network. |
| Destination address | Prevents delivery redirection. |
| Rate, spread, fee | Defines partner-visible economics. |
| Expiry | Bounds market risk. |
Rate, spread, and fee
| Field | Meaning |
|---|---|
rate | All-in output per input for the side. |
spreadBps | Pool FX spread in basis points. |
feeBps | Partner tier draw fee in basis points. |
minOrderUsdt | Minimum order in USDT-equivalent. |
maxOrderUsdt | Maximum order if configured. |
All money and rate values are decimal strings. Use decimal libraries for ledger math.
Slippage framing
0Pools should be described as quote-locked or bounded, not as magical "no slippage" in every market condition. A firm quote reduces the partner's exposed slippage window because the user can only accept the returned terms before expiry. If the quote expires or liquidity is unavailable, request a new quote.
Good quote UX
- Validate pair, side, network, and amount before quote.
- Use indicative quotes for editing.
- Create a firm quote when the user reaches confirmation.
- Show output amount, rate,
spreadBps,feeBps, network, destination, and expiry. - Disable accept before expiry.
- Execute once with idempotency.
- Show pending until status is terminal.
Unavailable quotes
Unavailable quotes return no quoteId. Handle them as a product state:
{
"available": false,
"unavailableReason": "pool_dry"
}Show a retry or alternate-pool option; do not retry in a tight loop.
Quote contract details
A quote is the product contract the user accepts. Treat it as immutable after creation.
| Quote type | Executable? | Store? | UI behavior |
|---|---|---|---|
| Indicative | No. | Optional analytics only. | Refresh while user edits. |
| Firm | Yes until expiry. | Required. | Show countdown and final amount. |
| Expired | No. | Required if shown/accepted. | Disable accept and request fresh quote. |
| Accepted | No new edits. | Required with trade linkage. | Show pending/processing. |
Firm quote example
{
"quote_id": "pq_live_01J4",
"pool_id": "EUR-USDT",
"quote_type": "firm",
"side": "buy",
"source_asset": "EUR",
"source_amount": "100.00",
"target_asset": "USDT",
"target_amount": "107.42",
"expires_at": "2026-06-28T20:14:30Z",
"executable": true
}Error treatment
| Error shape | Product behavior |
|---|---|
| Quote expired. | Request fresh quote and require user confirmation again. |
| Amount outside limits. | Show min/max before creating another quote. |
| Pool unavailable. | Disable action and offer retry later. |
| Idempotency conflict. | Render existing trade if same order; investigate if different order. |
Implementation depth
This page is about designing quote UX around preview, lock, expiry, fees, and execution. For developers, the durable boundary is simple: your product should depend on indicative rate, firm quote id, expiry, spread bps, fee bps, and unavailable reasons; it should not depend on source pricing, market-maker terms, and hedging decisions. That boundary is what lets 0Pools improve liquidity operations without forcing every partner to rebuild product code.
Product scenario
A user types an amount and sees a refreshing estimate. When they tap confirm, the server locks a firm quote and the UI shows a countdown tied to expiresAt.
Before and after in practice
| Before 0Pools | With 0Pools |
|---|---|
| Users accept an estimate that was never executable, creating slippage complaints and refund pressure. | Users accept a firm quote with a clear expiry, and stale quotes cannot be executed. |
| Product teams infer liquidity behavior from provider-specific screens or manual notes. | Product teams branch on 0Pools objects: pool, quote, trade, balance, webhook, and ledger. |
| Support asks engineering to reconstruct state from logs. | Support starts from request id, quote id, trade id, event id, and ledger id. |
System flow
Records to keep
| Record | Why it matters | Example |
|---|---|---|
quote_type | Distinguishes preview from executable terms. | firm |
rate | All-in rate shown to user. | 1.0731 |
expires_at | Countdown source. | 2026-06-28T... |
unavailable_reason | Why no executable quote exists. | pool_dry |
A useful implementation stores these records before adding optional analytics. Analytics can be rebuilt from durable state; missing ids usually cannot be reconstructed after a customer-impacting failure.
Example product record
{
"product_area": "quotes-pricing",
"partner_reference": "partner_order_123",
"pool_id": "EUR-USDT",
"quote_id": "pq_test_123",
"transact_id": "pt_test_456",
"status": "reserved",
"request_id": "req_01HZY0POOLS",
"reconciliation_state": "open"
}This record is intentionally partner-facing. It references 0Pools objects and your own product ids, but it does not include private liquidity routes, treasury balances, raw provider payloads, or customer secrets.
Failure modes and recovery
| Failure mode | Product response |
|---|---|
| Indicative quote executed | Only firm quotes return executable quoteId. |
| Countdown hidden | Show expiry before the accept action. |
| Fee fields dropped | Persist spread and fee fields for support. |
| Price refreshed after accept | Execute the accepted quote id only. |
Use-case patterns
| Pattern | How 0Pools helps |
|---|---|
| Quote screen | Refresh indicative price while editing. |
| Confirm screen | Lock firm terms. |
| Support ticket | Explain displayed price from quote fields. |
Developer checklist
- Read runtime discovery and capabilities before rendering enabled actions.
- Create firm quotes only when the user is ready to accept the terms.
- Execute from your server with an idempotency key.
- Treat webhooks and status reads as the source of truth for settlement state.
- Reconcile by durable ids first, then by amount and timestamp.
- Do not branch product behavior on provider names, route names, reserve balances, or treasury assumptions.