- User creates an unsigned Request for a Combo price.
- RFQ system sends the Request to connected market makers.
- Market makers submit signed Quotes within the 400 ms submission window.
- RFQ system returns the best Quote to the user.
- User accepts the Quote by signing the trade within the 10-second acceptance window.
- RFQ system requests Last Look confirmation when Last Look is enabled.
- Market maker confirms or declines within the 1-second confirmation window.
- RFQ system executes the accepted Combo.
- User receives execution updates.
- Market maker receives execution updates.
- Connected market makers receive confirmed trade broadcasts.
Combo position IDs are complementary to CLOB token IDs. A user can trade the
market on the CLOB or can include the market as a leg of a Combo.
For development updates on market making for Combos, join the Combos market
maker Telegram group.
Start Quoting
Start by preparing an authenticated quoting session with the RFQ system. You need a Polymarket account; create one at polymarket.com.- TypeScript
- Python
- API
Install the Package
Install the Unified TypeScript SDK with the package manager of your choice.
This page uses Viem for wallet signing. See the TypeScript tooling
guide for other wallet library integrations.
Create a Secure Client
Create an instance of The Relayer API key is necessary for setting up trading approvals in the next
step. Create a Relayer API key
from Settings > API Keys.
SecureClient with a wallet that has funds for fulfilling
user requests and its signer details.Handle Quote Requests
Quote requests describe a user’s intent to buy or sell shares in a Combo defined by a given set of legs. A quote request can currently only buy or sell the YES side of a Combo. The following cases show how a market maker can satisfy a user’s buy or sell request using collateral or inventory.| Quote Request | Using Collateral | From Inventory |
|---|---|---|
| Buy YES | Buy NO at 1 - price | Sell YES at price |
| Sell YES | Buy YES at price | Sell NO at 1 - price |
Authorize the Quote
Authorize each quote by pricing the request and returning a signed order to the RFQ system. Quoters should respond within the 400 ms submission window.- TypeScript
- Python
- API
Evaluate Request
Then, inspect the
Where:
RfqQuoteRequestEvent before pricing it.| Field | Type | Description |
|---|---|---|
rfqId | RfqId | RFQ identifier used to correlate responses |
requestorPublicId | RfqRequestorPublicId | Public identifier for the user request |
conditionId | ComboConditionId | Derived Combo condition ID |
direction | RfqDirection | Whether the user wants to buy or sell |
side | RfqSide.Yes | Currently always RfqSide.Yes |
requestedSize | RfqRequestedSize | User-requested notional or share size |
yesPositionId | PositionId | Derived YES Combo position ID |
noPositionId | PositionId | Derived NO Combo position ID |
legPositionIds | PositionId[] | Underlying leg position IDs |
submissionDeadline | EpochMilliseconds | Unix-millisecond quote submission deadline |
requestedSize is an RfqRequestedSize value that describes how the user sized
the request.notional: the target value of the request in collateral currency. For example,"3"means the user wants roughly 3 pUSD worth of the Combo, with the resulting share size derived from the quote price.shares: the target number of Combo outcome tokens. For example,"10"means the user wants 10 shares, or 10,000,000 base units.
value is a normalized decimal string.Quote Partial Fills
- TypeScript
- Python
- API
If you only want to fill part of the requested size, pass
size with the quote.
size is a normalized decimal value: "10" means 10 shares, or 10,000,000 base
units. When omitted, the SDK quotes the full requested size.Use Inventory
- TypeScript
- Python
- API
By default, quotes use collateral (pUSD) to buy YES or NO tokens as needed to
satisfy the quote request according to the combinatorial position logic. Pass
source: "inventory" when you want to quote from existing inventory instead.Cancel Quotes
After you submit a quote, keep the returned quote reference. If your price, inventory, or risk changes before the quote is selected, use that reference to request cancellation.A cancellation acknowledgement means the RFQ system processed the cancellation
request. It does not guarantee the quote was withdrawn from an RFQ that was
already selected.
- TypeScript
- Python
- API
Last Look
Last Look is a separate final review step for makers that have it enabled. If a selected quote requires Last Look, run a final risk check before the deadline and accept or reject the fill. Last Look is offered to makers with approximately $2,500 in Combo notional volume and an established line of communication with Polymarket. This keeps the program reliable and helps Polymarket resolve system issues quickly. To request access, complete the Last Look request form. Once access is enabled, your quoting system will immediately be asked to review selected fills. Make sure it is ready to evaluate and answer them before approval is activated.- TypeScript
- Python
- API
Switch on the Event Type
First, switch on
event.type to handle confirmation requests from the same
session stream.Inspect the Confirmation Request
Then, inspect the confirmation request before running your final risk check. It
includes the selected quote, the final fill size, and the
event.confirmBy
deadline for your Last Look response.Manage Combo Positions
Use Combo position workflows to manage inventory throughout the quote lifecycle.List Combo Positions
List Combo positions as part of your background inventory sync. Keep this state fresh outside the quote path.- TypeScript
- Python
- API
Use Each returned item is a You can filter positions by the following criteria:
client.listComboPositions(...) to page through Combo positions for the
authenticated account. Filter by status, Combo condition ID, or Combo position
ID when you only need a subset of positions.ComboPosition.Displaying closed (redeemed) positions.
entry_cost_usdc is the
remaining cost basis (entry_avg_price × shares_balance), so it reads ~0
once a winning combo is redeemed — and shares_balance does too. Two fields
carry the closed-position economics instead:realized_payout_usdc— gross redemption proceeds (winning shares redeem 1:1 at $1; accumulates underPARTIAL)total_cost_usdc— original cost basis, reconstructed asentry_avg_price × (shares_balance + realized_payout)
realized_payout_usdc − total_cost_usdc.Inventory Management
If you want to quote from inventory, build the inventory before quote requests arrive. Splitting converts collateral into complementary Combo positions for a set of legs. Merging converts matching complementary Combo positions back into collateral.- TypeScript
- Python
- API
Use Use
client.splitPosition(...) with legs to create Combo inventory from
collateral. amount is in pUSD base units.client.mergePositions(...) with the same legs to merge complementary
Combo positions back into collateral. Pass amount: "max" to merge the largest
matching amount available.Redeem Resolved Positions
When a Combo position resolves, redeem the winning position to settle it back to collateral.- TypeScript
- Python
- API
Use You can list resolved winning positions first, then redeem each one.
client.redeemPositions(...) with a Combo positionId. The SDK redeems the
available balance for that resolved position.Get Combo Markets
Use the Combo markets catalog to retrieve active markets that can be used as Combo legs. Markets are ordered by volume descending.- TypeScript
- Python
- API
Use Use The SDK returns structured YES and NO outcomes.
client.listComboMarkets(...) to page through markets that can be used as
Combo legs.exclude to omit markets you have already shown or selected.Map Legs to Markets
Market makers should build their own view of the markets that support Combos before quote requests arrive. Combo-enabled markets expose a list of position IDs with two entries: the first is the YES position ID and the second is the NO position ID. These IDs identify the outcome positions your pricing system can map back to market data.- TypeScript
- Python
- API
Fetch non-closed markets and index them by position ID in your own market data
store.You can also fetch markets by leg position ID on demand, but most market makers
will want this context ready before the 400 ms quote window starts.
Listen to Execution Updates
Execution updates tell you what happened after one of your quotes was selected. Use them to reconcile RFQ state, transaction hashes, and terminal execution outcomes in your own systems.- TypeScript
- Python
- API
Switch on the Event Type
First, switch on
event.type to handle execution updates from the same session
stream.Inspect the Execution Update
Then, inspect the execution update before reconciling the selected RFQ. Execution
updates are correlated by where
rfqId.RfqExecutionStatus could be:| Status | Meaning |
|---|---|
RfqExecutionStatus.Matched | The quote was selected and handed off to execute. |
RfqExecutionStatus.Mined | The execution transaction was mined. |
RfqExecutionStatus.Retrying | Execution is being retried. |
RfqExecutionStatus.Confirmed | Execution completed successfully. |
RfqExecutionStatus.Failed | Execution failed. |
Listen to Trade Broadcasts
Confirmed trade broadcasts tell connected market makers when any Combo RFQ trade has completed successfully. Use them to build a public trade tape, update risk, or reconcile market activity that was filled by another maker. Trade broadcasts are best-effort and may be replayed after reconnects. Deduplicate them by RFQ ID:rfqId in TypeScript or rfq_id in Python and raw WebSocket
messages.
- TypeScript
- Python
- API
Switch on the Event Type
First, switch on
event.type to handle trade broadcasts from the same session
stream.Inspect the Trade
Then, inspect the confirmed trade before storing or applying it. Trade broadcasts
exclude maker identity and per-maker fill allocations.
price is the accepted blended price in pUSD per YES Combo share. size is the
matched Combo share size. Both values are normalized decimal strings.Handle Errors
In this section, we will talk you through how to handle errors with the RFQ system.- TypeScript
- Python
- API
Open the RFQ Session
Wrapclient.openRfqSession() in try/catch and use
OpenRfqSessionError.isError(…) to narrow the error type.Submit a Quote
Wrapevent.quote(…) in try/catch and use RfqQuoteError.isError(…) to
narrow the error type.Cancel a Quote
Wrapsession.cancelQuote(…) in try/catch and use
RfqCancelQuoteError.isError(…) to narrow the error type.Confirm or Decline
Wrapevent.confirm() or event.decline() in try/catch and use
RfqConfirmationError.isError(…) to narrow the error type.