Status Flow
rejected(quotes) never comes from a missed confirmation. It’s set on sibling pending quotes when the user accepts a different one on the same RFQ, and on the target quote ofPOST /rfqs/{id}/quotes/{quoteId}/reject.withdrawn(quotes) covers MM-initiated cancellation of a pending quote, and is also what the system writes back onto the previously-accepted quote when the MM misses confirmation and the RFQ reopens.expired(quotes) is used for pending quotes whose ownvalid_untillapses, and for the accepted quote when the RFQ itself expires.
Step-by-Step Flow
User Builds a Live Quote Request
The user adds 2–5 legs to the parlay builder. Each leg references a market on its source venue (The system validates that each market exists in the cache, enforces leg-exclusion rules (see Get Exclusion Groups), versions the request, and broadcasts it to all connected market makers via the Quote Service SSE stream.Quote request status:
kalshi or polymarket) and a side (yes/no). The frontend creates or updates a short-lived quote request instead of immediately creating a real RFQ.market_ticker is venue-polymorphic — see Create Quote Request for the full field reference:- Kalshi: the Kalshi market ticker (e.g.
KXBTC-25FEB07-T100000). - Polymarket: the
condition_id, the 0x-prefixed hex string from Polymarket’s CTF (e.g.0x4d2…). Not the gamma id, question id, or market slug. Both yes and no sides of a Polymarket binary share the samecondition_idand are distinguished byside; CLOB token ids are not part of the RFQ surface.
activeMarket Makers Submit Draft Quotes
Market makers subscribe to the Quote Service SSE stream (The payout is calculated as:
GET /v1/mm/quote-requests/stream) and submit draft quotes with their payout odds.- user_cost = bet_amount (e.g. $25)
- total_payout = bet_amount × payout_odds (e.g. $100)
- mm_cost (MM’s max risk) = total_payout − user_cost (e.g. $75)
activeUser Commits the Best Quote
The frontend shows the best active draft quote. When the user submits, the server selects the best still-valid quote for the displayed version and creates the real RFQ plus accepted quote atomically.The response returns the real
rfq_id, quote_id, selected mm_id, payout odds, and confirmation_deadline — the timestamp by which the market maker must confirm.Status: acceptedMarket Maker Confirms
The market maker confirms before the deadline. Confirmation enqueues vault position creation.If the MM misses the deadline, the RFQ expiry sweep handles it based on the RFQ’s own
expires_at:- RFQ still within
expires_at— RFQ reverts toopen(withaccepted_quote_idandmarket_maker_idcleared so other MMs can quote it again) and the accepted quote becomeswithdrawn. - RFQ past
expires_at— RFQ becomesexpiredand the accepted quote becomesexpired.
confirmedOn-Chain Vault Position Creation
The vault job service executes a single atomic Solana transaction via the Status:
parlay_vaults program. The fee payer covers gas so users and MMs only need USDC in their vaults. User/MM signatures are obtained via Privy session signers.create_position — both the user’s stake and the MM’s collateral are locked atomically in their persistent vaults. The MM’s collateral is calculated via ILP (Integer Linear Programming) to reflect incremental worst-case exposure across the maker’s portfolio, not the full risk amount.The transaction signature and position PDA are stored in the database and displayed in the UI with links to Solana Explorer.Vault Architecture
Learn more about the vault architecture, Privy session-signer integration, and gas-sponsored transactions.
executedSettlement
A background service polls venue resolution feeds and settles positions once all leg markets have resolved. Settlement transfers funds between vaults and deducts a protocol fee on profit:
- All legs win — MM’s risk amount (minus fee) is transferred from the MM vault to the user vault (
settled_win). - Any leg loses — User’s stake (minus fee) is transferred from the user vault to the MM vault (
settled_loss).
settledBackground Services
Two background services manage the vault position lifecycle:- vault-job-service — processes pending positions: resolves Privy wallets, calculates ILP exposure, executes
create_position. - vault-settlement-service — polls market results, settles or cancels active positions based on outcomes.
Validation Rules
| Parameter | Constraint |
|---|---|
| Legs per parlay | 2–5 |
| Bet amount | 1–100 USDC |
| Payout odds | 1.0001× – 1000× |
| Quote request expiry | Server-set; visible as expires_at on the quote request object |
| RFQ expiration | Fixed at 300 s for RFQs created at commit |
Quote validity (expires_in_ms on a draft quote) | 5 s – 60 s (default 15 s) |
| MM confirmation window | Server-controlled; returned on the commit response as confirmation_deadline. Missing it reverts the RFQ to open (quote → withdrawn) or, past expires_at, expires both. |
