Skip to main content

Quoter Gateway

The primary channel is WebSocket. REST is a fallback for quoter commands and does not stream RFQ requests, confirmation requests, or execution updates. Quoter gateway websocket:
wss://combos-rfq-gateway-quoter.polymarket.com/ws/rfq
To see a preview of the trade stream:
wscat -c wss://combos-rfq-gateway-quoter.polymarket.com/ws/rfq
TransportPathUse
WebSocketGET /ws or GET /ws/rfqAuth, RFQ stream, quote submission, quote cancellation, last-look responses
RESTSee REST EndpointsQuote submission, quote cancellation, last-look responses

Connection Requirements

  • Send the auth message as the first WebSocket message within 30 seconds.
  • The gateway sends WebSocket ping control frames every 30 seconds with payload rfq.
  • Your client must respond with pong control frames. Most WebSocket clients do this automatically.
  • The gateway closes stale connections after 2 minutes without an inbound message or pong.
  • The gateway responds to client ping control frames with pong control frames.

Authentication

WebSocket Auth

Authenticate with CLOB API credentials and the signer/maker identity used for RFQ orders. See Getting API Credentials to create or derive CLOB API keys.
ServiceURL
CLOBhttps://clob.polymarket.com
Quoter WebSocketwss://combos-rfq-gateway-quoter.polymarket.com/ws/rfq
Polygon mainnet chain ID 137 is used for CLOB authentication and Exchange v3 order signing. Create or derive production CLOB credentials:
POST <CLOB_HOST>/auth/api-key
GET  <CLOB_HOST>/auth/derive-api-key
Use the returned apiKey, secret, and passphrase in the websocket auth message below.
{
  "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
  }
}
FieldTypeDescription
auth.apiKeystringCLOB API key
auth.secretstringCLOB API secret
auth.passphrasestringCLOB API passphrase
identity.signer_addressstringAddress that signs orders
identity.maker_addressstringWallet that funds orders
identity.signature_typenumbersignature type
Identity rules by signature type:
Signature typesigner_addressmaker_address / funder
0 EOAEOA addressSame EOA address
1 ProxyAuthenticated signing addressDerived proxy wallet
2 SafeAuthenticated signing addressDerived Safe wallet
3 POLY_1271Deposit wallet addressSame deposit wallet address
For POLY_1271, the CLOB API-key owner may be different from the deposit wallet, but the signed RFQ order must use the deposit wallet as both signer and maker. For more detail, see CLOB signature types and the Deposit Wallet order signing guide.

Production Onboarding

Production RFQ participation is currently onboarding-based. Before connecting a production quoter:
  1. Share the intended signer_address, maker_address, and signature_type with your Polymarket onboarding contact.
  2. Confirm the quoter’s RFQ tier and whether last look is enabled.
  3. Create or derive production CLOB credentials against https://clob.polymarket.com.
  4. Fund the maker_address with the pUSD or combo positions needed for the orders it will quote.
  5. Complete the Exchange v3 approvals from the maker_address.
  6. Connect to wss://combos-rfq-gateway-quoter.polymarket.com/ws/rfq.
  7. Send the auth message as the first application message.
Successful auth response:
{
  "type": "auth",
  "success": true,
  "address": "0xAuthenticatedAddress"
}
Failed auth response:
{
  "type": "auth",
  "success": false,
  "error": "unauthenticated"
}

Exchange v3 Approvals

