diff --git a/TARGET.md b/TARGET.md index 64cbbf0..6556418 100644 --- a/TARGET.md +++ b/TARGET.md @@ -7,7 +7,7 @@ https://docs.polymarket.com/quickstart.md https://docs.polymarket.com/quickstart/overview.md https://docs.polymarket.com/quickstart/fetching-data.md https://docs.polymarket.com/quickstart/first-order.md -https://docs.polymarket.com/quickstart/reference/glossary.md + https://docs.polymarket.com/quickstart/introduction/rate-limits.md https://docs.polymarket.com/quickstart/reference/endpoints.md @@ -18,6 +18,7 @@ https://docs.polymarket.com/market-makers/trading.md https://docs.polymarket.com/market-makers/liquidity-rewards.md https://docs.polymarket.com/market-makers/maker-rebates.md https://docs.polymarket.com/market-makers/inventory.md +https://docs.polymarket.com/market-makers/combos.md https://docs.polymarket.com/developers/market-makers/introduction.md https://docs.polymarket.com/developers/market-makers/setup.md https://docs.polymarket.com/developers/market-makers/data-feeds.md @@ -78,18 +79,10 @@ https://docs.polymarket.com/api-reference/market-data/get-tick-size-by-path-para https://docs.polymarket.com/api-reference/data/get-server-time.md ## API Reference - Orderbook -https://docs.polymarket.com/api-reference/orderbook/get-order-book-summary.md -https://docs.polymarket.com/api-reference/orderbook/get-multiple-order-books-summaries-by-request.md -## API Reference - Pricing (Legacy) -https://docs.polymarket.com/api-reference/pricing/get-market-price.md -https://docs.polymarket.com/api-reference/pricing/get-multiple-market-prices.md -https://docs.polymarket.com/api-reference/pricing/get-multiple-market-prices-by-request.md -https://docs.polymarket.com/api-reference/pricing/get-midpoint-price.md -https://docs.polymarket.com/api-reference/pricing/get-price-history-for-a-traded-token.md -## API Reference - Spreads -https://docs.polymarket.com/api-reference/spreads/get-bid-ask-spreads.md +## API Reference - WSS RFQ +https://docs.polymarket.com/api-reference/wss/rfq.md ## API Reference - Trade (CLOB) https://docs.polymarket.com/api-reference/trade/post-a-new-order.md @@ -157,7 +150,6 @@ https://docs.polymarket.com/developers/gamma-markets-api/gamma-structure.md https://docs.polymarket.com/developers/gamma-markets-api/fetch-markets-guide.md ## Gamma Endpoints - Status -https://docs.polymarket.com/api-reference/gamma-status/gamma-api-health-check.md ## API Reference - Sports https://docs.polymarket.com/api-reference/sports/list-teams.md @@ -210,7 +202,6 @@ https://docs.polymarket.com/api-reference/profiles/get-public-profile-by-wallet- https://docs.polymarket.com/api-reference/search/search-markets-events-and-profiles.md ## API Reference - Data API Status -https://docs.polymarket.com/api-reference/data-api-status/data-api-health-check.md ## API Reference - Misc https://docs.polymarket.com/api-reference/misc/download-an-accounting-snapshot-zip-of-csvs.md @@ -233,13 +224,13 @@ https://docs.polymarket.com/api-reference/builders/get-aggregated-builder-leader https://docs.polymarket.com/api-reference/builders/get-daily-builder-volume-time-series.md ## Bridge & Swap - Overview -https://docs.polymarket.com/trading/bridge/overview.md + https://docs.polymarket.com/developers/misc-endpoints/bridge-overview.md ## API Reference - Bridge https://docs.polymarket.com/api-reference/bridge/get-supported-assets.md https://docs.polymarket.com/api-reference/bridge/get-a-quote.md -https://docs.polymarket.com/api-reference/bridge/create-deposit-addresses.md + https://docs.polymarket.com/api-reference/bridge/create-withdrawal-addresses.md https://docs.polymarket.com/api-reference/bridge/get-transaction-status.md https://docs.polymarket.com/api-reference/bridge/create-bridge-addresses.md @@ -250,8 +241,7 @@ https://docs.polymarket.com/trading/bridge/supported-assets.md https://docs.polymarket.com/trading/bridge/withdraw.md ## Subgraph -https://docs.polymarket.com/market-data/subgraph.md -https://docs.polymarket.com/developers/subgraph/overview.md + ## Resolution https://docs.polymarket.com/developers/resolution/UMA.md diff --git a/docs/api-reference/bridge/create-deposit-addresses.md b/docs/api-reference/bridge/create-deposit-addresses.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/bridge/create-deposit-addresses.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/data-api-status/data-api-health-check.md b/docs/api-reference/data-api-status/data-api-health-check.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/data-api-status/data-api-health-check.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/gamma-status/gamma-api-health-check.md b/docs/api-reference/gamma-status/gamma-api-health-check.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/gamma-status/gamma-api-health-check.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/orderbook/get-multiple-order-books-summaries-by-request.md b/docs/api-reference/orderbook/get-multiple-order-books-summaries-by-request.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/orderbook/get-multiple-order-books-summaries-by-request.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/orderbook/get-order-book-summary.md b/docs/api-reference/orderbook/get-order-book-summary.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/orderbook/get-order-book-summary.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/pricing/get-market-price.md b/docs/api-reference/pricing/get-market-price.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/pricing/get-market-price.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/pricing/get-midpoint-price.md b/docs/api-reference/pricing/get-midpoint-price.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/pricing/get-midpoint-price.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/pricing/get-multiple-market-prices-by-request.md b/docs/api-reference/pricing/get-multiple-market-prices-by-request.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/pricing/get-multiple-market-prices-by-request.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/pricing/get-multiple-market-prices.md b/docs/api-reference/pricing/get-multiple-market-prices.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/pricing/get-multiple-market-prices.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/pricing/get-price-history-for-a-traded-token.md b/docs/api-reference/pricing/get-price-history-for-a-traded-token.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/pricing/get-price-history-for-a-traded-token.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/spreads/get-bid-ask-spreads.md b/docs/api-reference/spreads/get-bid-ask-spreads.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/api-reference/spreads/get-bid-ask-spreads.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/api-reference/wss/rfq.md b/docs/api-reference/wss/rfq.md new file mode 100644 index 0000000..c40c9b0 --- /dev/null +++ b/docs/api-reference/wss/rfq.md @@ -0,0 +1,1446 @@ +> ## Documentation Index +> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt +> Use this file to discover all available pages before exploring further. + +# Quoter Gateway + +> Authenticated WebSocket for combinatorial RFQ quoters — receive requests, submit quotes, confirm last look, and track execution. + + + +## AsyncAPI + +````yaml asyncapi-rfq.json quoter +id: quoter +title: Quoter Gateway +description: >- + Authenticated quoter channel. Send the `auth` message as the first message + within 30 seconds. The gateway broadcasts active RFQ requests, accepts signed + quotes and cancellations, issues last-look confirmation requests, and streams + execution updates. +servers: + - id: production + protocol: wss + host: combos-rfq-gateway-quoter.polymarket.com + bindings: [] + variables: [] +address: /ws/rfq +parameters: [] +bindings: [] +operations: + - &ref_4 + id: authenticate + title: Authenticate + description: Authenticate the connection (send as the first message) + type: receive + messages: + - &ref_16 + id: auth + contentType: application/json + payload: + - name: Auth + description: Authenticate the connection + type: object + properties: + - name: type + type: string + description: auth + required: true + - name: auth + type: object + description: CLOB API credentials. + required: true + properties: + - name: apiKey + type: string + description: CLOB API key. + required: true + - name: secret + type: string + description: CLOB API secret. + required: true + - name: passphrase + type: string + description: CLOB API passphrase. + required: true + - name: identity + type: object + description: Signer/maker identity used for RFQ orders. + required: true + properties: + - name: signer_address + type: string + description: Address that signs orders. + required: true + - name: maker_address + type: string + description: Wallet that funds orders. + required: true + - name: signature_type + type: integer + description: >- + CLOB signature type: 0 EOA, 1 POLY_PROXY, 2 GNOSIS_SAFE, 3 + POLY_1271. + enumValues: + - 0 + - 1 + - 2 + - 3 + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Authentication message. Must be the first message after connecting. + required: + - type + - auth + - identity + properties: + type: + type: string + const: auth + x-parser-schema-id: + auth: + type: object + description: CLOB API credentials. + required: + - apiKey + - secret + - passphrase + properties: + apiKey: + type: string + description: CLOB API key. + x-parser-schema-id: + secret: + type: string + description: CLOB API secret. + x-parser-schema-id: + passphrase: + type: string + description: CLOB API passphrase. + x-parser-schema-id: + x-parser-schema-id: + identity: + type: object + description: Signer/maker identity used for RFQ orders. + required: + - signer_address + - maker_address + - signature_type + properties: + signer_address: + type: string + description: Address that signs orders. + x-parser-schema-id: + maker_address: + type: string + description: Wallet that funds orders. + x-parser-schema-id: + signature_type: &ref_1 + type: integer + description: >- + CLOB signature type: 0 EOA, 1 POLY_PROXY, 2 GNOSIS_SAFE, 3 + POLY_1271. + enum: + - 0 + - 1 + - 2 + - 3 + x-parser-schema-id: SignatureType + x-parser-schema-id: + x-parser-schema-id: AuthMessage + title: Auth + description: Authenticate the connection + example: |- + { + "type": "auth", + "auth": { + "apiKey": "YOUR_API_KEY", + "secret": "YOUR_API_SECRET", + "passphrase": "YOUR_API_PASSPHRASE" + }, + "identity": { + "signer_address": "0xYourSigner", + "maker_address": "0xYourQuoterWallet", + "signature_type": 0 + } + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: auth + bindings: [] + extensions: &ref_0 + - id: x-parser-unique-object-id + value: quoter + - &ref_8 + id: authResult + title: Auth Result + description: Gateway response to the auth message + type: send + messages: + - &ref_20 + id: authResponse + contentType: application/json + payload: + - name: Auth Response + description: Gateway response to the auth message + type: object + properties: + - name: type + type: string + description: auth + required: true + - name: success + type: boolean + required: true + - name: address + type: string + description: Authenticated address, present on success. + required: false + - name: error + type: string + description: Error detail, present on failure. + required: false + headers: [] + jsonPayloadSchema: + type: object + description: Gateway response to the auth message. + required: + - type + - success + properties: + type: + type: string + const: auth + x-parser-schema-id: + success: + type: boolean + x-parser-schema-id: + address: + type: string + description: Authenticated address, present on success. + x-parser-schema-id: + error: + type: string + description: Error detail, present on failure. + x-parser-schema-id: + x-parser-schema-id: AuthResponse + title: Auth Response + description: Gateway response to the auth message + example: |- + { + "type": "auth", + "success": true, + "address": "0xAuthenticatedAddress" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: authResponse + bindings: [] + extensions: *ref_0 + - &ref_9 + id: receiveRfqRequest + title: RFQ Request + description: Broadcast of an active RFQ request to quote + type: send + messages: + - &ref_21 + id: rfqRequest + contentType: application/json + payload: + - name: RFQ_REQUEST + description: Broadcast of an active RFQ request + type: object + properties: + - name: type + type: string + description: RFQ_REQUEST + required: true + - name: rfq_id + type: string + description: Server-assigned RFQ ID. + required: true + - name: requestor_public_id + type: string + description: Opaque public ID for the RFQ source. + required: true + - name: leg_position_ids + type: array + description: Canonical leg position IDs in the combo. + required: true + properties: + - name: item + type: string + required: false + - name: condition_id + type: string + description: Derived combinatorial condition ID. + required: true + - name: yes_position_id + type: string + description: Derived YES combo position ID. + required: true + - name: no_position_id + type: string + description: Derived NO combo position ID. + required: true + - name: direction + type: string + description: Requester trade direction. + enumValues: + - BUY + - SELL + required: true + - name: side + type: string + description: Combinatorial position side. Currently only YES is supported. + enumValues: + - 'YES' + - 'NO' + required: true + - name: requested_size + type: object + description: Requested RFQ size and unit. + required: true + properties: + - name: unit + type: string + description: >- + `notional` for requester BUY RFQs and `shares` for + requester SELL RFQs. + enumValues: + - notional + - shares + required: true + - name: value_e6 + type: string + description: Six-decimal fixed-point value encoded as a string. + required: true + - name: submission_deadline + type: integer + description: Quote submission deadline in Unix milliseconds. + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Broadcast of an active RFQ request. + required: + - type + - rfq_id + - requestor_public_id + - leg_position_ids + - condition_id + - yes_position_id + - no_position_id + - direction + - side + - requested_size + - submission_deadline + properties: + type: + type: string + const: RFQ_REQUEST + x-parser-schema-id: + rfq_id: + type: string + description: Server-assigned RFQ ID. + x-parser-schema-id: + requestor_public_id: + type: string + description: Opaque public ID for the RFQ source. + x-parser-schema-id: + leg_position_ids: + type: array + description: Canonical leg position IDs in the combo. + items: + type: string + x-parser-schema-id: + x-parser-schema-id: + condition_id: + type: string + description: Derived combinatorial condition ID. + x-parser-schema-id: + yes_position_id: + type: string + description: Derived YES combo position ID. + x-parser-schema-id: + no_position_id: + type: string + description: Derived NO combo position ID. + x-parser-schema-id: + direction: &ref_2 + type: string + description: Requester trade direction. + enum: + - BUY + - SELL + x-parser-schema-id: Direction + side: &ref_3 + type: string + description: Combinatorial position side. Currently only YES is supported. + enum: + - 'YES' + - 'NO' + x-parser-schema-id: Side + requested_size: + type: object + description: Requested RFQ size and unit. + required: + - unit + - value_e6 + properties: + unit: + type: string + description: >- + `notional` for requester BUY RFQs and `shares` for requester + SELL RFQs. + enum: + - notional + - shares + x-parser-schema-id: + value_e6: + type: string + description: Six-decimal fixed-point value encoded as a string. + x-parser-schema-id: + x-parser-schema-id: RequestedSize + submission_deadline: + type: integer + format: int64 + description: Quote submission deadline in Unix milliseconds. + x-parser-schema-id: + x-parser-schema-id: RfqRequest + title: RFQ_REQUEST + description: Broadcast of an active RFQ request + example: |- + { + "type": "RFQ_REQUEST", + "rfq_id": "rfq_", + "requestor_public_id": "req_", + "leg_position_ids": [ + "", + "" + ], + "condition_id": "0x", + "yes_position_id": "", + "no_position_id": "", + "direction": "BUY", + "side": "YES", + "requested_size": { + "unit": "notional", + "value_e6": "1000000" + }, + "submission_deadline": 1780575184000 + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: rfqRequest + bindings: [] + extensions: *ref_0 + - &ref_5 + id: submitQuote + title: Submit Quote + description: Submit a signed maker quote before the submission deadline + type: receive + messages: + - &ref_17 + id: rfqQuote + contentType: application/json + payload: + - name: RFQ_QUOTE + description: Submit a signed maker quote + type: object + properties: + - name: type + type: string + description: RFQ_QUOTE + required: true + - name: rfq_id + type: string + description: RFQ ID from RFQ_REQUEST. + required: true + - name: price_e6 + type: string + description: Quote price in six-decimal fixed-point units. + required: true + - name: size_e6 + type: string + description: Fillable share count in six-decimal fixed-point units. + required: true + - name: signed_order + type: object + description: Signed Exchange v3 order. + required: true + properties: + - name: salt + type: string + description: Order salt (uint256 as a decimal string). + required: true + - name: maker + type: string + description: Wallet that funds the order. + required: true + - name: signer + type: string + description: Address that signs the order. + required: true + - name: tokenId + type: string + description: YES or NO combo position ID (uint256 as a decimal string). + required: true + - name: makerAmount + type: string + description: Amount the maker pays, in six-decimal base units. + required: true + - name: takerAmount + type: string + description: Amount the maker receives, in six-decimal base units. + required: true + - name: side + type: integer + description: Order side — 0 BUY, 1 SELL. + enumValues: + - 0 + - 1 + required: true + - name: signatureType + type: integer + description: >- + CLOB signature type: 0 EOA, 1 POLY_PROXY, 2 GNOSIS_SAFE, 3 + POLY_1271. + enumValues: + - 0 + - 1 + - 2 + - 3 + required: true + - name: timestamp + type: string + description: Order timestamp in Unix seconds (as a string). + required: true + - name: metadata + type: string + description: 32-byte hex field; defaults to the zero value. + required: false + - name: builder + type: string + description: 32-byte hex field; defaults to the zero value. + required: false + - name: signature + type: string + description: EIP-712 signature over the order. + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Submit a signed maker quote before the submission deadline. + required: + - type + - rfq_id + - price_e6 + - size_e6 + - signed_order + properties: + type: + type: string + const: RFQ_QUOTE + x-parser-schema-id: + rfq_id: + type: string + description: RFQ ID from RFQ_REQUEST. + x-parser-schema-id: + price_e6: + type: string + description: Quote price in six-decimal fixed-point units. + x-parser-schema-id: + size_e6: + type: string + description: Fillable share count in six-decimal fixed-point units. + x-parser-schema-id: + signed_order: + type: object + description: Signed Exchange v3 order. + required: + - salt + - maker + - signer + - tokenId + - makerAmount + - takerAmount + - side + - signatureType + - timestamp + - signature + properties: + salt: + type: string + description: Order salt (uint256 as a decimal string). + x-parser-schema-id: + maker: + type: string + description: Wallet that funds the order. + x-parser-schema-id: + signer: + type: string + description: Address that signs the order. + x-parser-schema-id: + tokenId: + type: string + description: YES or NO combo position ID (uint256 as a decimal string). + x-parser-schema-id: + makerAmount: + type: string + description: Amount the maker pays, in six-decimal base units. + x-parser-schema-id: + takerAmount: + type: string + description: Amount the maker receives, in six-decimal base units. + x-parser-schema-id: + side: + type: integer + description: Order side — 0 BUY, 1 SELL. + enum: + - 0 + - 1 + x-parser-schema-id: + signatureType: *ref_1 + timestamp: + type: string + description: Order timestamp in Unix seconds (as a string). + x-parser-schema-id: + metadata: + type: string + description: 32-byte hex field; defaults to the zero value. + x-parser-schema-id: + builder: + type: string + description: 32-byte hex field; defaults to the zero value. + x-parser-schema-id: + signature: + type: string + description: EIP-712 signature over the order. + x-parser-schema-id: + x-parser-schema-id: ExchangeV3Order + x-parser-schema-id: RfqQuote + title: RFQ_QUOTE + description: Submit a signed maker quote + example: |- + { + "type": "RFQ_QUOTE", + "rfq_id": "rfq_", + "price_e6": "450000", + "size_e6": "1000000", + "signed_order": { + "salt": "", + "maker": "0xYourQuoterWallet", + "signer": "0xYourSigner", + "tokenId": "", + "makerAmount": "", + "takerAmount": "", + "side": 0, + "signatureType": 0, + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x..." + } + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: rfqQuote + bindings: [] + extensions: *ref_0 + - &ref_10 + id: acknowledgeQuote + title: Quote Ack + description: Returns the server-generated quote ID + type: send + messages: + - &ref_22 + id: ackRfqQuote + contentType: application/json + payload: + - name: ACK_RFQ_QUOTE + description: Returns the server-generated quote ID + type: object + properties: + - name: type + type: string + description: ACK_RFQ_QUOTE + required: true + - name: rfq_id + type: string + required: true + - name: quote_id + type: string + description: Server-generated quote ID. + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Returns the server-generated quote ID. + required: + - type + - rfq_id + - quote_id + properties: + type: + type: string + const: ACK_RFQ_QUOTE + x-parser-schema-id: + rfq_id: + type: string + x-parser-schema-id: + quote_id: + type: string + description: Server-generated quote ID. + x-parser-schema-id: + x-parser-schema-id: AckRfqQuote + title: ACK_RFQ_QUOTE + description: Returns the server-generated quote ID + example: |- + { + "type": "ACK_RFQ_QUOTE", + "rfq_id": "rfq_", + "quote_id": "quote_" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: ackRfqQuote + bindings: [] + extensions: *ref_0 + - &ref_6 + id: cancelQuote + title: Cancel Quote + description: Cancel an active maker quote before it is selected + type: receive + messages: + - &ref_18 + id: rfqQuoteCancel + contentType: application/json + payload: + - name: RFQ_QUOTE_CANCEL + description: Cancel an active maker quote + type: object + properties: + - name: type + type: string + description: RFQ_QUOTE_CANCEL + required: true + - name: rfq_id + type: string + required: true + - name: quote_id + type: string + description: Server-generated quote ID. + required: true + - name: signer_address + type: string + description: Must match the authenticated signer_address. + required: true + - name: maker_address + type: string + description: Must match the authenticated maker_address. + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Cancel an active maker quote before it is selected. + required: + - type + - rfq_id + - quote_id + - signer_address + - maker_address + properties: + type: + type: string + const: RFQ_QUOTE_CANCEL + x-parser-schema-id: + rfq_id: + type: string + x-parser-schema-id: + quote_id: + type: string + description: Server-generated quote ID. + x-parser-schema-id: + signer_address: + type: string + description: Must match the authenticated signer_address. + x-parser-schema-id: + maker_address: + type: string + description: Must match the authenticated maker_address. + x-parser-schema-id: + x-parser-schema-id: RfqQuoteCancel + title: RFQ_QUOTE_CANCEL + description: Cancel an active maker quote + example: |- + { + "type": "RFQ_QUOTE_CANCEL", + "rfq_id": "rfq_", + "quote_id": "quote_", + "signer_address": "0xYourSigner", + "maker_address": "0xYourQuoterWallet" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: rfqQuoteCancel + bindings: [] + extensions: *ref_0 + - &ref_11 + id: acknowledgeQuoteCancel + title: Quote Cancel Ack + description: Confirms quote cancellation + type: send + messages: + - &ref_23 + id: ackRfqQuoteCancel + contentType: application/json + payload: + - name: ACK_RFQ_QUOTE_CANCEL + description: Confirms quote cancellation + type: object + properties: + - name: type + type: string + description: ACK_RFQ_QUOTE_CANCEL + required: true + - name: rfq_id + type: string + required: true + - name: quote_id + type: string + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Confirms quote cancellation. + required: + - type + - rfq_id + - quote_id + properties: + type: + type: string + const: ACK_RFQ_QUOTE_CANCEL + x-parser-schema-id: + rfq_id: + type: string + x-parser-schema-id: + quote_id: + type: string + x-parser-schema-id: + x-parser-schema-id: AckRfqQuoteCancel + title: ACK_RFQ_QUOTE_CANCEL + description: Confirms quote cancellation + example: |- + { + "type": "ACK_RFQ_QUOTE_CANCEL", + "rfq_id": "rfq_", + "quote_id": "quote_" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: ackRfqQuoteCancel + bindings: [] + extensions: *ref_0 + - &ref_12 + id: receiveConfirmationRequest + title: Confirmation Request + description: Last-look confirmation request for a selected quote + type: send + messages: + - &ref_24 + id: rfqConfirmationRequest + contentType: application/json + payload: + - name: RFQ_CONFIRMATION_REQUEST + description: Last-look confirmation request for a selected quote + type: object + properties: + - name: type + type: string + description: RFQ_CONFIRMATION_REQUEST + required: true + - name: rfq_id + type: string + required: true + - name: quote_id + type: string + description: Selected quote ID. + required: true + - name: signer_address + type: string + required: true + - name: maker_address + type: string + required: true + - name: signature_type + type: integer + description: >- + CLOB signature type: 0 EOA, 1 POLY_PROXY, 2 GNOSIS_SAFE, 3 + POLY_1271. + enumValues: + - 0 + - 1 + - 2 + - 3 + required: true + - name: leg_position_ids + type: array + required: true + properties: + - name: item + type: string + required: false + - name: condition_id + type: string + required: true + - name: yes_position_id + type: string + required: true + - name: no_position_id + type: string + required: true + - name: direction + type: string + description: Requester trade direction. + enumValues: + - BUY + - SELL + required: true + - name: side + type: string + description: Combinatorial position side. Currently only YES is supported. + enumValues: + - 'YES' + - 'NO' + required: true + - name: fill_size_e6 + type: string + description: Selected fill size in six-decimal fixed-point units. + required: true + - name: price_e6 + type: string + description: Selected quote price in six-decimal fixed-point units. + required: true + - name: confirm_by + type: integer + description: Confirmation deadline in Unix milliseconds. + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Last-look confirmation request for a selected quote. + required: + - type + - rfq_id + - quote_id + - signer_address + - maker_address + - signature_type + - leg_position_ids + - condition_id + - yes_position_id + - no_position_id + - direction + - side + - fill_size_e6 + - price_e6 + - confirm_by + properties: + type: + type: string + const: RFQ_CONFIRMATION_REQUEST + x-parser-schema-id: + rfq_id: + type: string + x-parser-schema-id: + quote_id: + type: string + description: Selected quote ID. + x-parser-schema-id: + signer_address: + type: string + x-parser-schema-id: + maker_address: + type: string + x-parser-schema-id: + signature_type: *ref_1 + leg_position_ids: + type: array + items: + type: string + x-parser-schema-id: + x-parser-schema-id: + condition_id: + type: string + x-parser-schema-id: + yes_position_id: + type: string + x-parser-schema-id: + no_position_id: + type: string + x-parser-schema-id: + direction: *ref_2 + side: *ref_3 + fill_size_e6: + type: string + description: Selected fill size in six-decimal fixed-point units. + x-parser-schema-id: + price_e6: + type: string + description: Selected quote price in six-decimal fixed-point units. + x-parser-schema-id: + confirm_by: + type: integer + format: int64 + description: Confirmation deadline in Unix milliseconds. + x-parser-schema-id: + x-parser-schema-id: RfqConfirmationRequest + title: RFQ_CONFIRMATION_REQUEST + description: Last-look confirmation request for a selected quote + example: |- + { + "type": "RFQ_CONFIRMATION_REQUEST", + "rfq_id": "rfq_", + "quote_id": "quote_", + "signer_address": "0xYourSigner", + "maker_address": "0xYourQuoterWallet", + "signature_type": 0, + "leg_position_ids": [ + "", + "" + ], + "condition_id": "0x", + "yes_position_id": "", + "no_position_id": "", + "direction": "BUY", + "side": "YES", + "fill_size_e6": "1000000", + "price_e6": "450000", + "confirm_by": 1780575184000 + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: rfqConfirmationRequest + bindings: [] + extensions: *ref_0 + - &ref_7 + id: respondConfirmation + title: Confirmation Response + description: Confirm or decline a selected quote during last look + type: receive + messages: + - &ref_19 + id: rfqConfirmationResponse + contentType: application/json + payload: + - name: RFQ_CONFIRMATION_RESPONSE + description: Confirm or decline a selected quote + type: object + properties: + - name: type + type: string + description: RFQ_CONFIRMATION_RESPONSE + required: true + - name: rfq_id + type: string + required: true + - name: quote_id + type: string + description: Selected quote ID. + required: true + - name: decision + type: string + enumValues: + - CONFIRM + - DECLINE + required: true + headers: [] + jsonPayloadSchema: + type: object + description: >- + Confirm or decline a selected quote. Identity is applied from the + authenticated session. + required: + - type + - rfq_id + - quote_id + - decision + properties: + type: + type: string + const: RFQ_CONFIRMATION_RESPONSE + x-parser-schema-id: + rfq_id: + type: string + x-parser-schema-id: + quote_id: + type: string + description: Selected quote ID. + x-parser-schema-id: + decision: + type: string + enum: + - CONFIRM + - DECLINE + x-parser-schema-id: + x-parser-schema-id: RfqConfirmationResponse + title: RFQ_CONFIRMATION_RESPONSE + description: Confirm or decline a selected quote + example: |- + { + "type": "RFQ_CONFIRMATION_RESPONSE", + "rfq_id": "rfq_", + "quote_id": "quote_", + "decision": "CONFIRM" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: rfqConfirmationResponse + bindings: [] + extensions: *ref_0 + - &ref_13 + id: acknowledgeConfirmation + title: Confirmation Ack + description: Confirms the maker's last-look response + type: send + messages: + - &ref_25 + id: ackRfqConfirmationResponse + contentType: application/json + payload: + - name: ACK_RFQ_CONFIRMATION_RESPONSE + description: Confirms the maker's last-look response + type: object + properties: + - name: type + type: string + description: ACK_RFQ_CONFIRMATION_RESPONSE + required: true + - name: rfq_id + type: string + required: true + - name: quote_id + type: string + required: true + - name: decision + type: string + enumValues: + - CONFIRM + - DECLINE + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Confirms the maker's last-look response. + required: + - type + - rfq_id + - quote_id + - decision + properties: + type: + type: string + const: ACK_RFQ_CONFIRMATION_RESPONSE + x-parser-schema-id: + rfq_id: + type: string + x-parser-schema-id: + quote_id: + type: string + x-parser-schema-id: + decision: + type: string + enum: + - CONFIRM + - DECLINE + x-parser-schema-id: + x-parser-schema-id: AckRfqConfirmationResponse + title: ACK_RFQ_CONFIRMATION_RESPONSE + description: Confirms the maker's last-look response + example: |- + { + "type": "ACK_RFQ_CONFIRMATION_RESPONSE", + "rfq_id": "rfq_", + "quote_id": "quote_", + "decision": "CONFIRM" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: ackRfqConfirmationResponse + bindings: [] + extensions: *ref_0 + - &ref_14 + id: receiveExecutionUpdate + title: Execution Update + description: Execution progress for selected makers + type: send + messages: + - &ref_26 + id: rfqExecutionUpdate + contentType: application/json + payload: + - name: RFQ_EXECUTION_UPDATE + description: Execution progress for selected makers + type: object + properties: + - name: type + type: string + description: RFQ_EXECUTION_UPDATE + required: true + - name: rfq_id + type: string + required: true + - name: status + type: string + enumValues: + - MATCHED + - MINED + - RETRYING + - CONFIRMED + - FAILED + required: true + - name: tx_hash + type: string + description: Transaction hash, when available. + required: false + headers: [] + jsonPayloadSchema: + type: object + description: >- + Reports execution progress for selected makers. CONFIRMED and FAILED + are terminal. + required: + - type + - rfq_id + - status + properties: + type: + type: string + const: RFQ_EXECUTION_UPDATE + x-parser-schema-id: + rfq_id: + type: string + x-parser-schema-id: + status: + type: string + enum: + - MATCHED + - MINED + - RETRYING + - CONFIRMED + - FAILED + x-parser-schema-id: + tx_hash: + type: string + description: Transaction hash, when available. + x-parser-schema-id: + x-parser-schema-id: RfqExecutionUpdate + title: RFQ_EXECUTION_UPDATE + description: Execution progress for selected makers + example: |- + { + "type": "RFQ_EXECUTION_UPDATE", + "rfq_id": "rfq_", + "status": "MINED", + "tx_hash": "0x" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: rfqExecutionUpdate + bindings: [] + extensions: *ref_0 + - &ref_15 + id: receiveError + title: Error + description: Sent when a command fails validation or cannot be applied + type: send + messages: + - &ref_27 + id: rfqError + contentType: application/json + payload: + - name: RFQ_ERROR + description: Sent when a command fails validation or cannot be applied + type: object + properties: + - name: type + type: string + description: RFQ_ERROR + required: true + - name: request_type + type: string + description: Inbound command that failed, when parsed. + required: false + - name: rfq_id + type: string + description: RFQ ID, when present on the failed command. + required: false + - name: quote_id + type: string + description: Quote ID, when present on the failed command. + required: false + - name: code + type: string + description: Stable machine-readable error code. + enumValues: + - ADDRESS_MISMATCH + - ALLOWANCE_VALIDATION_FAILED + - BALANCE_VALIDATION_FAILED + - CONTRADICTORY_LEGS + - EXPIRED_RFQ + - INVALID_ACCEPTANCE + - INVALID_CONFIRMATION + - INVALID_EXECUTION_RESULT + - INVALID_IDENTITY + - INVALID_MESSAGE + - INVALID_QUOTE + - INVALID_RFQ + - INVALID_RFQ_STATE + - INVALID_ROLE + - LEG_METADATA_UNAVAILABLE + - MAKER_ALREADY_RESPONDED + - MAKER_NOT_REQUIRED + - PRE_EXECUTION_BALANCE_RESERVATION_FAILED + - QUOTE_MISMATCH + - QUOTE_UNAVAILABLE + - RATE_LIMITED + - REQUEST_FAILED + - SERVICE_UNAVAILABLE + - SUBMISSION_WINDOW_CLOSED + - TRADE_SUBMISSION_FAILED + - UNAUTHENTICATED + - UNAUTHORIZED_ROLE + - UNKNOWN_RFQ + required: true + - name: error + type: string + description: Human-readable error detail for logging and debugging. + required: true + headers: [] + jsonPayloadSchema: + type: object + description: Sent when a command fails validation or cannot be applied. + required: + - type + - code + - error + properties: + type: + type: string + const: RFQ_ERROR + x-parser-schema-id: + request_type: + type: string + description: Inbound command that failed, when parsed. + x-parser-schema-id: + rfq_id: + type: string + description: RFQ ID, when present on the failed command. + x-parser-schema-id: + quote_id: + type: string + description: Quote ID, when present on the failed command. + x-parser-schema-id: + code: + type: string + description: Stable machine-readable error code. + enum: + - ADDRESS_MISMATCH + - ALLOWANCE_VALIDATION_FAILED + - BALANCE_VALIDATION_FAILED + - CONTRADICTORY_LEGS + - EXPIRED_RFQ + - INVALID_ACCEPTANCE + - INVALID_CONFIRMATION + - INVALID_EXECUTION_RESULT + - INVALID_IDENTITY + - INVALID_MESSAGE + - INVALID_QUOTE + - INVALID_RFQ + - INVALID_RFQ_STATE + - INVALID_ROLE + - LEG_METADATA_UNAVAILABLE + - MAKER_ALREADY_RESPONDED + - MAKER_NOT_REQUIRED + - PRE_EXECUTION_BALANCE_RESERVATION_FAILED + - QUOTE_MISMATCH + - QUOTE_UNAVAILABLE + - RATE_LIMITED + - REQUEST_FAILED + - SERVICE_UNAVAILABLE + - SUBMISSION_WINDOW_CLOSED + - TRADE_SUBMISSION_FAILED + - UNAUTHENTICATED + - UNAUTHORIZED_ROLE + - UNKNOWN_RFQ + x-parser-schema-id: + error: + type: string + description: Human-readable error detail for logging and debugging. + x-parser-schema-id: + x-parser-schema-id: RfqError + title: RFQ_ERROR + description: Sent when a command fails validation or cannot be applied + example: |- + { + "type": "RFQ_ERROR", + "request_type": "RFQ_QUOTE", + "rfq_id": "rfq_", + "code": "SUBMISSION_WINDOW_CLOSED", + "error": "submission window closed" + } + bindings: [] + extensions: + - id: x-parser-unique-object-id + value: rfqError + bindings: [] + extensions: *ref_0 +sendOperations: + - *ref_4 + - *ref_5 + - *ref_6 + - *ref_7 +receiveOperations: + - *ref_8 + - *ref_9 + - *ref_10 + - *ref_11 + - *ref_12 + - *ref_13 + - *ref_14 + - *ref_15 +sendMessages: + - *ref_16 + - *ref_17 + - *ref_18 + - *ref_19 +receiveMessages: + - *ref_20 + - *ref_21 + - *ref_22 + - *ref_23 + - *ref_24 + - *ref_25 + - *ref_26 + - *ref_27 +extensions: + - id: x-parser-unique-object-id + value: quoter +securitySchemes: [] + +```` \ No newline at end of file diff --git a/docs/developers/subgraph/overview.md b/docs/developers/subgraph/overview.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/developers/subgraph/overview.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/market-data/subgraph.md b/docs/market-data/subgraph.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/market-data/subgraph.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/market-makers/combos.md b/docs/market-makers/combos.md new file mode 100644 index 0000000..03d333a --- /dev/null +++ b/docs/market-makers/combos.md @@ -0,0 +1,3405 @@ +> ## Documentation Index +> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt +> Use this file to discover all available pages before exploring further. + +# Combos + +> Build a market maker integration for pricing and executing Combos + +Combos are multi-leg positions that combine multiple underlying market outcomes +into one YES or NO position. Each Combo is defined by its legs and identified by +derived YES and NO position IDs. + +The request for quote (RFQ) system enables quote-based Combo execution between +two participants: Polymarket users (requesters) and market makers (quoters). A +user creates a Request, which starts an auction among connected market makers. +Market makers compete by submitting Quotes: executable prices they are willing to +fill. + +```mermaid theme={null} +sequenceDiagram + autonumber + participant Requester as Polymarket User + participant RFQ as RFQ System + participant Quoter as Market Maker + participant Execution as Execution + + Requester->>RFQ: Request a Combo price + RFQ->>Quoter: Send quote request + activate Quoter + Note right of Quoter: 400 ms max + Quoter->>RFQ: Submit executable price + deactivate Quoter + RFQ->>Requester: Return best quote + activate Requester + Note left of Requester: 10 seconds max + Requester->>RFQ: Accept quote + deactivate Requester + opt Last Look enabled + RFQ->>Quoter: Request Last Look confirmation + activate Quoter + Note right of Quoter: 1 second max + Quoter->>RFQ: Confirm fill + deactivate Quoter + end + RFQ->>Execution: Execute accepted Combo + Execution-->>Requester: Send execution update + Execution-->>Quoter: Send execution update +``` + +1. **User creates an unsigned Request** for a Combo price. +2. **RFQ system sends the Request** to connected market makers. +3. **Market makers submit signed Quotes** within the 400 ms submission window. +4. **RFQ system returns the best Quote** to the user. +5. **User accepts the Quote** by signing the trade within the 10-second + acceptance window. +6. **RFQ system requests Last Look confirmation** when Last Look is enabled. +7. **Market maker confirms or declines** within the 1-second confirmation window. +8. **RFQ system executes the accepted Combo**. +9. **User receives execution updates**. +10. **Market maker receives execution updates**. + + + 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. + + +This guide shows market makers how to handle Combo RFQs. You will open a quoting +session, respond to incoming requests, cancel submitted quotes when needed, +confirm fills through Last Look, and monitor execution updates. + +## Start Quoting + +Start by preparing an authenticated quoting session with the RFQ system. You +need a Polymarket account; create one at [polymarket.com](https://polymarket.com). + + + + + + Install the Unified TypeScript SDK with the package manager of your choice. + + + ```bash pnpm theme={null} + pnpm add @polymarket/client@beta viem + ``` + + ```bash npm theme={null} + npm install @polymarket/client@beta viem + ``` + + ```bash yarn theme={null} + yarn add @polymarket/client@beta viem + ``` + + + + This page uses Viem for wallet signing. See the [TypeScript tooling + guide](/dev-tooling/typescript) for other wallet library integrations. + + + + + Create an instance of `SecureClient` with a wallet that has funds for fulfilling + user requests and its signer details. + + ```ts theme={null} + import { createSecureClient, relayerApiKey } from "@polymarket/client"; + import { privateKey } from "@polymarket/client/viem"; + + const client = await createSecureClient({ + wallet: process.env.POLYMARKET_WALLET_ADDRESS!, + signer: privateKey(process.env.PRIVATE_KEY!), + apiKey: relayerApiKey({ + key: process.env.RELAYER_API_KEY!, + address: process.env.RELAYER_API_KEY_ADDRESS!, + }), + }); + ``` + + The Relayer API key is necessary for setting up trading approvals in the next + step. Create a [Relayer API key](https://polymarket.com/settings?tab=api-keys) + from Settings > API Keys. + + + + Set up the approvals required to fill user requests. + + ```ts theme={null} + await client.setupTradingApprovals(); + ``` + + + + Open the RFQ session. + + ```ts theme={null} + const session = await client.openRfqSession(); + + for await (const event of session) { + // event: RfqEvent + } + ``` + + + + You can close the session at any time by calling `session.close()`. + + ```ts theme={null} + for await (const event of session) { + if (shouldCloseSession) { + await session.close(); + break; + } + + // … + } + ``` + + + + + + + + Install the Python SDK with the package manager of your choice. + + + ```bash uv theme={null} + uv add polymarket-client + ``` + + ```bash pip theme={null} + pip install polymarket-client + ``` + + ```bash poetry theme={null} + poetry add polymarket-client + ``` + + + + + Create an `AsyncSecureClient` with a wallet that has funds for fulfilling user + requests and its signer details. + + ```python theme={null} + import os + + from polymarket import AsyncSecureClient, RelayerApiKey + + + client = await AsyncSecureClient.create( + private_key=os.environ["PRIVATE_KEY"], + wallet=os.environ["POLYMARKET_WALLET_ADDRESS"], + api_key=RelayerApiKey( + key=os.environ["RELAYER_API_KEY"], + address=os.environ["RELAYER_API_KEY_ADDRESS"], + ), + ) + ``` + + The Relayer API key is necessary for setting up trading approvals in the next + step. Create a [Relayer API key](https://polymarket.com/settings?tab=api-keys) + from Settings > API Keys. + + + + Set up the approvals required to fill user requests. + + ```python theme={null} + await client.setup_trading_approvals() + ``` + + + + Open the RFQ session. + + ```python theme={null} + async with client.open_rfq_session() as session: + async for event in session: + # event: RfqEvent + ... + ``` + + + + You can close the session at any time by calling `await session.close()`. + + ```python theme={null} + async with client.open_rfq_session() as session: + async for event in session: + if should_close_session: + await session.close() + break + + ... + ``` + + + + + + + Use Polygon mainnet chain ID `137` for CLOB authentication and Exchange v3 + order signing. + + + + + Connect to the RFQ system WebSocket. + + ```text theme={null} + wss://combos-rfq-gateway-quoter.polymarket.com/ws/rfq + ``` + + To inspect the stream before integrating: + + ```bash theme={null} + wscat -c "wss://combos-rfq-gateway-quoter.polymarket.com/ws/rfq" + ``` + + Some write operations are also available through the REST API. + + ```text theme={null} + https://combos-rfq-api.polymarket.com + ``` + + + + RFQ WebSocket authentication uses CLOB API credentials: API key, secret, and + passphrase. If you need credentials, start with [Getting API + Credentials](/api-reference/authentication#using-the-rest-api). + + + + Resolve the order signer identity before sending `auth`. The RFQ system needs + the address that signs the order, the wallet that funds the order, and the + signature type that connects those two addresses. + + | Wallet Type | `signature_type` | `signer_address` | `maker_address` | + | -------------- | ---------------- | ----------------------------- | -------------------- | + | Deposit Wallet | `3` POLY\_1271 | Deposit wallet address | Deposit wallet | + | Safe Wallet | `2` Safe | Authenticated signing address | Derived Safe wallet | + | Poly Proxy | `1` Proxy | Authenticated signing address | Derived proxy wallet | + | EOA | `0` EOA | EOA address | Same EOA address | + + For more detail, see [Signature Types and + Funder](/api-reference/authentication#signature-types-and-funder). + + + + Send `auth` as the first WebSocket message within 30 seconds. Include the CLOB + credentials and the `signer_address`, `maker_address`, and `signature_type` + values resolved in the previous step. This example uses a Deposit Wallet. + + ```json theme={null} + { + "type": "auth", + "auth": { + "apiKey": "YOUR_API_KEY", + "secret": "YOUR_API_SECRET", + "passphrase": "YOUR_API_PASSPHRASE" + }, + "identity": { + "signer_address": "", + "maker_address": "", + "signature_type": 3 // + } + } + ``` + + Authentication returns a success or failure response. + + + ```json Success theme={null} + { + "type": "auth", + "success": true, + "address": "0xAuthenticatedAddress", + "role": "maker" + } + ``` + + ```json Failure theme={null} + { + "type": "auth", + "success": false, + "error": "unauthenticated" + } + ``` + + + + The RFQ system uses WebSocket protocol heartbeat frames to keep the connection + alive. It sends a ping frame every 30 seconds with payload `rfq`; your client + must respond with a pong frame that echoes the same payload. Most WebSocket + clients handle this automatically. These are protocol frames, not JSON + messages in the RFQ event stream. The gateway closes stale connections after 2 + minutes without an inbound message or pong. + + + + + Before posting quotes, `maker_address` must approve the contracts that may + transfer assets during RFQ execution. + + | Approval | Required when | Contract call | + | --------------------------- | --------------------------------------------- | ------------------------------------------------------- | + | pUSD collateral | The quoted order transfers pUSD | `CollateralToken.approve(ExchangeV3, maxUint256)` | + | Combo positions | The quoted order transfers Combo positions | `PositionManager.setApprovalForAll(ExchangeV3, true)` | + | AutoRedeemer Combo operator | You want automatic redemption flows to use it | `PositionManager.setApprovalForAll(AutoRedeemer, true)` | + + Use these contract addresses to build the approval calls. + + | Contract | Address | + | --------------------- | -------------------------------------------- | + | pUSD collateral token | `0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB` | + | Exchange v3 | `0xe3333700cA9d93003F00f0F71f8515005F6c00Aa` | + | PositionManager | `0x006F54F7f9A22e0000CC2AB60031000000ae9fEF` | + | AutoRedeemer | `0xa1200000d0002264C9a1698e001292D00E1b00af` | + + + The following steps show the Deposit Wallet + [batch](/trading/deposit-wallets#submit-a-deposit-wallet-batch) path. If you + are trading with an EOA, submit the approvals directly from `maker_address`. + For Safe or Poly Proxy wallet flows, use an SDK. + + + + + Encode the approval calls that are not already in place. + + + ```solidity ERC-20 Approval theme={null} + function approve(address spender, uint256 amount) returns (bool); + ``` + + ```solidity ERC-1155 Approval theme={null} + function setApprovalForAll(address operator, bool approved); + ``` + + + Build a relayer call list from the encoded calldata. + + ```json theme={null} + [ + { + "target": "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB", + "value": "0", + "data": "" + }, + { + "target": "0x006F54F7f9A22e0000CC2AB60031000000ae9fEF", + "value": "0", + "data": "" + }, + { + "target": "0x006F54F7f9A22e0000CC2AB60031000000ae9fEF", + "value": "0", + "data": "" + } + ] + ``` + + + + Fetch a fresh `WALLET` nonce before signing the batch. + + ```bash theme={null} + curl -G "https://relayer-v2.polymarket.com/v1/account/transactions/params" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" \ + --data-urlencode "address=$RELAYER_API_KEY_ADDRESS" \ + --data-urlencode "type=WALLET" + ``` + + The response includes the nonce to sign with the transaction. + + ```json theme={null} + { + "address": "", + "nonce": "" + } + ``` + + + + Build and sign a Deposit Wallet `Batch` with the owner. Use the approval calls + from the call-list step as `calls`. + + ```json EIP-712 Batch theme={null} + { + "domain": { + "name": "DepositWallet", + "version": "1", + "chainId": 137, + "verifyingContract": "" + }, + "types": { + "Call": [ + { "name": "target", "type": "address" }, + { "name": "value", "type": "uint256" }, + { "name": "data", "type": "bytes" } + ], + "Batch": [ + { "name": "wallet", "type": "address" }, + { "name": "nonce", "type": "uint256" }, + { "name": "deadline", "type": "uint256" }, + { "name": "calls", "type": "Call[]" } + ] + }, + "primaryType": "Batch", + "message": { + "wallet": "", + "nonce": "", + "deadline": "", + "calls": [ + { + "target": "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB", + "value": "0", + "data": "" + } + ] + } + } + ``` + + Submit the signed batch to the relayer. + + ```bash theme={null} + curl -X POST "https://relayer-v2.polymarket.com/submit" \ + -H "Content-Type: application/json" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" \ + -d '{ + "type": "WALLET", + "from": "", + "to": "0x00000000000Fb5C9ADea0298D729A0CB3823Cc07", + "nonce": "", + "signature": "", + "metadata": "Approve Combo RFQ contracts", + "depositWalletParams": { + "depositWallet": "", + "deadline": "", + "calls": [ + { + "target": "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB", + "value": "0", + "data": "" + } + ] + } + }' + ``` + + The response includes the relayer transaction ID. + + ```json theme={null} + { + "transactionID": "", + "state": "STATE_NEW" + } + ``` + + + + Poll the relayer transaction until it reaches `STATE_CONFIRMED` before posting + quotes that rely on those approvals. + + ```bash theme={null} + curl "https://relayer-v2.polymarket.com/v1/account/transactions/" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" + ``` + + ```json theme={null} + { + "transaction_id": "", + "transaction_hash": "", + "state": "STATE_CONFIRMED", + "error_msg": null + } + ``` + + Treat `STATE_FAILED` and `STATE_INVALID` as terminal failures. + + + + + +## 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` | + +See [Combinatorial Positions](/trading/ctf/combinatorial) for more detail on the +YES/NO position model. + +The diagram below shows the maker-side quote lifecycle, from receiving a quote +request through its terminal outcome. + +```mermaid theme={null} +flowchart TD + A[Receive request] --> B[Send quote] + B --> C[Active quote] + C --> D[Canceled] + C --> E[Selected] + E --> F{Last Look?} + F -->|No| G[Execution] + + subgraph lastLook["Last Look"] + F -->|Yes| H[Review fill] + H --> I[Confirm] + H --> J[Decline] + H --> K[Timeout] + end + + I --> G + G --> L[Confirmed] + G --> M[Failed] + + style lastLook fill:#165DFC14,stroke:#165DFC66,stroke-width:1px +``` + +### 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. + + + + + + First, switch on `event.type` to handle quote requests from the session stream. + + ```ts theme={null} + switch (event.type) { + case "quote_request": + // event: RfqQuoteRequestEvent + void handleQuoteRequest(event); + break; + + // … + } + ``` + + + + Then, inspect the `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. + + ```ts theme={null} + type RfqRequestedSize = + | { + unit: RfqRequestedSizeUnit.Notional; + value: DecimalString; + } + | { + unit: RfqRequestedSizeUnit.Shares; + value: DecimalString; + }; + ``` + + Where: + + * `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. + + In both cases, `value` is a normalized decimal string. + + + + Finally, handle pricing, quote submission, and persistence outside the session + loop before the `event.submissionDeadline` deadline. Price the request as pUSD + per YES Combo share; for example, `0.45` means `0.45` pUSD per share. If you do + not want to quote the request, skip submission. + + ```ts theme={null} + async function handleQuoteRequest(event: RfqQuoteRequestEvent) { + const price = priceComboRequest(event); + + if (price === undefined) return; + + const reference = await event.quote({ price }); + + storeQuoteReference(reference); + } + ``` + + + + + + + + First, use `isinstance(...)` to handle quote requests from the session stream. + + ```python theme={null} + from polymarket import RfqQuoteRequestEvent + + + async for event in session: + if isinstance(event, RfqQuoteRequestEvent): + await handle_quote_request(event) + ``` + + + + Then, inspect the `RfqQuoteRequestEvent` before pricing it. + + | Field | Type | Description | + | --------------------- | ------------------------ | ------------------------------------------ | + | `rfq_id` | `RfqId` | RFQ identifier used to correlate responses | + | `requestor_public_id` | `RfqRequestorPublicId` | Public identifier for the user request | + | `condition_id` | `ComboConditionId` | Derived Combo condition ID | + | `direction` | `RfqDirection` | Whether the user wants to buy or sell | + | `side` | `RfqSide` | Currently always `RfqSide.YES` | + | `requested_size` | `RfqRequestedSize` | User-requested notional or share size | + | `yes_position_id` | `PositionId` | Derived YES Combo position ID | + | `no_position_id` | `PositionId` | Derived NO Combo position ID | + | `leg_position_ids` | `tuple[PositionId, ...]` | Underlying leg position IDs | + | `submission_deadline` | `int` | Unix-millisecond quote submission deadline | + + `requested_size` is an `RfqRequestedSize` value that describes how the user sized + the request. + + ```python theme={null} + from dataclasses import dataclass + from decimal import Decimal + + from polymarket import RfqRequestedSizeUnit + + + @dataclass(frozen=True, slots=True, kw_only=True) + class RfqRequestedSize: + unit: RfqRequestedSizeUnit + value: Decimal + ``` + + Where: + + * `RfqRequestedSizeUnit.NOTIONAL`: the target value of the request in collateral + currency. For example, `Decimal("3")` means the user wants roughly 3 pUSD worth + of the Combo, with the resulting share size derived from the quote price. + * `RfqRequestedSizeUnit.SHARES`: the target number of Combo outcome tokens. For + example, `Decimal("10")` means the user wants 10 shares, or 10,000,000 base + units. + + In both cases, `value` is a `Decimal`. + + + + Finally, handle pricing, quote submission, and persistence outside the session + loop before the `event.submission_deadline` deadline. Price the request as pUSD + per YES Combo share; for example, `Decimal("0.45")` means `0.45` pUSD per share. + If you do not want to quote the request, skip submission. + + ```python theme={null} + from decimal import Decimal + + from polymarket import RfqQuoteRequestEvent + + + async def handle_quote_request(event: RfqQuoteRequestEvent) -> None: + price = price_combo_request(event) + + if price is None: + return + + reference = await event.quote(price=price) + + store_quote_reference(reference) + ``` + + + + + + + + The RFQ system sends `RFQ_REQUEST` messages over the authenticated WebSocket. + Inspect the request before pricing it. + + + ```json Notional Request theme={null} + { + "type": "RFQ_REQUEST", + "rfq_id": "", + "requestor_public_id": "", + "leg_position_ids": ["", ""], + "condition_id": "", + "yes_position_id": "", + "no_position_id": "", + "direction": "SELL", + "side": "YES", + "requested_size": { + "unit": "notional", + "value_e6": "1000000" + }, + "submission_deadline": "" + } + ``` + + ```json Shares Request theme={null} + { + "type": "RFQ_REQUEST", + "rfq_id": "", + "requestor_public_id": "", + "leg_position_ids": ["", ""], + "condition_id": "", + "yes_position_id": "", + "no_position_id": "", + "direction": "SELL", + "side": "YES", + "requested_size": { + "unit": "shares", + "value_e6": "1000000" + }, + "submission_deadline": "" + } + ``` + + + A `notional` request specifies a target pUSD amount; the fillable share size is + derived from the quote price. A `shares` request specifies the exact number of + Combo outcome tokens requested. + + + + Decide the `price` in base units for a full share. A full share is `1000000` + share base units, and `1` pUSD is `1000000` pUSD base units. For example, a + price of `0.45` pUSD per share means `price = 450000`. + + Determine `size` from the request: + + | `requested_size.unit` | `size` | + | --------------------- | -------------------------------------------------- | + | `notional` | `floor(requested_size.value_e6 * 1000000 / price)` | + | `shares` | `requested_size.value_e6` | + + Then determine the order token and amounts: + + | Quote Request | Token | `makerAmount` | `takerAmount` | + | ------------- | ----------------- | ------------------------------------------ | ------------- | + | `SELL` YES | `yes_position_id` | `ceil(price * size / 1000000)` | `size` | + | `BUY` YES | `no_position_id` | `ceil((1000000 - price) * size / 1000000)` | `size` | + + The examples below quote `1` share, so `size = 1000000`. + + + ```json SELL Request theme={null} + { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "450000", + "takerAmount": "1000000", + "side": 0, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ``` + + ```json BUY Request theme={null} + { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "550000", + "takerAmount": "1000000", + "side": 0, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ``` + + + + + Build the EIP-712 typed-data payload for your wallet type: + + * Use `depositWalletTypedData` when `signature_type` is `3`. + * Use `exchangeV3OrderTypedData` when `signature_type` is `0`, `1`, or `2`. + + + ```json depositWalletTypedData theme={null} + { + "domain": { + "name": "Polymarket CTF Exchange", + "version": "3", + "chainId": 137, + "verifyingContract": "0xe3333700cA9d93003F00f0F71f8515005F6c00Aa" + }, + "types": { + "Order": [ + { "name": "salt", "type": "uint256" }, + { "name": "maker", "type": "address" }, + { "name": "signer", "type": "address" }, + { "name": "tokenId", "type": "uint256" }, + { "name": "makerAmount", "type": "uint256" }, + { "name": "takerAmount", "type": "uint256" }, + { "name": "side", "type": "uint8" }, + { "name": "signatureType", "type": "uint8" }, + { "name": "timestamp", "type": "uint256" }, + { "name": "metadata", "type": "bytes32" }, + { "name": "builder", "type": "bytes32" } + ], + "TypedDataSign": [ + { "name": "contents", "type": "Order" }, + { "name": "name", "type": "string" }, + { "name": "version", "type": "string" }, + { "name": "chainId", "type": "uint256" }, + { "name": "verifyingContract", "type": "address" }, + { "name": "salt", "type": "bytes32" } + ] + }, + "primaryType": "TypedDataSign", + "message": { + "contents": { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "450000", + "takerAmount": "1000000", + "side": 0, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "name": "DepositWallet", + "version": "1", + "chainId": 137, + "verifyingContract": "0xYourDepositWallet", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + } + ``` + + ```json exchangeV3OrderTypedData theme={null} + { + "domain": { + "name": "Polymarket CTF Exchange", + "version": "3", + "chainId": 137, + "verifyingContract": "0xe3333700cA9d93003F00f0F71f8515005F6c00Aa" + }, + "types": { + "EIP712Domain": [ + { "name": "name", "type": "string" }, + { "name": "version", "type": "string" }, + { "name": "chainId", "type": "uint256" }, + { "name": "verifyingContract", "type": "address" } + ], + "Order": [ + { "name": "salt", "type": "uint256" }, + { "name": "maker", "type": "address" }, + { "name": "signer", "type": "address" }, + { "name": "tokenId", "type": "uint256" }, + { "name": "makerAmount", "type": "uint256" }, + { "name": "takerAmount", "type": "uint256" }, + { "name": "side", "type": "uint8" }, + { "name": "signatureType", "type": "uint8" }, + { "name": "timestamp", "type": "uint256" }, + { "name": "metadata", "type": "bytes32" }, + { "name": "builder", "type": "bytes32" } + ] + }, + "primaryType": "Order", + "message": { + "salt": "", + "maker": "0xYourEoaAddress", + "signer": "0xYourEoaAddress", + "tokenId": "", + "makerAmount": "450000", + "takerAmount": "1000000", + "side": 0, + "signatureType": 0, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + } + ``` + + + Both payloads use the Exchange v3 EIP-712 domain. `exchangeV3OrderTypedData` is + the direct Exchange v3 `Order` payload. `depositWalletTypedData` is a + `TypedDataSign` wrapper whose `contents` field is the Exchange v3 order and + whose message includes the Deposit Wallet validation fields. + + + + Sign the typed-data payload for the wallet type you authenticated with. The + normal Exchange v3 payload and the Deposit Wallet payload are different: + + | Wallet Type | `signatureType` | Payload to sign | `signed_order.signature` | + | -------------- | --------------- | -------------------------- | ------------------------------ | + | Deposit Wallet | `3` | `depositWalletTypedData` | ERC-7739-wrapped signature | + | Safe Wallet | `2` | `exchangeV3OrderTypedData` | Standard 65-byte EVM signature | + | Poly Proxy | `1` | `exchangeV3OrderTypedData` | Standard 65-byte EVM signature | + | EOA | `0` | `exchangeV3OrderTypedData` | Standard 65-byte EVM signature | + + The example below shows how to produce `signature` with Viem for both signing + paths. + + + ```ts sign.ts theme={null} + import { privateKeyToAccount } from "viem/accounts"; + import { wrapDepositWalletSignature } from "./wrapDepositWalletSignature"; + + const signer = privateKeyToAccount(""); + + const signature = + signatureType === 3 + ? wrapDepositWalletSignature( + await signer.signTypedData(depositWalletTypedData), + depositWalletTypedData, + ) + : await signer.signTypedData(exchangeV3OrderTypedData); + ``` + + ```ts wrapDepositWalletSignature.ts theme={null} + import { + concatHex, + encodeAbiParameters, + keccak256, + toHex, + type Address, + type Hex, + } from "viem"; + import type { DepositWalletTypedData } from "./types"; + + const ORDER_TYPE = + "Order(uint256 salt,address maker,address signer,uint256 tokenId,uint256 makerAmount,uint256 takerAmount,uint8 side,uint8 signatureType,uint256 timestamp,bytes32 metadata,bytes32 builder)"; + const EIP712_DOMAIN_TYPE = + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"; + + export function wrapDepositWalletSignature( + innerSignature: Hex, + depositWalletTypedData: DepositWalletTypedData, + ): Hex { + const order = depositWalletTypedData.message.contents; + const exchangeV3Domain = depositWalletTypedData.domain; + + const appDomainSeparator = keccak256( + encodeAbiParameters( + [ + { type: "bytes32" }, + { type: "bytes32" }, + { type: "bytes32" }, + { type: "uint256" }, + { type: "address" }, + ], + [ + keccak256(toHex(EIP712_DOMAIN_TYPE)), + keccak256(toHex(exchangeV3Domain.name)), + keccak256(toHex(exchangeV3Domain.version)), + BigInt(exchangeV3Domain.chainId), + exchangeV3Domain.verifyingContract, + ], + ), + ); + const contentsHash = keccak256( + encodeAbiParameters( + [ + { type: "bytes32" }, + { type: "uint256" }, + { type: "address" }, + { type: "address" }, + { type: "uint256" }, + { type: "uint256" }, + { type: "uint256" }, + { type: "uint8" }, + { type: "uint8" }, + { type: "uint256" }, + { type: "bytes32" }, + { type: "bytes32" }, + ], + [ + keccak256(toHex(ORDER_TYPE)), + BigInt(order.salt), + order.maker, + order.signer, + BigInt(order.tokenId), + BigInt(order.makerAmount), + BigInt(order.takerAmount), + order.side, + order.signatureType, + BigInt(order.timestamp), + order.metadata, + order.builder, + ], + ), + ); + + return concatHex([ + innerSignature, + appDomainSeparator, + contentsHash, + toHex(ORDER_TYPE), + toHex(ORDER_TYPE.length, { size: 2 }), + ]); + } + ``` + + ```ts types.ts theme={null} + import type { Address, Hex } from "viem"; + + export type DepositWalletTypedData = { + domain: { + name: string; + version: string; + chainId: number; + verifyingContract: Address; + }; + message: { + contents: { + salt: string; + maker: Address; + signer: Address; + tokenId: string; + makerAmount: string; + takerAmount: string; + side: number; + signatureType: number; + timestamp: string; + metadata: Hex; + builder: Hex; + }; + }; + types: Record; + primaryType: "TypedDataSign"; + }; + ``` + + + + + Before `submission_deadline`, submit the RFQ ID, quote price, fillable size, and + signed order. Add the signature from the previous step as + `signed_order.signature`. + + + ```json WebSocket theme={null} + { + "type": "RFQ_QUOTE", + "rfq_id": "", + "price_e6": "450000", + "size_e6": "1000000", + "signed_order": { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "450000", + "takerAmount": "1000000", + "side": 0, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signature": "" + } + } + ``` + + ```bash REST theme={null} + curl -X POST "https://combos-rfq-api.polymarket.com/v1/maker/quotes" \ + -H "Content-Type: application/json" \ + -H "POLY_ADDRESS: " \ + -H "POLY_SIGNATURE: " \ + -H "POLY_TIMESTAMP: " \ + -H "POLY_API_KEY: " \ + -H "POLY_PASSPHRASE: " \ + -d '{ + "quote_id": "", + "rfq_id": "", + "signer_address": "", + "maker_address": "", + "signature_type": 3, + "price_e6": "450000", + "size_e6": "1000000", + "signed_order": { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "450000", + "takerAmount": "1000000", + "side": 0, + "signatureType": 3, + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signature": "" + } + }' + ``` + + + + REST submissions require a client-generated `quote_id`. Use an opaque unique + value; the RFQ system uses the `quote_` prefix followed by 32 lowercase hex + characters. + + + + + After submitting a quote, store the RFQ ID and quote ID together. WebSocket + submissions receive both values in the acknowledgement. REST submissions return + the current RFQ snapshot, so use the client-generated `quote_id` from the request. + + + ```json WebSocket theme={null} + { + "type": "ACK_RFQ_QUOTE", + "rfq_id": "", + "quote_id": "" + } + ``` + + ```json REST theme={null} + { + "request": { + "rfq_id": "" + // … + }, + "status": "COLLECTING_QUOTES", + "competition_started_at": 1780963200000, + "competition_ends_at": 1780963200400 + } + ``` + + + This reference identifies the submitted quote. + + + + + +### Quote Partial Fills + + + + 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. + + ```ts theme={null} + await event.quote({ + price: "0.45", + size: "10", + }); + ``` + + + + If you only want to fill part of the requested size, pass `size` with the quote. + `size` is a `Decimal`-compatible value: `Decimal("10")` means 10 shares, or + 10,000,000 base units. When omitted, the SDK quotes the full requested size. + + ```python theme={null} + from decimal import Decimal + + + await event.quote( + price=Decimal("0.45"), + size=Decimal("10"), + ) + ``` + + + + Partial fills use the same signed-order flow as a full quote. + + + + Start by converting `requested_size` into the full request size in share base + units. + + | `requested_size.unit` | Full request size | + | --------------------- | -------------------------------------------------- | + | `notional` | `floor(requested_size.value_e6 * 1000000 / price)` | + | `shares` | `requested_size.value_e6` | + + Choose a partial `size` in share base units that is smaller than the full request + size. + + + + Compute the signed order amounts from the partial `size`. + + | Quote Request | Token | `makerAmount` | `takerAmount` | + | ------------- | ----------------- | ------------------------------------------ | ------------- | + | `SELL` YES | `yes_position_id` | `ceil(price * size / 1000000)` | `size` | + | `BUY` YES | `no_position_id` | `ceil((1000000 - price) * size / 1000000)` | `size` | + + This example quotes half of a `1` share request at `0.45` pUSD per share, so + `size = 500000`: + + + ```json SELL Request theme={null} + { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "225000", + "takerAmount": "500000", + "side": 0, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ``` + + ```json BUY Request theme={null} + { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "275000", + "takerAmount": "500000", + "side": 0, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ``` + + + + + Sign the partial order, then submit the quote. + + ```json theme={null} + { + "type": "RFQ_QUOTE", + "rfq_id": "", + "price_e6": "450000", + "size_e6": "500000", + "signed_order": { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "225000", + "takerAmount": "500000", + "side": 0, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signature": "" + } + } + ``` + + + + + +### Use Inventory + + + + 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. + + ```ts theme={null} + await event.quote({ + price: "0.45", + source: "inventory", + }); + ``` + + + + 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=RfqQuoteSource.INVENTORY` when you want to quote from existing inventory + instead. + + ```python theme={null} + from decimal import Decimal + + from polymarket import RfqQuoteSource + + + await event.quote( + price=Decimal("0.45"), + source=RfqQuoteSource.INVENTORY, + ) + ``` + + + + Inventory quotes sell existing outcome tokens instead of spending collateral. The + RFQ quote price still means pUSD per YES Combo share. + + + + Use the token you already hold for the side of the quote request. + + | Quote Request | Inventory Token | Order Side | + | ------------- | ----------------- | ---------- | + | `BUY` YES | `yes_position_id` | SELL | + | `SELL` YES | `no_position_id` | SELL | + + + + Compute the signed order amounts from the inventory `size`. + + | Quote Request | Order Price | `makerAmount` | `takerAmount` | + | ------------- | ----------------- | ------------- | ------------------------------------------- | + | `BUY` YES | `price` | `size` | `floor(price * size / 1000000)` | + | `SELL` YES | `1000000 - price` | `size` | `floor((1000000 - price) * size / 1000000)` | + + This example quotes `1` share at `0.45` pUSD per share, so `price = 450000` and + `size = 1000000`: + + + ```json BUY Request theme={null} + { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "1000000", + "takerAmount": "450000", + "side": 1, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ``` + + ```json SELL Request theme={null} + { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "1000000", + "takerAmount": "550000", + "side": 1, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ``` + + + + + Sign the inventory order, then submit the quote. + + ```json theme={null} + { + "type": "RFQ_QUOTE", + "rfq_id": "", + "price_e6": "450000", + "size_e6": "1000000", + "signed_order": { + "salt": "", + "maker": "", + "signer": "", + "tokenId": "", + "makerAmount": "1000000", + "takerAmount": "450000", + "side": 1, + "signatureType": 3, // + "timestamp": "", + "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000", + "builder": "0x0000000000000000000000000000000000000000000000000000000000000000", + "signature": "" + } + } + ``` + + + + + +### 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. + + + + + + + First, keep the quote reference returned by `event.quote(…)`. It contains the + `rfqId` and `quoteId` needed to cancel the quote. + + ```ts theme={null} + const reference = await event.quote({ price: 0.45 }); + + // reference.rfqId: RfqId + // reference.quoteId: RfqQuoteId + ``` + + + + Then, pass that reference to `session.cancelQuote(…)` on the same live RFQ + session. + + ```ts theme={null} + if (shouldCancelQuote) { + const ack = await session.cancelQuote(reference); + + // ack.rfqId: RfqId + // ack.quoteId: RfqQuoteId + } + ``` + + + + + + + + First, keep the quote reference returned by `event.quote(...)`. It contains the + `rfq_id` and `quote_id` needed to cancel the quote. + + ```python theme={null} + from decimal import Decimal + + + reference = await event.quote(price=Decimal("0.45")) + + # reference.rfq_id: RfqId + # reference.quote_id: RfqQuoteId + ``` + + + + Then, pass that reference to `session.cancel_quote(...)` on the same live RFQ + session. + + ```python theme={null} + if should_cancel_quote: + ack = await session.cancel_quote(reference) + + # ack.rfq_id: RfqId + # ack.quote_id: RfqQuoteId + ``` + + + + + + Send a cancellation request with the RFQ ID and quote ID. On the WebSocket, the + RFQ system acknowledges a processed cancellation request with + `ACK_RFQ_QUOTE_CANCEL`. + + + ```json Send theme={null} + { + "type": "RFQ_QUOTE_CANCEL", + "rfq_id": "", + "quote_id": "", + "signer_address": "", + "maker_address": "" + } + ``` + + ```json Receive theme={null} + { + "type": "ACK_RFQ_QUOTE_CANCEL", + "rfq_id": "", + "quote_id": "" + } + ``` + + + Alternatively, cancel the quote through the REST API. + + + ```bash Request theme={null} + curl -X POST "https://combos-rfq-api.polymarket.com/v1/maker/quotes/cancel" \ + -H "Content-Type: application/json" \ + -H "POLY_ADDRESS: " \ + -H "POLY_SIGNATURE: " \ + -H "POLY_TIMESTAMP: " \ + -H "POLY_API_KEY: " \ + -H "POLY_PASSPHRASE: " \ + -d '{ + "rfq_id": "", + "quote_id": "", + "signer_address": "", + "maker_address": "", + "signature_type": 3 + }' + ``` + + ```json Response theme={null} + { + "request": { + "rfq_id": "" + // … + }, + "status": "COLLECTING_QUOTES", + "competition_started_at": 1780963200000, + "competition_ends_at": 1780963200400 + } + ``` + + + + +### Last Look + +Last Look is a separate confirmation step for makers that have it enabled. If a +selected quote requires confirmation, run a final risk check before the +confirmation deadline and either confirm or decline the quote. + + + + + + First, switch on `event.type` to handle confirmation requests from the same + session stream. + + ```ts theme={null} + switch (event.type) { + case "confirmation_request": + // event: RfqConfirmationRequestEvent + void handleConfirmationRequest(event); + break; + + // … + } + ``` + + + + 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. + + ```ts theme={null} + type RfqConfirmationRequestEvent = { + type: "confirmation_request"; + rfqId: RfqId; + quoteId: RfqQuoteId; + conditionId: ComboConditionId; + direction: RfqDirection; + side: RfqSide.Yes; + price: DecimalString; + fillSize: DecimalString; + yesPositionId: PositionId; + noPositionId: PositionId; + legPositionIds: PositionId[]; + confirmBy: EpochMilliseconds; + confirm(): Promise; + decline(): Promise; + }; + ``` + + + + Finally, run your final risk check outside the session loop and respond before + the `event.confirmBy` deadline. + + ```ts theme={null} + async function handleConfirmationRequest(event: RfqConfirmationRequestEvent) { + const canStillFill = runFinalRiskCheck(event); + + if (canStillFill) { + await event.confirm(); + return; + } + + await event.decline(); + } + ``` + + + + + + + + First, use `isinstance(...)` to handle confirmation requests from the same + session stream. + + ```python theme={null} + from polymarket import RfqConfirmationRequestEvent + + + async for event in session: + if isinstance(event, RfqConfirmationRequestEvent): + await handle_confirmation_request(event) + ``` + + + + Then, inspect the confirmation request before running your final risk check. It + includes the selected quote, the final fill size, and the `event.confirm_by` + deadline for your Last Look response. + + ```python theme={null} + class RfqConfirmationRequestEvent: + type: "confirmation_request" + rfq_id: RfqId + quote_id: RfqQuoteId + signer_address: EvmAddress + maker_address: EvmAddress + signature_type: int + condition_id: ComboConditionId + direction: RfqDirection + side: RfqSide + price: Decimal + fill_size: Decimal + yes_position_id: PositionId + no_position_id: PositionId + leg_position_ids: tuple[PositionId, ...] + confirm_by: int + + async def confirm(self) -> RfqConfirmationAck: ... + async def decline(self) -> RfqConfirmationAck: ... + ``` + + + + Finally, run your final risk check outside the session loop and respond before + the `event.confirm_by` deadline. + + ```python theme={null} + from polymarket import RfqConfirmationRequestEvent + + + async def handle_confirmation_request( + event: RfqConfirmationRequestEvent, + ) -> None: + can_still_fill = run_final_risk_check(event) + + if can_still_fill: + await event.confirm() + return + + await event.decline() + ``` + + + + + + If Last Look is enabled for your maker, the RFQ WebSocket sends + `RFQ_CONFIRMATION_REQUEST` after your quote is selected. + + ```json theme={null} + { + "type": "RFQ_CONFIRMATION_REQUEST", + "rfq_id": "", + "quote_id": "", + "signer_address": "", + "maker_address": "", + "signature_type": 3, // + "leg_position_ids": ["", ""], + "condition_id": "", + "yes_position_id": "", + "no_position_id": "", + "direction": "BUY", + "side": "YES", + "fill_size_e6": "1000000", + "price_e6": "450000", + "confirm_by": 1780963200000 + } + ``` + + Respond before `confirm_by` with `CONFIRM` or `DECLINE`. + + + ```json Confirm theme={null} + { + "type": "RFQ_CONFIRMATION_RESPONSE", + "rfq_id": "", + "quote_id": "", + "decision": "CONFIRM" + } + ``` + + ```json Decline theme={null} + { + "type": "RFQ_CONFIRMATION_RESPONSE", + "rfq_id": "", + "quote_id": "", + "decision": "DECLINE" + } + ``` + + + The RFQ system acknowledges the response with + `ACK_RFQ_CONFIRMATION_RESPONSE`. + + ```json theme={null} + { + "type": "ACK_RFQ_CONFIRMATION_RESPONSE", + "rfq_id": "", + "quote_id": "", + "decision": "CONFIRM" + } + ``` + + Do not include `signer_address`, `maker_address`, or `signature_type` in + `RFQ_CONFIRMATION_RESPONSE`. The RFQ system applies identity from the + authenticated session. + + Alternatively, send the Last Look decision through the REST API. The response + returns `execution` when your confirmation completes the bundle. If the RFQ is + still waiting on another maker confirmation, or if you decline, it returns + `snapshot`. + + + ```bash Request theme={null} + curl -X POST "https://combos-rfq-api.polymarket.com/v1/maker/confirmations" \ + -H "Content-Type: application/json" \ + -H "POLY_ADDRESS: " \ + -H "POLY_SIGNATURE: " \ + -H "POLY_TIMESTAMP: " \ + -H "POLY_API_KEY: " \ + -H "POLY_PASSPHRASE: " \ + -d '{ + "rfq_id": "", + "quote_id": "", + "signer_address": "", + "maker_address": "", + "signature_type": 3, + "decision": "CONFIRM" + }' + ``` + + ```json Execution Response theme={null} + { + "execution": { + "execution_id": "", + "quote_id": "", + "request": { + "rfq_id": "" + } + } + } + ``` + + ```json Snapshot Response theme={null} + { + "snapshot": { + "request": { + "rfq_id": "" + }, + "status": "AWAITING_MAKER_CONFIRMATION" + } + } + ``` + + + + +## 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. + + + + Use `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. + + ```ts theme={null} + import { ComboPositionStatus, type ComboPosition } from "@polymarket/client"; + + const positions = client.listComboPositions({ + status: ComboPositionStatus.Open, + pageSize: 50, + }); + + for await (const page of positions) { + for (const position of page.items) { + // position: ComboPosition + } + } + ``` + + Each returned item is a `ComboPosition`. + + + ```ts ComboPosition theme={null} + type ComboPosition = { + conditionId: ComboConditionId; + positionId: PositionId; + moduleId: number; + userAddress: Address; + shares: DecimalString; + entryAvgPriceUsdc?: DecimalString | null; + entryCostUsdc?: DecimalString | null; + status: ComboPositionStatus; + firstEntryAt: IsoDateTimeString; + resolvedAt?: IsoDateTimeString | null; + legsTotal: number; + legsResolved: number; + legsPending: number; + legs: ComboPositionLeg[]; + }; + ``` + + ```ts ComboPositionLeg theme={null} + type ComboPositionLeg = { + legIndex: number; + legPositionId: PositionId; + legConditionId: CtfConditionId; + legOutcomeIndex: number; + legOutcomeLabel?: string | null; + legStatus: ComboPositionStatus; + legResolvedAt?: IsoDateTimeString | null; + legCurrentPrice?: DecimalString | null; + market?: ComboPositionMarket | null; + }; + ``` + + ```ts ComboPositionMarket theme={null} + type ComboPositionMarket = { + marketId?: string | null; + slug?: string | null; + title?: string | null; + outcome?: string | null; + imageUrl?: string | null; + iconUrl?: string | null; + category?: string | null; + subcategory?: string | null; + tags?: string[] | null; + endDate?: IsoDateTimeString | null; + event?: ComboPositionMarketEvent | null; + }; + ``` + + ```ts ComboPositionMarketEvent theme={null} + type ComboPositionMarketEvent = { + eventId?: string | null; + eventSlug?: string | null; + eventTitle?: string | null; + eventImage?: string | null; + }; + ``` + + + You can filter positions by the following criteria: + + + ```ts Condition ID theme={null} + const positions = client.listComboPositions({ + conditionId: "", + }); + ``` + + ```ts Position ID theme={null} + const positions = client.listComboPositions({ + positionId: "", + }); + ``` + + ```ts Status theme={null} + const positions = client.listComboPositions({ + status: ComboPositionStatus.Open, + }); + ``` + + + + + Use `client.list_combo_positions(...)` to page through Combo positions for the + authenticated wallet. The Python SDK returns snake\_case model fields and + `Decimal` values for numeric position amounts. + + ```python theme={null} + positions = client.list_combo_positions(status="OPEN") + + async for page in positions: + for position in page.items: + # position: ComboPosition + ... + ``` + + The returned `ComboPosition` models include the following fields: + + + ```python ComboPosition theme={null} + class ComboPosition: + condition_id: ComboConditionId + position_id: PositionId + module_id: int + user_address: EvmAddress + shares: Decimal + entry_avg_price_usdc: Decimal | None + entry_cost_usdc: Decimal | None + status: ComboPositionStatus + first_entry_at: datetime + resolved_at: datetime | None + legs_total: int + legs_resolved: int + legs_pending: int + legs: tuple[ComboPositionLeg, ...] + ``` + + ```python ComboPositionLeg theme={null} + class ComboPositionLeg: + leg_index: int + leg_position_id: PositionId + leg_condition_id: CtfConditionId + leg_outcome_index: int + leg_outcome_label: str | None + leg_status: ComboPositionStatus + leg_resolved_at: datetime | None + leg_current_price: Decimal | None + market: ComboPositionMarket | None + ``` + + ```python ComboPositionMarket theme={null} + class ComboPositionMarket: + market_id: str | None + slug: str | None + title: str | None + outcome: str | None + image_url: str | None + icon_url: str | None + category: str | None + subcategory: str | None + tags: tuple[str, ...] | None + end_date: datetime | None + event: ComboPositionMarketEvent | None + ``` + + ```python ComboPositionMarketEvent theme={null} + class ComboPositionMarketEvent: + event_id: str | None + event_slug: str | None + event_title: str | None + event_image: str | None + ``` + + + You can filter positions by the following criteria: + + + ```python Condition ID theme={null} + positions = client.list_combo_positions( + condition_id="", + ) + ``` + + ```python Position ID theme={null} + positions = client.list_combo_positions( + position_id="", + ) + ``` + + ```python Status theme={null} + positions = client.list_combo_positions( + status="OPEN", + ) + ``` + + + + + Use the Data API to list Combo positions for a wallet. + + ```bash theme={null} + curl -G "https://data-api.polymarket.com/v1/positions/combos" \ + --data-urlencode "user=" \ + --data-urlencode "limit=50" \ + --data-urlencode "status=OPEN" + ``` + + You can filter positions by the following query parameters: + + + ```bash Condition ID theme={null} + curl -G "https://data-api.polymarket.com/v1/positions/combos" \ + --data-urlencode "user=" \ + --data-urlencode "combo_condition_id=" + ``` + + ```bash Position ID theme={null} + curl -G "https://data-api.polymarket.com/v1/positions/combos" \ + --data-urlencode "user=" \ + --data-urlencode "combo_position_id=" + ``` + + ```bash Status theme={null} + curl -G "https://data-api.polymarket.com/v1/positions/combos" \ + --data-urlencode "user=" \ + --data-urlencode "status=OPEN" + ``` + + + The response returns Combo positions in `combos` and pagination metadata in + `pagination`. + + ```json theme={null} + { + "combos": [ + { + "combo_condition_id": "", + "combo_position_id": "", + "module_id": 3, + "user_address": "", + "shares_balance": "10", + "entry_avg_price_usdc": "0.45", + "entry_cost_usdc": "4.5", + "realized_payout_usdc": "0.00", + "total_cost_usdc": "4.50", + "status": "OPEN", + "first_entry_at": "2026-06-08T00:00:00Z", + "resolved_at": null, + "legs_total": 2, + "legs_resolved": 0, + "legs_pending": 2, + "legs": [ + { + "leg_index": 0, + "leg_position_id": "", + "leg_condition_id": "", + "leg_outcome_index": 0, + "leg_outcome_label": "Yes", + "leg_status": "OPEN", + "leg_resolved_at": null, + "leg_current_price": "0.52" + } + ] + } + ], + "pagination": { + "limit": 50, + "offset": 0, + "has_more": false, + "next_cursor": null + } + } + ``` + + + + + **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 under `PARTIAL`) + * `total_cost_usdc` — original cost basis, reconstructed as + `entry_avg_price × (shares_balance + realized_payout)` + + Net result of a finished combo = `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. + + + + Use `client.splitPosition(...)` with `legs` to create Combo inventory from + collateral. `amount` is in pUSD base units. + + ```ts theme={null} + const split = await client.splitPosition({ + amount: 10_000_000n, + legs: ["", ""], + }); + + const splitOutcome = await split.wait(); + + // splitOutcome.transactionHash identifies the confirmed split transaction. + ``` + + Use `client.mergePositions(...)` with the same `legs` to merge complementary + Combo positions back into collateral. Pass `amount: "max"` to merge the largest + matching amount available. + + ```ts theme={null} + const merge = await client.mergePositions({ + amount: "max", + legs: ["", ""], + }); + + const mergeOutcome = await merge.wait(); + + // mergeOutcome.transactionHash identifies the confirmed merge transaction. + ``` + + + + Use `client.split_position(...)` with `legs` to create Combo inventory from + collateral. `amount` is in pUSD base units. + + ```python theme={null} + split = await client.split_position( + amount=10_000_000, + legs=["", ""], + ) + + split_outcome = await split.wait() + + # split_outcome.transaction_hash identifies the confirmed split transaction. + ``` + + Use `client.merge_positions(...)` with the same `legs` to merge complementary + Combo positions back into collateral. Pass `amount="max"` to merge the largest + matching amount available. + + ```python theme={null} + merge = await client.merge_positions( + amount="max", + legs=["", ""], + ) + + merge_outcome = await merge.wait() + + # merge_outcome.transaction_hash identifies the confirmed merge transaction. + ``` + + + + Use the Relayer API to split or merge Combo inventory by sending an ordered list + of encoded contract calls in one batch. The following steps assume you are using + a Deposit Wallet. + + + If you use a Safe or Poly Proxy wallet, use one of the SDKs instead because + those wallet integrations require wallet-specific signing and encoding. + + + Use these contract addresses when building the call list. + + | Contract | Address | + | --------------------- | -------------------------------------------- | + | CombinatorialModule | `0x30000034706c7d8e12009dab006be20000c031a8` | + | Router | `0x12121212006e4CD160D18e3f00711DA5c3372600` | + | PositionManager | `0x006F54F7f9A22e0000CC2AB60031000000ae9fEF` | + | pUSD collateral token | `0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB` | + + + + First, determine whether the inventory action needs an approval. If approval is + already in place, skip this step. + + For a split, `` must approve pUSD spending by the Router. For a + merge, `` must approve the Router as a PositionManager ERC-1155 + operator. + + + ```solidity ERC-20 Approval theme={null} + function approve(address spender, uint256 amount) returns (bool); + ``` + + ```solidity ERC-1155 Approval theme={null} + function setApprovalForAll(address operator, bool approved); + ``` + + + Encode one of these approval calls when needed. Keep the resulting call object; + it will be added before the Combo calls in the next step. + + + ```json Split Approval Call theme={null} + [ + { + "target": "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB", + "value": "0", + "data": "" + } + ] + ``` + + ```json Merge Approval Call theme={null} + [ + { + "target": "0x006F54F7f9A22e0000CC2AB60031000000ae9fEF", + "value": "0", + "data": "" + } + ] + ``` + + + + + Then, add the Combo call objects to the ordered list. + + For a split, include `prepareCondition` before `split`. `prepareCondition` is + idempotent, so it is safe to include even when the Combo condition was already + prepared. For a merge, call `merge` directly with the Combo condition ID for the + positions being merged. + + ```solidity theme={null} + function prepareCondition(uint256[] legs) returns (bytes31); + function split(bytes31 conditionId, uint256 amount); + function merge(bytes31 conditionId, uint256 amount); + ``` + + Append these encoded calls after the approval call from the previous step, if one + was needed. + + + ```json Split Combo Calls theme={null} + [ + // Include the approval call first when needed. + // … + { + "target": "0x30000034706c7d8e12009dab006be20000c031a8", + "value": "0", + "data": "" + }, + { + "target": "0x12121212006e4CD160D18e3f00711DA5c3372600", + "value": "0", + "data": "" + } + ] + ``` + + ```json Merge Combo Calls theme={null} + [ + // Include the approval call first when needed. + // … + { + "target": "0x12121212006e4CD160D18e3f00711DA5c3372600", + "value": "0", + "data": "" + } + ] + ``` + + + + + Fetch a fresh `WALLET` nonce before each submission. + + ```bash theme={null} + curl -G "https://relayer-v2.polymarket.com/v1/account/transactions/params" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" \ + --data-urlencode "address=$RELAYER_API_KEY_ADDRESS" \ + --data-urlencode "type=WALLET" + ``` + + The response includes the nonce to sign with the transaction. + + ```json theme={null} + { + "address": "", + "nonce": "" + } + ``` + + + + Build the Deposit Wallet EIP-712 `Batch` typed data. + + ```json theme={null} + { + "domain": { + "name": "DepositWallet", + "version": "1", + "chainId": 137, + "verifyingContract": "" + }, + "types": { + "Call": [ + { "name": "target", "type": "address" }, + { "name": "value", "type": "uint256" }, + { "name": "data", "type": "bytes" } + ], + "Batch": [ + { "name": "wallet", "type": "address" }, + { "name": "nonce", "type": "uint256" }, + { "name": "deadline", "type": "uint256" }, + { "name": "calls", "type": "Call[]" } + ] + }, + "primaryType": "Batch", + "message": { + "wallet": "", + "nonce": "", + "deadline": "", + "calls": [ + // Use the final calls array from the previous steps. + // … + ] + } + } + ``` + + Sign the EIP-712 batch with your signer. Use the resulting signature as + `signature` in the relayer submission. + + + + Submit the signed transaction to the Relayer API. + + + ```bash Split theme={null} + curl -X POST "https://relayer-v2.polymarket.com/submit" \ + -H "Content-Type: application/json" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" \ + -d '{ + "type": "WALLET", + "from": "", + "to": "0x00000000000Fb5C9ADea0298D729A0CB3823Cc07", + "nonce": "", + "signature": "", + "metadata": "Split Combo position", + "depositWalletParams": { + "depositWallet": "", + "deadline": "", + "calls": [ + // Use the final calls array from the previous steps. + // … + ] + } + }' + ``` + + ```bash Merge theme={null} + curl -X POST "https://relayer-v2.polymarket.com/submit" \ + -H "Content-Type: application/json" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" \ + -d '{ + "type": "WALLET", + "from": "", + "to": "0x00000000000Fb5C9ADea0298D729A0CB3823Cc07", + "nonce": "", + "signature": "", + "metadata": "Merge Combo positions", + "depositWalletParams": { + "depositWallet": "", + "deadline": "", + "calls": [ + // Use the final calls array from the previous steps. + // … + ] + } + }' + ``` + + + The response includes the relayer transaction ID. + + ```json theme={null} + { + "transactionID": "", + "state": "STATE_NEW" + } + ``` + + + + Poll the relayer transaction until it reaches `STATE_CONFIRMED` before relying on + the updated inventory. + + ```bash theme={null} + curl "https://relayer-v2.polymarket.com/v1/account/transactions/" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" + ``` + + ```json theme={null} + { + "transaction_id": "", + "transaction_hash": "", + "state": "STATE_CONFIRMED", + "error_msg": null + } + ``` + + Treat `STATE_FAILED` and `STATE_INVALID` as terminal failures. + + + + + +### Redeem Resolved Positions + +When a Combo position resolves, redeem the winning position to settle it back to +collateral. + + + + Use `client.redeemPositions(...)` with a Combo `positionId`. The SDK redeems the + available balance for that resolved position. + + ```ts theme={null} + const redeem = await client.redeemPositions({ + positionId: "", + }); + + const redeemOutcome = await redeem.wait(); + + // redeemOutcome.transactionHash identifies the confirmed redemption transaction. + ``` + + You can list resolved winning positions first, then redeem each one. + + ```ts theme={null} + import { ComboPositionStatus } from "@polymarket/client"; + + for await (const page of client.listComboPositions({ + status: ComboPositionStatus.ResolvedWin, + })) { + for (const position of page.items) { + const redeem = await client.redeemPositions({ + positionId: position.positionId, + }); + + await redeem.wait(); + } + } + ``` + + + + Use `client.redeem_positions(...)` with a Combo `position_id`. The SDK redeems + the available balance for that resolved position. + + ```python theme={null} + redeem = await client.redeem_positions( + position_id="", + ) + + redeem_outcome = await redeem.wait() + + # redeem_outcome.transaction_hash identifies the confirmed redemption transaction. + ``` + + You can list resolved winning positions first, then redeem each one. + + ```python theme={null} + positions = client.list_combo_positions(status="RESOLVED_WIN") + + async for position in positions.iter_items(): + redeem = await client.redeem_positions( + position_id=position.position_id, + ) + + await redeem.wait() + ``` + + + + Use the Relayer API to redeem resolved Combo positions by sending an ordered list + of encoded contract calls in one batch. The following steps assume you are using + a Deposit Wallet. + + + If you use a Safe or Poly Proxy wallet, use one of the SDKs instead because + those wallet integrations require wallet-specific signing and encoding. + + + | Contract | Address | + | --------------- | -------------------------------------------- | + | Router | `0x12121212006e4CD160D18e3f00711DA5c3372600` | + | PositionManager | `0x006F54F7f9A22e0000CC2AB60031000000ae9fEF` | + + + + First, determine whether `` has approved the Router as a + PositionManager ERC-1155 operator. If approval is already in place, skip this + step. + + ```solidity theme={null} + function setApprovalForAll(address operator, bool approved); + ``` + + Encode the approval call when needed. The approval call becomes the first object + in the final `calls` array. + + ```json theme={null} + [ + { + "target": "0x006F54F7f9A22e0000CC2AB60031000000ae9fEF", + "value": "0", + "data": "" + } + ] + ``` + + + + Set the Router inputs for the redemption. + + | Value | Source | + | -------------- | ------------------------------------- | + | `conditionId` | `` | + | `outcomeIndex` | `0` for YES, `1` for NO | + | `amount` | Shares to redeem, in share base units | + + The Router accepts `conditionId`, `outcomeIndex`, and `amount`, not `positionId`. + + + + The Router redeem function is: + + ```solidity theme={null} + function redeem(bytes31 conditionId, uint256 outcomeIndex, uint256 amount); + ``` + + Append the redeem call after the approval call from the previous step, if one was + needed. + + ```json Redeem Calls theme={null} + [ + // Include the approval call first when needed. + // … + { + "target": "0x12121212006e4CD160D18e3f00711DA5c3372600", + "value": "0", + "data": "" + } + ] + ``` + + + + Fetch a fresh `WALLET` nonce before each submission. + + ```bash theme={null} + curl -G "https://relayer-v2.polymarket.com/v1/account/transactions/params" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" \ + --data-urlencode "address=$RELAYER_API_KEY_ADDRESS" \ + --data-urlencode "type=WALLET" + ``` + + The response includes the nonce to sign with the transaction. + + ```json theme={null} + { + "address": "", + "nonce": "" + } + ``` + + + + Build the Deposit Wallet EIP-712 `Batch` typed data. + + ```json theme={null} + { + "domain": { + "name": "DepositWallet", + "version": "1", + "chainId": 137, + "verifyingContract": "" + }, + "types": { + "Call": [ + { "name": "target", "type": "address" }, + { "name": "value", "type": "uint256" }, + { "name": "data", "type": "bytes" } + ], + "Batch": [ + { "name": "wallet", "type": "address" }, + { "name": "nonce", "type": "uint256" }, + { "name": "deadline", "type": "uint256" }, + { "name": "calls", "type": "Call[]" } + ] + }, + "primaryType": "Batch", + "message": { + "wallet": "", + "nonce": "", + "deadline": "", + "calls": [ + // Use the final calls array from the previous steps. + // … + ] + } + } + ``` + + Sign the EIP-712 batch with your signer. Use the resulting signature as + `signature` in the relayer submission. + + + + Submit the signed transaction to the Relayer API. + + ```bash theme={null} + curl -X POST "https://relayer-v2.polymarket.com/submit" \ + -H "Content-Type: application/json" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" \ + -d '{ + "type": "WALLET", + "from": "", + "to": "0x00000000000Fb5C9ADea0298D729A0CB3823Cc07", + "nonce": "", + "signature": "", + "metadata": "Redeem Combo position", + "depositWalletParams": { + "depositWallet": "", + "deadline": "", + "calls": [ + // Use the final calls array from the previous steps. + // … + ] + } + }' + ``` + + The response includes the relayer transaction ID. + + ```json theme={null} + { + "transactionID": "", + "state": "STATE_NEW" + } + ``` + + + + Poll the relayer transaction until it reaches `STATE_CONFIRMED` before relying on + the redeemed balance. + + ```bash theme={null} + curl "https://relayer-v2.polymarket.com/v1/account/transactions/" \ + -H "RELAYER_API_KEY: $RELAYER_API_KEY" \ + -H "RELAYER_API_KEY_ADDRESS: $RELAYER_API_KEY_ADDRESS" + ``` + + ```json theme={null} + { + "transaction_id": "", + "transaction_hash": "", + "state": "STATE_CONFIRMED", + "error_msg": null + } + ``` + + Treat `STATE_FAILED` and `STATE_INVALID` as terminal failures. + + + + + +## 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. + + + + Use `client.listComboMarkets(...)` to page through markets that can be used as + Combo legs. + + ```ts theme={null} + const paginator = client.listComboMarkets({ pageSize: 50 }); + + for await (const page of paginator) { + // page.items: ComboMarket[] + } + ``` + + Use `exclude` to omit markets you have already shown or selected. + + ```ts theme={null} + const paginator = client.listComboMarkets({ + exclude: selectedConditionIds, + pageSize: 50, + }); + ``` + + The SDK returns structured YES and NO outcomes. + + ```ts theme={null} + type ComboMarket = { + id: MarketId; + conditionId: CtfConditionId; + slug: string; + title: string; + outcomes: { + yes: { + label: string; + positionId: PositionId; + price: DecimalString; + }; + no: { + label: string; + positionId: PositionId; + price: DecimalString; + }; + }; + image: string; + volume: number; + tags: string[]; + }; + ``` + + + + Use `client.list_combo_markets(...)` to page through markets that can be used as + Combo legs. + + ```python theme={null} + paginator = client.list_combo_markets(page_size=50) + + async for market in paginator.iter_items(): + print(market.title, market.outcomes.yes.position_id) + ``` + + Use `exclude` to omit markets you have already shown or selected. + + ```python theme={null} + paginator = client.list_combo_markets( + exclude=selected_condition_ids, + page_size=50, + ) + ``` + + The SDK returns structured YES and NO outcomes with snake\_case fields. + + ```python theme={null} + yes_position_id = market.outcomes.yes.position_id + yes_price = market.outcomes.yes.price + no_position_id = market.outcomes.no.position_id + no_price = market.outcomes.no.price + ``` + + + + Fetch the first page of Combo-enabled markets. + + ```bash theme={null} + curl -G "https://combos-rfq-api.polymarket.com/v1/rfq/combo-markets" \ + --data-urlencode "limit=50" + ``` + + Use `cursor` to fetch the next page, and use `exclude` to omit markets you have + already shown or selected. + + ```bash theme={null} + curl -G "https://combos-rfq-api.polymarket.com/v1/rfq/combo-markets" \ + --data-urlencode "limit=50" \ + --data-urlencode "cursor=" \ + --data-urlencode "exclude=," + ``` + + The response includes markets and an opaque `next_cursor`. A `null` cursor means + there are no more pages. + + ```json theme={null} + { + "markets": [ + { + "id": "1897034", + "condition_id": "0x4cd7...110ff", + "position_ids": ["1012585...362880", "1012585...362881"], + "slug": "fifwc-mex-rsa-2026-06-11-mex", + "title": "Will Mexico win on 2026-06-11?", + "outcomes": ["Yes", "No"], + "outcome_prices": ["0.685", "0.315"], + "image": "https://...", + "volume": 330327.7128580074, + "tags": ["sports", "soccer", "games", "world-cup"] + } + ], + "next_cursor": "Mg" + } + ``` + + For each market, `position_ids`, `outcomes`, and `outcome_prices` are aligned by + array index. Index `0` is the YES outcome, and index `1` is the NO outcome. + + + +## 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. + + + + Fetch non-closed markets and index them by position ID in your own market data + store. + + ```ts theme={null} + for await (const page of client.listMarkets({ closed: false })) { + for (const market of page.items) { + for (const positionId of market.positionIds) { + marketByPositionId.set(positionId, market); + } + } + } + ``` + + 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. + + ```ts theme={null} + const page = await client + .listMarkets({ + positionIds: event.legPositionIds, + }) + .firstPage(); + + const markets = page.items; + ``` + + + + Fetch non-closed markets and index them by position ID in your own market data + store. + + ```python theme={null} + async for market in client.list_markets(closed=False).iter_items(): + for position_id in market.position_ids: + market_by_position_id[position_id] = market + ``` + + 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. + + ```python theme={null} + page = await client.list_markets( + position_ids=event.leg_position_ids, + ).first_page() + + markets = page.items + ``` + + + + Use Gamma `GET /markets` to resolve Combo leg position IDs into market metadata. + Build this mapping outside the quote path. + + ```bash theme={null} + curl -G "https://gamma-api.polymarket.com/markets" \ + --data-urlencode "closed=false" \ + --data-urlencode "limit=100" + ``` + + Index every returned market by `positionIds`. + + ```json theme={null} + { + "id": "", + "conditionId": "", + "question": "Will example happen?", + "positionIds": ["", ""] + } + ``` + + You can also resolve markets by leg position ID on demand, but avoid doing this + inside the **400 ms** quote window. + + ```bash theme={null} + curl -G "https://gamma-api.polymarket.com/markets" \ + --data-urlencode "position_ids=" \ + --data-urlencode "position_ids=" + ``` + + + +## 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. + + + + + + First, switch on `event.type` to handle execution updates from the same session + stream. + + ```ts theme={null} + switch (event.type) { + case "execution_update": + // event: RfqExecutionUpdateEvent + handleExecutionUpdate(event); + break; + + // … + } + ``` + + + + Then, inspect the execution update before reconciling the selected RFQ. Execution + updates are correlated by `rfqId`. + + ```ts theme={null} + type RfqExecutionUpdateEvent = { + type: "execution_update"; + rfqId: RfqId; + status: RfqExecutionStatus; + txHash?: TxHash; + }; + ``` + + where `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. | + + + + Finally, persist the update and treat `RfqExecutionStatus.Confirmed` and + `RfqExecutionStatus.Failed` as terminal states. + + ```ts theme={null} + function handleExecutionUpdate(event: RfqExecutionUpdateEvent) { + storeExecutionUpdate(event); + + if (event.status === RfqExecutionStatus.Confirmed) { + markQuoteConfirmed(event.rfqId); + return; + } + + if (event.status === RfqExecutionStatus.Failed) { + markQuoteFailed(event.rfqId); + } + } + ``` + + + + + + + + First, use `isinstance(...)` to handle execution updates from the same session + stream. + + ```python theme={null} + from polymarket import RfqExecutionUpdateEvent + + + async for event in session: + if isinstance(event, RfqExecutionUpdateEvent): + handle_execution_update(event) + ``` + + + + Then, inspect the execution update before reconciling the selected RFQ. Execution + updates are correlated by `rfq_id`. + + ```python theme={null} + class RfqExecutionUpdateEvent: + type: "execution_update" + rfq_id: RfqId + status: RfqExecutionStatus + tx_hash: TransactionHash | None + ``` + + where `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. | + + + + Finally, persist the update and treat `RfqExecutionStatus.CONFIRMED` and + `RfqExecutionStatus.FAILED` as terminal states. + + ```python theme={null} + from polymarket import RfqExecutionStatus, RfqExecutionUpdateEvent + + + def handle_execution_update(event: RfqExecutionUpdateEvent) -> None: + store_execution_update(event) + + if event.status is RfqExecutionStatus.CONFIRMED: + mark_quote_confirmed(event.rfq_id) + return + + if event.status is RfqExecutionStatus.FAILED: + mark_quote_failed(event.rfq_id) + ``` + + + + + + Listen for `RFQ_EXECUTION_UPDATE` messages on the RFQ WebSocket after one of your + quotes is selected. + + ```json theme={null} + { + "type": "RFQ_EXECUTION_UPDATE", + "rfq_id": "", + "status": "MINED", + "tx_hash": "" + } + ``` + + Execution updates are correlated by `rfq_id`. + + | Status | Meaning | + | ----------- | ------------------------------------------------- | + | `MATCHED` | The quote was selected and handed off to execute. | + | `MINED` | The execution transaction was mined. | + | `RETRYING` | Execution is being retried. | + | `CONFIRMED` | Execution completed successfully. | + | `FAILED` | Execution failed. | + + Treat `CONFIRMED` and `FAILED` as terminal states. + + + +## Handle Errors + +In this section, we will talk you through how to handle errors with the RFQ system. + + + + ### Open the RFQ Session + + Wrap `client.openRfqSession()` in `try`/`catch` and use + `OpenRfqSessionError.isError(…)` to narrow the error type. + + ```ts theme={null} + try { + const session = await client.openRfqSession(); + } catch (error) { + if (!OpenRfqSessionError.isError(error)) throw error; + + switch (error.name) { + case "TransportError": + // error: TransportError + break; + } + } + ``` + + ### Submit a Quote + + Wrap `event.quote(…)` in `try`/`catch` and use `RfqQuoteError.isError(…)` to + narrow the error type. + + ```ts theme={null} + try { + const reference = await event.quote({ price }); + // … + } catch (error) { + if (!RfqQuoteError.isError(error)) throw error; + + switch (error.name) { + case "RfqQuoteRejectedError": + // error: RfqQuoteRejectedError + // error.rfqId: RfqId + // error.code: RfqErrorCode | undefined + break; + case "SigningError": + // error: SigningError + break; + case "TimeoutError": + // error: TimeoutError + break; + case "TransportError": + // error: TransportError + break; + case "UserInputError": + // error: UserInputError + break; + } + } + ``` + + ### Cancel a Quote + + Wrap `session.cancelQuote(…)` in `try`/`catch` and use + `RfqCancelQuoteError.isError(…)` to narrow the error type. + + ```ts theme={null} + try { + const ack = await session.cancelQuote(reference); + // … + } catch (error) { + if (!RfqCancelQuoteError.isError(error)) throw error; + + switch (error.name) { + case "RfqCancelQuoteRejectedError": + // error: RfqCancelQuoteRejectedError + // error.rfqId: RfqId + // error.quoteId: RfqQuoteId + // error.code: RfqErrorCode | undefined + break; + case "TimeoutError": + // error: TimeoutError + break; + case "TransportError": + // error: TransportError + break; + } + } + ``` + + ### Confirm or Decline + + Wrap `event.confirm()` or `event.decline()` in `try`/`catch` and use + `RfqConfirmationError.isError(…)` to narrow the error type. + + ```ts theme={null} + try { + if (canStillFill) { + await event.confirm(); + } else { + await event.decline(); + } + } catch (error) { + if (!RfqConfirmationError.isError(error)) throw error; + + switch (error.name) { + case "RfqConfirmationRejectedError": + // error: RfqConfirmationRejectedError + // error.rfqId: RfqId + // error.quoteId: RfqQuoteId + // error.code: RfqErrorCode | undefined + break; + case "TimeoutError": + // error: TimeoutError + break; + case "TransportError": + // error: TransportError + break; + } + } + ``` + + + + ### Open the RFQ Session + + Wrap `client.open_rfq_session()` in `try`/`except` and catch SDK exception types. + + ```python theme={null} + from polymarket import TimeoutError, TransportError + + + try: + async with client.open_rfq_session() as session: + async for event in session: + ... + except TimeoutError as error: + # error: TimeoutError + ... + except TransportError as error: + # error: TransportError + ... + ``` + + ### Submit a Quote + + Wrap `event.quote(...)` in `try`/`except` and catch the typed RFQ rejection, + timeout, and transport errors. + + ```python theme={null} + from decimal import Decimal + + from polymarket import RfqQuoteRejectedError, TimeoutError, TransportError + + + try: + reference = await event.quote(price=Decimal("0.45")) + except RfqQuoteRejectedError as error: + # error.rfq_id: RfqId + # error.code: RfqErrorCode | None + ... + except TimeoutError as error: + # error: TimeoutError + ... + except TransportError as error: + # error: TransportError + ... + ``` + + ### Cancel a Quote + + Wrap `session.cancel_quote(...)` in `try`/`except` and catch the typed RFQ + cancellation rejection, timeout, and transport errors. + + ```python theme={null} + from polymarket import RfqCancelQuoteRejectedError, TimeoutError, TransportError + + + try: + ack = await session.cancel_quote(reference) + except RfqCancelQuoteRejectedError as error: + # error.rfq_id: RfqId + # error.quote_id: RfqQuoteId + # error.code: RfqErrorCode | None + ... + except TimeoutError as error: + # error: TimeoutError + ... + except TransportError as error: + # error: TransportError + ... + ``` + + ### Confirm or Decline + + Wrap `event.confirm()` or `event.decline()` in `try`/`except` and catch the typed + RFQ confirmation rejection, timeout, and transport errors. + + ```python theme={null} + from polymarket import RfqConfirmationRejectedError, TimeoutError, TransportError + + + try: + if can_still_fill: + await event.confirm() + else: + await event.decline() + except RfqConfirmationRejectedError as error: + # error.rfq_id: RfqId + # error.quote_id: RfqQuoteId + # error.code: RfqErrorCode | None + ... + except TimeoutError as error: + # error: TimeoutError + ... + except TransportError as error: + # error: TransportError + ... + ``` + + + + When a WebSocket command fails validation or cannot be applied, the RFQ system + sends `RFQ_ERROR`. + + ```json theme={null} + { + "type": "RFQ_ERROR", + "request_type": "RFQ_QUOTE", + "rfq_id": "", + "quote_id": "", + "code": "SUBMISSION_WINDOW_CLOSED", + "error": "submission window closed" + } + ``` + + Use `request_type`, `rfq_id`, and `quote_id` to correlate the error with the + command you sent. + + | Field | Description | + | -------------- | ----------------------------------------------- | + | `type` | Always `RFQ_ERROR` | + | `request_type` | Inbound command that failed, when parsed | + | `rfq_id` | RFQ ID, when present on the failed command | + | `quote_id` | Quote ID, when present on the failed command | + | `code` | Stable machine-readable error code | + | `error` | Human-readable detail for logging and debugging | + + The `request_type` value identifies the command that failed. + + | `request_type` | Failed command | + | --------------------------- | --------------------------------- | + | `RFQ_QUOTE` | Quote submission | + | `RFQ_QUOTE_CANCEL` | Quote cancellation | + | `RFQ_CONFIRMATION_RESPONSE` | Last Look confirmation or decline | + + Error codes include: + + | Code | Meaning | + | ------------------------------------------ | -------------------------------------------------------------- | + | `INVALID_MESSAGE` | Message JSON or message type is invalid | + | `UNAUTHORIZED_ROLE` | Message is not allowed for the authenticated gateway role | + | `ADDRESS_MISMATCH` | Message identity does not match the authenticated session | + | `UNKNOWN_RFQ` | RFQ ID is not active or no longer exists | + | `EXPIRED_RFQ` | RFQ has expired | + | `SUBMISSION_WINDOW_CLOSED` | Quote arrived after the submission window closed | + | `ALLOWANCE_VALIDATION_FAILED` | Maker allowance is insufficient for the quoted order | + | `BALANCE_VALIDATION_FAILED` | Maker balance is insufficient for the quoted order | + | `PRE_EXECUTION_BALANCE_RESERVATION_FAILED` | Balance reservation failed before execution | + | `INVALID_QUOTE` | Quote payload or signed order is invalid | + | `INVALID_RFQ_STATE` | RFQ is not in a state that accepts the requested command | + | `INVALID_CONFIRMATION` | Last Look confirmation payload is invalid | + | `MAKER_NOT_REQUIRED` | This quote maker is not required for last-look confirmation | + | `MAKER_ALREADY_RESPONDED` | This quote maker already responded to the confirmation request | + | `SERVICE_UNAVAILABLE` | RFQ service dependency is temporarily unavailable | + + Treat these errors as command-level failures. Keep the WebSocket session alive + unless the connection itself closes or authentication fails. + + diff --git a/docs/quickstart/reference/glossary.md b/docs/quickstart/reference/glossary.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/quickstart/reference/glossary.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/docs/trading/bridge/overview.md b/docs/trading/bridge/overview.md deleted file mode 100644 index ec747fa..0000000 --- a/docs/trading/bridge/overview.md +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file