Skip to main content
Live quote requests are the core trading mechanism on Totalis. You create a parlay with 2-5 market legs, market makers compete to price it in real time, and you lock in the best offer when you’re ready. All endpoints use the /v1/ prefix on the Quote Service base URL.

How It Works

1

Create a Quote Request

Call POST /v1/quote-requests with your parlay legs and bet amount. You can update legs or bet amount with PATCH /v1/quote-requests/{id} — each change bumps the version and invalidates stale quotes.
2

Stream Live Pricing

Open an SSE connection to GET /v1/quote-requests/{id}/stream to receive best_quote events as market makers submit and update their offers. Each event includes book_seq (monotonically increasing) and the current best payout multiplier.
3

Market Makers Price Your Request

Connected market makers receive your request via their SSE stream and submit competing quotes via PUT /v1/mm/quote-requests/{id}/quote. You always see the best available offer.
4

Commit the Best Quote

When you’re satisfied with the price, call POST /v1/quote-requests/{id}/commit. The commit includes protection fields that prove you saw the current price, preventing stale execution.
5

Trade Confirmation

The winning market maker receives a quote:accepted event via WebSocket and confirms the trade. Vault settlement begins automatically.

Commit Protection

The commit endpoint requires these fields to ensure you’re locking in the price you actually saw:
FieldTypeDescription
expected_versionintegerThe quote request version you’re committing against. Rejected if the request was modified since your last update.
displayed_quote_idstringThe id of the best quote you were shown.
displayed_quote_book_seqintegerThe book_seq from the SSE event that delivered the quote. Proves your pricing was current.
min_payout_odds_seennumberThe minimum payout odds you saw. Only quotes at or above this threshold can be selected.
{
  "expected_version": 3,
  "displayed_quote_id": "quote-uuid",
  "displayed_quote_book_seq": 5,
  "min_payout_odds_seen": 4.25
}

Rejection Codes

If a commit fails, error.details.reason tells you why:
ReasonWhat Happened
QUOTE_CHANGEDThe request was updated since your last fetch. Re-fetch and try again.
MARKET_NOT_LIVEOne or more markets expired, halted, or were delisted. Remove the affected legs.
QUOTE_EXPIREDAll quotes expired. Wait for a fresh quote and retry.
COMMIT_FAILED_RETRYABLETemporary error. Retry after a short delay.

For Market Makers

Receiving Quote Requests

Connect to the MM SSE stream to receive quote requests in real time. On initial connection you receive a snapshot of all active requests, then incremental updates as new requests arrive.

Submitting Quotes

Call PUT /v1/mm/quote-requests/{id}/quote with the request_version and request_hash from the SSE event. One active quote per request version — submitting again replaces your previous quote. Send only the fields below; the server derives user_cost, total_payout, and mm_cost from payout_odds and the request’s bet_amount.
{
  "request_version": 3,
  "request_hash": "sha256...",
  "payout_odds": 4.25,
  "expires_in_ms": 15000
}
Keep quotes short-lived (default 15s). When the request changes to a new version, your prior-version quote is invalidated automatically — just re-price and PUT a new quote with the new version and request_hash. You don’t need to withdraw the old one.

Withdrawing Quotes

Call DELETE /v1/mm/quote-requests/{id}/quote to retract a quote on the current version before the user commits it — for example, if your price moved and you want to stand down. This is not part of the version-change flow: a new version already invalidates your prior quote, so you don’t withdraw to re-quote.

Heartbeat

Send POST /v1/mm/heartbeat every 30 seconds to signal liveness. The TTL is 60 seconds.

SSE Event Format

Events on the user stream (/v1/quote-requests/{id}/stream):
{
  "book_seq": 5,
  "version": 3,
  "best_quote": {
    "id": "quote-uuid",
    "payout_odds": 4.25,
    "user_cost": 25,
    "total_payout": 106.25,
    "mm_cost": 81.25,
    "valid_until": "2026-06-01T18:45:45.000Z"
  }
}
When no quotes are active, best_quote is null. Store book_seq and best_quote.id from the latest event — you’ll need them for the commit request.

Quote Request Object

{
  "id": "1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40",
  "version": 3,
  "request_hash": "sha256...",
  "book_seq": 5,
  "status": "active",
  "bet_amount": 25,
  "expires_at": "2026-06-01T18:45:30.000Z",
  "legs": [
    {
      "id": "8ccf2c5d-...",
      "market_ticker": "KXBTC-26JUN05-T73500",
      "side": "yes",
      "venue": "kalshi"
    }
  ],
  "input_legs": [
    { "market_ticker": "KXBTC-26JUN05-T73500", "side": "yes", "venue": "kalshi" }
  ]
}