Before submitting RFQ quotes, the quoter’s maker_address must approve Exchange v3 to spend the assets used for combinatorial RFQ settlement. AutoRedeemer approval is optional and only needed for redeeming resolved positions through AutoRedeemer.
ApprovalRequired for RFQ execution?Contract call
pUSD collateralYesCollateralToken.approve(ExchangeV3, maxUint256)
Combo positionsYesPositionManager.setApprovalForAll(ExchangeV3, true)
AutoRedeemer position approvalNoPositionManager.setApprovalForAll(AutoRedeemer, true)
Mainnet contract addresses:
ContractAddress
CollateralToken0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB
PositionManager0x006F54F7f9A22e0000CC2AB60031000000ae9fEF
ExchangeV30xe3333700cA9d93003F00f0F71f8515005F6c00Aa
AutoRedeemer0xa1200000d0002264C9a1698e001292D00E1b00af
Run approval scripts locally. Never paste private keys into hosted tools, shared terminals, or browser consoles.
For EOA makers, this self-contained script checks current approvals and submits only the missing transactions. It includes the optional AutoRedeemer approval.
import {
  createPublicClient,
  createWalletClient,
  http,
  maxUint256,
  parseAbi,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";

const POLYGON_CHAIN_ID = 137;
const POLYGON_CHAIN = {
  id: POLYGON_CHAIN_ID,
  name: "Polygon",
  nativeCurrency: { decimals: 18, name: "POL", symbol: "POL" },
  rpcUrls: { default: { http: ["https://polygon-rpc.com"] } },
} as const;

const COLLATERAL_TOKEN = "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB";
const POSITION_MANAGER = "0x006F54F7f9A22e0000CC2AB60031000000ae9fEF";
const EXCHANGE_V3 = "0xe3333700cA9d93003F00f0F71f8515005F6c00Aa";
const AUTO_REDEEMER = "0xa1200000d0002264C9a1698e001292D00E1b00af";

const ERC20_ABI = parseAbi([
  "function allowance(address,address) view returns (uint256)",
  "function approve(address,uint256) returns (bool)",
]);

const ERC1155_ABI = parseAbi([
  "function isApprovedForAll(address,address) view returns (bool)",
  "function setApprovalForAll(address,bool)",
]);

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required env: ${name}`);
  return value;
}

async function main() {
  const account = privateKeyToAccount(requiredEnv("PK") as `0x${string}`);
  const rpcUrl = requiredEnv("RPC_URL");

  const collateral = COLLATERAL_TOKEN as `0x${string}`;
  const positionManager = POSITION_MANAGER as `0x${string}`;
  const exchangeV3 = EXCHANGE_V3 as `0x${string}`;
  const autoRedeemer = AUTO_REDEEMER as `0x${string}`;

  const publicClient = createPublicClient({
    chain: POLYGON_CHAIN,
    transport: http(rpcUrl),
  });
  const walletClient = createWalletClient({
    account,
    chain: POLYGON_CHAIN,
    transport: http(rpcUrl),
  });

  console.log(`Address:          ${account.address}`);
  console.log(`Chain ID:         ${POLYGON_CHAIN_ID}`);
  console.log(`Collateral token: ${collateral}`);
  console.log(`PositionManager:  ${positionManager}`);
  console.log(`ExchangeV3:       ${exchangeV3}`);
  console.log(`AutoRedeemer:     ${autoRedeemer}`);

  const [collateralAllowance, positionsApproved, autoRedeemerApproved] =
    await Promise.all([
      publicClient.readContract({
        address: collateral,
        abi: ERC20_ABI,
        functionName: "allowance",
        args: [account.address, exchangeV3],
      }),
      publicClient.readContract({
        address: positionManager,
        abi: ERC1155_ABI,
        functionName: "isApprovedForAll",
        args: [account.address, exchangeV3],
      }),
      publicClient.readContract({
        address: positionManager,
        abi: ERC1155_ABI,
        functionName: "isApprovedForAll",
        args: [account.address, autoRedeemer],
      }),
    ]);

  console.log("\nCurrent state:");
  console.log(`  Collateral -> ExchangeV3: ${collateralAllowance}`);
  console.log(`  Positions  -> ExchangeV3: ${positionsApproved}`);
  console.log(`  Positions  -> AutoRedeemer: ${autoRedeemerApproved}`);

  if (collateralAllowance === 0n) {
    const hash = await walletClient.writeContract({
      address: collateral,
      abi: ERC20_ABI,
      functionName: "approve",
      args: [exchangeV3, maxUint256],
    });
    console.log(`\nSetting collateral allowance for ExchangeV3: ${hash}`);
    await publicClient.waitForTransactionReceipt({ hash });
  }

  if (!positionsApproved) {
    const hash = await walletClient.writeContract({
      address: positionManager,
      abi: ERC1155_ABI,
      functionName: "setApprovalForAll",
      args: [exchangeV3, true],
    });
    console.log(`\nSetting PositionManager approval for ExchangeV3: ${hash}`);
    await publicClient.waitForTransactionReceipt({ hash });
  }

  if (!autoRedeemerApproved) {
    const hash = await walletClient.writeContract({
      address: positionManager,
      abi: ERC1155_ABI,
      functionName: "setApprovalForAll",
      args: [autoRedeemer, true],
    });
    console.log(`\nSetting PositionManager approval for AutoRedeemer: ${hash}`);
    await publicClient.waitForTransactionReceipt({ hash });
  }

  console.log("\nExchangeV3 and AutoRedeemer approvals set");
}

main();
Run with:
npm install viem tsx
PK=0x... RPC_URL=https://... npx tsx approve-exchange-v3.ts
If your maker_address is a contract wallet, proxy wallet, Safe, or deposit wallet, the approval transactions must be submitted by that wallet. An approvals UI for all wallet types, including deposit wallets, will be available shortly.

Message Schemas

RFQ_REQUEST

Gateway to quoter. Broadcasts an active RFQ request.
{
  "type": "RFQ_REQUEST",
  "rfq_id": "rfq_<id>",
  "requestor_public_id": "req_<public_id>",
  "leg_position_ids": ["<leg_position_id_1>", "<leg_position_id_2>"],
  "condition_id": "0x<condition_id>",
  "yes_position_id": "<yes_position_id>",
  "no_position_id": "<no_position_id>",
  "direction": "BUY",
  "side": "YES",
  "requested_size": {
    "unit": "notional",
    "value_e6": "1000000"
  },
  "submission_deadline": "<unix_milliseconds>"
}
FieldTypeDescription
typestringAlways RFQ_REQUEST
rfq_idstringServer-assigned RFQ ID
requestor_public_idstringOpaque public ID for the RFQ source
leg_position_idsarrayCanonical leg position IDs in the combo
condition_idstringDerived combinatorial condition ID
yes_position_idstringDerived YES combo position ID
no_position_idstringDerived NO combo position ID
directionstringBUY or SELL
sidestringCurrently YES
requested_sizeobjectRequested RFQ size and unit
submission_deadlinenumberQuote submission deadline in Unix milliseconds
requested_size.unit is notional for requester BUY RFQs and shares for requester SELL RFQs. requested_size.value_e6 is a six-decimal fixed-point value encoded as a string.
leg_position_ids are the constituent legs for the combinatorial position being requested. Note that each leg can be either a YES or NO outcome.You can retrieve market information for each leg by using the following Gamma API endpoint: https://gamma-api.polymarket.com/markets?position_ids=<position_id>

RFQ_QUOTE

Quoter to gateway. Submit before submission_deadline.
{
  "type": "RFQ_QUOTE",
  "rfq_id": "rfq_<id>",
  "price_e6": "450000",
  "size_e6": "1000000",
  "signed_order": {
    "salt": "<order_salt>",
    "maker": "0xYourQuoterWallet",
    "signer": "0xYourSigner",
    "tokenId": "<yes_or_no_position_id>",
    "makerAmount": "<amount_to_pay>",
    "takerAmount": "<taker_amount>",
    "side": 0,
    "signatureType": 0,
    "timestamp": "<unix_seconds>",
    "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "builder": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "0x..."
  }
}
FieldTypeDescription
typestringAlways RFQ_QUOTE
rfq_idstringRFQ ID from RFQ_REQUEST
price_e6stringQuote price in six-decimal fixed-point units
size_e6stringFillable share count in six-decimal fixed-point units. Note that this differs from the request’s size field, which may be notional or share count.
signed_orderobjectSigned Exchange v3 order
All public *_e6 fixed-point fields are encoded as strings to avoid number precision issues. Use direction from RFQ_REQUEST to choose the signed order side and token:
RFQ directionQuoter ordersigned_order.sidesigned_order.tokenId
BUYBuy the complementary NO position with pUSD0no_position_id
BUYSell the YES position for pUSD1yes_position_id
SELLBuy the YES position with pUSD0yes_position_id
SELLSell the complementary NO position for pUSD1no_position_id
RFQ trades for Combinatorial positions settle through a distinct Exchange contract, called Exchange v3. You can find more details about signing orders for Exchange v3 here.

ACK_RFQ_QUOTE

Gateway to quoter.
{
  "type": "ACK_RFQ_QUOTE",
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>"
}

RFQ_QUOTE_CANCEL

Quoter to gateway. Cancel an active quote before the end of the competition window.
{
  "type": "RFQ_QUOTE_CANCEL",
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>",
  "signer_address": "0xYourSigner",
  "maker_address": "0xYourQuoterWallet"
}
FieldTypeDescription
typestringAlways RFQ_QUOTE_CANCEL
rfq_idstringRFQ ID
quote_idstringServer-generated quote ID
signer_addressstringMust match authenticated signer_address
maker_addressstringMust match authenticated maker_address

ACK_RFQ_QUOTE_CANCEL

Gateway to quoter.
{
  "type": "ACK_RFQ_QUOTE_CANCEL",
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>"
}

RFQ_CONFIRMATION_REQUEST

Gateway to quoter. Sent when the quote’s maker is Tier 1 and has last-look enabled.
{
  "type": "RFQ_CONFIRMATION_REQUEST",
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>",
  "signer_address": "0xYourSigner",
  "maker_address": "0xYourQuoterWallet",
  "signature_type": 0,
  "leg_position_ids": ["<leg_position_id_1>", "<leg_position_id_2>"],
  "condition_id": "0x<condition_id>",
  "yes_position_id": "<yes_position_id>",
  "no_position_id": "<no_position_id>",
  "direction": "BUY",
  "side": "YES",
  "fill_size_e6": "1000000",
  "price_e6": "450000",
  "confirm_by": "<unix_milliseconds>"
}
FieldTypeDescription
typestringAlways RFQ_CONFIRMATION_REQUEST
rfq_idstringRFQ ID
quote_idstringSelected quote ID
signer_addressstringSelected signer address
maker_addressstringSelected quoter wallet
signature_typenumberSelected signature type
leg_position_idsstring[]Combo leg position IDs
condition_idstringDerived combinatorial condition ID
yes_position_idstringDerived YES combo position ID
no_position_idstringDerived NO combo position ID
directionstringBUY or SELL
sidestringCurrently YES
fill_size_e6stringSelected fill size in six-decimal fixed-point units
price_e6stringSelected quote price in six-decimal fixed-point units
confirm_bynumberConfirmation deadline in Unix milliseconds

RFQ_CONFIRMATION_RESPONSE

Quoter to gateway. Respond before confirm_by.
{
  "type": "RFQ_CONFIRMATION_RESPONSE",
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>",
  "decision": "CONFIRM"
}
FieldTypeDescription
typestringAlways RFQ_CONFIRMATION_RESPONSE
rfq_idstringRFQ ID
quote_idstringSelected quote ID
decisionstringCONFIRM or DECLINE
Do not include top-level signer_address, maker_address, or signature_type in RFQ_CONFIRMATION_RESPONSE. The gateway applies identity from the authenticated session.

ACK_RFQ_CONFIRMATION_RESPONSE

Gateway to quoter.
{
  "type": "ACK_RFQ_CONFIRMATION_RESPONSE",
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>",
  "decision": "CONFIRM"
}

RFQ_EXECUTION_UPDATE

Gateway to selected quoters.
{
  "type": "RFQ_EXECUTION_UPDATE",
  "rfq_id": "rfq_<id>",
  "status": "MINED",
  "tx_hash": "0x<transaction_hash>"
}
FieldTypeDescription
typestringAlways RFQ_EXECUTION_UPDATE
rfq_idstringRFQ ID
statusstringMATCHED, MINED, RETRYING, CONFIRMED, or FAILED
tx_hashstringTransaction hash, when available
CONFIRMED and FAILED are terminal.

RFQ_ERROR

Gateway to quoter. Sent when a command fails validation or cannot be applied.
{
  "type": "RFQ_ERROR",
  "request_type": "RFQ_QUOTE",
  "rfq_id": "rfq_<id>",
  "code": "SUBMISSION_WINDOW_CLOSED",
  "error": "submission window closed"
}
FieldTypeDescription
typestringAlways RFQ_ERROR
request_typestringInbound command that failed, when parsed
rfq_idstringRFQ ID, when present on the failed command
quote_idstringQuote ID, when present on the failed command
codestringStable machine-readable error code
errorstringHuman-readable error detail for logging and debugging
Quoter error codes:
CodeMeaning
INVALID_MESSAGEMessage JSON or message type is invalid
UNAUTHORIZED_ROLEMessage is not allowed for the authenticated gateway role
ADDRESS_MISMATCHMessage identity does not match the authenticated session
ALLOWANCE_VALIDATION_FAILEDMaker allowance is insufficient for the quoted order
BALANCE_VALIDATION_FAILEDMaker balance is insufficient for the quoted order
UNKNOWN_RFQRFQ ID is not active or no longer exists
EXPIRED_RFQRFQ has expired
SUBMISSION_WINDOW_CLOSEDQuote arrived after the submission window closed
INVALID_QUOTEQuote payload or signed order is invalid
INVALID_RFQ_STATERFQ is not in a state that accepts the requested command
INVALID_CONFIRMATIONLast-look confirmation payload is invalid
MAKER_NOT_REQUIREDThis quote maker is not required for last-look confirmation
MAKER_ALREADY_RESPONDEDThis quote maker already responded to the confirmation request
PRE_EXECUTION_BALANCE_RESERVATION_FAILEDBalance reservation failed before execution
SERVICE_UNAVAILABLERFQ service dependency is temporarily unavailable

Signing Orders With Viem

Use the Exchange v3 address and order-signing chain ID provided during onboarding. The example below signs a BUY order for the token the quoter should buy for a request.
import { privateKeyToAccount } from "viem/accounts";

const ZERO_BYTES32 = `0x${"00".repeat(32)}`;
const ORDER_SIDE_BUY = 0;

const ORDER_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" },
  ],
} as const;

function ceilDiv(numerator: bigint, denominator: bigint) {
  return (numerator + denominator - 1n) / denominator;
}

function quoterBuyTokenId(request: {
  direction: "BUY" | "SELL";
  yes_position_id: string;
  no_position_id: string;
}) {
  return request.direction === "BUY"
    ? request.no_position_id
    : request.yes_position_id;
}

function quoterBuyOrderPriceE6(
  request: { direction: "BUY" | "SELL" },
  quotePriceE6: string,
) {
  const price = BigInt(quotePriceE6);
  return request.direction === "BUY" ? 1_000_000n - price : price;
}

function requestedSizeE6(request: {
  requested_size: { unit: "notional" | "shares"; value_e6: string };
}) {
  return BigInt(request.requested_size.value_e6);
}

export async function buildSignedBuyOrder({
  privateKey,
  request,
  quotePriceE6,
  exchangeV3,
  chainId,
  signerAddress,
  quoterWalletAddress,
  signatureType = 0,
}: {
  privateKey: `0x${string}`;
  request: {
    direction: "BUY" | "SELL";
    yes_position_id: string;
    no_position_id: string;
    requested_size: { unit: "notional" | "shares"; value_e6: string };
  };
  quotePriceE6: string;
  exchangeV3: `0x${string}`;
  chainId: number;
  signerAddress: `0x${string}`;
  quoterWalletAddress: `0x${string}`;
  signatureType?: number;
}) {
  const account = privateKeyToAccount(privateKey);
  const sizeE6 = requestedSizeE6(request);
  const orderPriceE6 = quoterBuyOrderPriceE6(request, quotePriceE6);
  const amountToPay = ceilDiv(orderPriceE6 * sizeE6, 1_000_000n);
  const order = {
    salt: `${BigInt(Date.now()) * 1_000_000n + BigInt(Math.floor(Math.random() * 1_000_000))}`,
    maker: quoterWalletAddress.toLowerCase(),
    signer: signerAddress.toLowerCase(),
    tokenId: quoterBuyTokenId(request),
    makerAmount: amountToPay.toString(),
    takerAmount: sizeE6.toString(),
    side: ORDER_SIDE_BUY,
    signatureType,
    timestamp: String(Math.floor(Date.now() / 1000)),
    metadata: ZERO_BYTES32,
    builder: ZERO_BYTES32,
  };

  const signature = await account.signTypedData({
    domain: {
      name: "Polymarket CTF Exchange",
      version: "3",
      chainId,
      verifyingContract: exchangeV3,
    },
    types: ORDER_TYPES,
    primaryType: "Order",
    message: {
      salt: BigInt(order.salt),
      maker: order.maker as `0x${string}`,
      signer: order.signer as `0x${string}`,
      tokenId: BigInt(order.tokenId),
      makerAmount: BigInt(order.makerAmount),
      takerAmount: BigInt(order.takerAmount),
      side: order.side,
      signatureType: order.signatureType,
      timestamp: BigInt(order.timestamp),
      metadata: order.metadata as `0x${string}`,
      builder: order.builder as `0x${string}`,
    },
  });

  return { ...order, signature };
}
Use the returned object as signed_order in RFQ_QUOTE.

REST Endpoints

Get Combo Markets

Returns active markets that can be used as combo legs. This endpoint is public and does not require CLOB authentication.
GET https://combos-rfq-api.polymarket.com/v1/rfq/combo-markets
Query parameterTypeDescription
limitintegerNumber of markets to return. Defaults to 50; maximum 100.
cursorstringOpaque cursor returned as next_cursor by the previous response.
excludestringComma-separated condition IDs to omit, such as markets already shown.
Markets are ordered by volume descending. Use next_cursor unchanged in the next request; a value of null indicates the final page.
{
  "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"
}
The entries in position_ids, outcomes, and outcome_prices correspond by array index.

Authenticated Maker Commands

The remaining REST endpoints use CLOB L2 HTTP authentication. See Getting API Credentials and L2 Authentication Headers.
MethodRouteUse
POST/v1/maker/quotesSubmit a quote
POST/v1/maker/quotes/cancelCancel a quote
POST/v1/maker/confirmationsConfirm or decline last look

POST /v1/maker/quotes

REST does not assign a quote ID. Generate quote_id client-side.
{
  "quote_id": "quote_<id>",
  "rfq_id": "rfq_<id>",
  "signer_address": "0xYourSigner",
  "maker_address": "0xYourQuoterWallet",
  "signature_type": 0,
  "price_e6": "450000",
  "size_e6": "1000000",
  "signed_order": {
    "salt": "<order_salt>",
    "maker": "0xYourQuoterWallet",
    "signer": "0xYourSigner",
    "tokenId": "<yes_or_no_position_id>",
    "makerAmount": "<amount_to_pay>",
    "takerAmount": "<taker_amount>",
    "side": 0,
    "signatureType": 0,
    "timestamp": "<unix_seconds>",
    "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "builder": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "0x..."
  }
}

POST /v1/maker/quotes/cancel

{
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>",
  "signer_address": "0xYourSigner",
  "maker_address": "0xYourQuoterWallet",
  "signature_type": 0
}

POST /v1/maker/confirmations

{
  "rfq_id": "rfq_<id>",
  "quote_id": "quote_<id>",
  "signer_address": "0xYourSigner",
  "maker_address": "0xYourQuoterWallet",
  "signature_type": 0,
  "decision": "CONFIRM"
}

Reading Combos (Data API)

Combos created through RFQ are queryable from the Data API. A combo trade in a user’s activity feed is flagged with isCombo (flag only — no legs embedded); its conditionId equals the combo’s combo_condition_id. Collect those ids and pass them as market_id (CSV) to fetch combo detail. These endpoints are available on the Data API:
https://data-api.polymarket.com

GET /v1/positions/combos

Current combo positions for a user, with per-leg breakdown. Also at /v1/data/user/{address}/positions/combos.
// GET https://data-api.polymarket.com/v1/positions/combos?user=0x840E…&market_id=0x0391…
{
  "combos": [
    {
      "combo_condition_id": "0x0391ab0e…",
      "status": "OPEN",
      "shares_balance": "44.000000",
      "entry_cost_usdc": "11.00",
      "legs_total": 2,
      "legs": [
        {
          "leg_outcome_label": "Yes",
          "market": {
            "title": "Korea Republic",
            "slug": "fifwc-kr-cze-2026-06-11-kr"
          }
        }
      ]
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "has_more": false,
    "next_cursor": null
  }
}

GET /v1/activity/combos

Combo lifecycle and redeem events (split / merge / convert / redeem) for a user, same per-leg shape. Also at /v1/data/user/{address}/activity/combos.
// GET https://data-api.polymarket.com/v1/activity/combos?user=0x840E…&market_id=0x0391…
{
  "activity": [
    {
      "side": "Split",
      "combo_condition_id": "0x0391ab0e…",
      "amount_usdc": 20,
      "payout_usdc": null,
      "tx_hash": "0x5ac1aa40…",
      "timestamp": 1780575184,
      "legs": [
        { "leg_outcome_label": "Yes", "market": { "title": "Korea Republic" } },
        { "leg_outcome_label": "Yes", "market": { "title": "Mexico" } }
      ]
    }
  ],
  "pagination": {
    "limit": 50,
    "offset": 0,
    "has_more": false,
    "next_cursor": null
  }
}