Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Exchange API (Beta)

POST /exchange carries every signed write: orders, cancels, leverage and margin changes, agent authorization, fund movements, and builder-code actions. action.type selects the operation; each one has its own page with a Try it panel that signs and sends it on testnet.

How to sign and wrap an action is covered once, in Signing. The TypeScript SDK does it for you.

Actions

Trading actions are signed by an agent key, authorized once with approveAgent. Fund movements and authorizations are signed by the account key itself.

ActionSigned byWhat it does
Account
approveAgentAccount keyAuthorize — or revoke — an agent key
tokenSendAccount keyMove tokens between sub-accounts, to another user, or to a TxRelay peg
withdraw3Account keyWithdraw USDC to Arbitrum via Bridge2
Orders
orderAgent keyPlace up to 50 orders in one action
cancelAgent keyCancel up to 200 orders by order id
cancelByCloidAgent keyCancel up to 200 orders by client order id
modify2Agent keyAmend a resting order's price and size in place, keeping its order id and queue position
outcomeOperateAgent keySplit collateral into YES/NO shares, or merge a complete set back
Margin (perpetuals)
updatePositionModeAgent keySwitch the account between one-way and hedge mode
updateLeverageAgent keySet leverage for one instrument
updateMarginModeAgent keySwitch an instrument between cross and isolated margin
updateIsolatedMarginAgent keyAdd or remove margin on an isolated position
Builder codes
approveBuilderFeeAccount keyApprove or update a builder's maximum fee rate
revokeBuilderFeeAccount keyRemove a builder-fee approval
claimBuilderRewardsAgent keyClaim the builder's unclaimed rewards

Builder-fee actions need protocol version 47 or later. TWAP, vault, and governance actions are not documented yet; cross-chain deposit addresses come from the TxRelay API, not /exchange.

Outcome markets

Outcome orders use the same order, cancel, cancelByCloid, and modify2 actions, with the market's instrument id as the asset. An Outcome order can be accepted asynchronously: an ok response means it was queued, not matched. A queued order that fails is pushed on outcomeOrderUpdate (successes are not); the matching lifecycle is on outcomeOrderUpdates.

Market lifecycle actions

Creating markets, pushing oracle prices, and settling markets go through outcomeDeploy. It is permissioned — only registered outcome deployers and platform hot keys can sign it, and oracle pushes must also come from the instrument's oracle_updater or the exchange's configured oracle addresses — so it is not part of this reference. Integrations trade existing markets and read them through outcomeMeta; the protocol model is in TIP 3.

Attach a builder to an order

Once the user has approved a builder with approveBuilderFee, an order action can carry one builder object:

{
  "type": "order",
  "grouping": "na",
  "orders": [
    { "a": 1, "b": true, "p": "50000.0", "s": "0.01", "r": false, "t": { "limit": { "tif": "Gtc" } } }
  ],
  "builder": { "b": "0x2e4D75df2eE2653EA7a113cC1Fa36D45E923061F", "f": 10 }
}
FieldTypeDescription
builder.baddressBuilder wallet address
builder.fuint32Fee in tenths of a basis point: rate = f / 100,000; f = 10 is 1 bp (0.01%)

The order signature covers builder. The fee applies to perpetual and Outcome markets, on top of exchange fees, and may exceed neither the user's approval nor the market cap: f <= 100 (0.1%) for perpetuals, f <= 1000 (1%) for Outcome. If the builder is unapproved, the market is unsupported, or either cap is exceeded, the fee is dropped and the order still goes through.

Fees accrue only while the builder holds at least 100 USDC in its perpetual account; builderState reports that balance, eligibility, and accrued rewards. See Builder Code for the end-to-end flow.

Response

Every action returns its response type and a single status, however many orders or cancels it carries:

{
  "status": "ok",
  "code": 0,
  "data": {
    "type": "PlaceOrder",
    "data": { "statuses": ["success"] }
  }
}
  • "success" means the transaction was accepted by consensus; it has not executed yet. Send "confirm": "executed" next to action in the request body to wait for the execution result instead: the reply then carries "confirm": "executed", a failed execution comes back as { "error": "<reason>" } in statuses, and a timeout returns HTTP 202 { "status": "pending", "txHash": … }.
  • The response never says whether an order rested, filled, or was cancelled. Read that from orderUpdates or frontendOpenOrders.
  • data.type is the action's internal name and may differ from the request — order returns PlaceOrder; cancel and cancelByCloid both return CancelOrder.
  • A rejected request returns "status": "err" with a non-zero code and the reason in message — for example { "status": "err", "code": 10000, "message": "Price precision does not match the tick size: 0.1" }. Some gateway rejections, such as rate limits, put the reason in response instead.
  • An Outcome order can instead be acknowledged asynchronously with { "status": "ok", "traceId": "…" } — see Outcome markets.