Skip to main content
Any account can make markets. You need an API key with the mm:quote scope, USDC to back your quotes, trading enabled once in the app (see Funding), and a bot on two channels: the SSE quote request stream for pricing, and the WebSocket for fills. A request arrives, you quote, the user commits, you confirm within five seconds, collateral locks, settlement pays out A request arrives, you quote, the user commits, you confirm within five seconds, collateral locks, settlement pays out

How it works

1

Stream quote requests

Open GET /v1/mm/quote-requests/stream. You get a snapshot of every active request, then updates. Match event names exactly as the event table lists them. Each leg carries current_yes_price and current_no_price, the venue prices when the request was created, as a starting point for your own pricing.
2

Submit a quote

Send payout_odds for the exact version and request_hash you received, with PUT /v1/mm/quote-requests/{id}/quote.
Odds apply to the net stake, user_stake, never to bet_amount. Quoting off the gross bet overprices every quote. See Limits and fees.
3

Confirm the fill

When a user commits your quote, you get quote:accepted on the mm:quotes:{mm_id} channel of the WebSocket, with the quote_id and a confirmation_deadline a few seconds away. Confirm with POST /v1/mm/quotes/{quoteId}/confirm before that timestamp. The SSE stream only says a request closed, so keep the socket open. Confirm with the event’s quote_id, not the draft id your submit returned.
4

Reconcile

After a disconnect or a restart, list GET /v1/mm/quotes?status=accepted and confirm anything still open.

Endpoints

Quoting rules

  • One live quote per request version. Submitting again replaces it.
  • Send only request_version, request_hash, payout_odds and, optionally, expires_in_ms. The server derives every money field from your odds and the net stake.
  • A new version invalidates your old quote. Re-price and submit again. There is nothing to withdraw.
  • DELETE a quote only to stand down on the current version before the user commits.
  • Submit and confirm take no Idempotency-Key. After a timeout, read GET /v1/mm/quotes?status=accepted before you confirm again.
Quote validity, the confirmation window, and the quote service’s 300 requests a minute per IP are on Limits and fees. Re-quote when a quote is about to lapse or your price moves, not on a timer.

Your balance

Quotes are backed by wallet USDC plus your vault’s free balance. The submit check (insufficient_collateral) and the confirm check both read that sum. Your vault is created with your first filled position. Until then keep USDC in the wallet. POST /v1/vault/deposit returns 404 before the vault exists, and is optional after. Live quotes do not reserve collateral. Each quote is checked on its own when you submit it, so if several fill at once, a confirm can fail for lack of funds. A missed confirmation loses the fill, and the bettor can leave you out of that request.

Profit and loss

There is no maker P&L endpoint yet. Record user_stake and mm_risk when you confirm, and settle them against mm_result on the maker position.settled webhook.

Collateral and the ILP

You do not lock each position’s full mm_risk on its own. Totalis locks your worst-case loss across your whole book of open positions. It finds that number exactly by solving an integer linear program (ILP) over every way your markets can resolve, so positions that cannot all pay out at once share collateral. Two parlays that cannot both win: posted in isolation they lock 20,000, margined as a portfolio they lock 12,000 Two parlays that cannot both win: posted in isolation they lock 20,000, margined as a portfolio they lock 12,000 In the picture, two parlays cannot both win. Locked one by one they need 20,000 USDC. As a book they need 12,000, the larger of the two.
Netting lowers what stays locked, not what you need to quote. Submitting a quote and confirming a fill both require wallet plus vault free balance to cover the quote’s full mm_risk, plus the mm_risk of any fills not yet on chain.
The solver treats these as linked, and everything else as independent:
  • The legs of one position. It pays only if every leg hits.
  • Markets in one event where only one can resolve yes, such as the winner of a game.
  • Kalshi strike ladders on the same underlier or game, such as BTC above 100k and above 90k, or a game’s totals and spreads.
  • A team’s total over a line and the game’s total over the same line.
  • Markets that have resolved but not yet settled. They are fixed to their result.
Treating two markets as independent can only overstate your worst case, never understate it. If a solve runs out of time you are locked a safe upper bound, never more than the plain sum of your mm_risk. In Totalis backtests the saving was 10% to 30% for generalist books, 20% to 40% for books on a single league, and over 70% for books of long-tail parlays with four or more legs.

Early cashouts

A user can leave a live position before it settles. Totalis broadcasts a short auction to every maker as a cashout_request event on the stream you already read. Reply with one all-in price_micro, the amount the user receives in microUSDC, through PUT /v1/mm/cashout-requests/{id}/quote. The highest live bid wins, and ties go to the earliest. To pass, submit nothing. If you back the position, a win closes it, and the profit fee comes out of whichever side profits. If you do not, a win acquires it: the position moves to your account as the bettor side, and shows in GET /v1/rfqs. Cashout auctions has the rules, payload and errors.

Your identity

Your mm_id is your user_id, a Privy DID (did:privy:...). auth:success on the WebSocket and the connected event on the SSE stream both return it, and it names your mm:quotes:{mm_id} channel.
counterparty_mm_id is not your id and not the bidder’s id. It names the maker who already backs a position. See the Glossary.

Get set up

Get an API key

A key with the four read scopes and mm:quote.

Cashout auctions

Bid on parlay exits and know which outcome you are in.

Errors

Every rejection reason, and which to alert on.

MM API reference

Every maker endpoint and event.
To provide liquidity at scale, email founders@totalis.trade.