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

order

Places one or more orders. Every order in the batch is signed together and applied in array order.

POST/exchangetype order

Place one or more orders (limit, market, trigger, TP/SL).Agent-signed

Action fields
groupingstringrequired

How the batch is interpreted as a group.

"na""normalTpsl""positionTpsl""normalTrigger""reversePosition""closeAll"
ordersOrderBody[]required

Order bodies; at most 50 per action.

ainteger · uint32required

Instrument's external id — the `index` value from `perpMeta`; Outcome markets use the `instrument_id`. Long form: `asset`.

bbooleanrequired

`true` to buy, `false` to sell. Long form: `isBuy`.

pstringrequired

Limit price. The literal `"bbo"` prices at the current best bid/offer. Long form: `limitPx`.

sstringrequired

Size in base units. Long form: `sz`.

toneOfrequired

Either a `limit` or a `trigger` body. Long form: `orderType`.

cstringoptional

Client order id, used later by `cancelByCloid`. Long form: `cloid`.

expiresAtinteger · uint64optional

Required when `tif` is `Gtd`. Unix milliseconds, and must be in the future.

mstringoptional

Margin mode. Long form: `marginMode`. Optional: when omitted the node routes the order to the account's current margin mode for this market (its saved position profile, `cross` for an account that has never set one) — so the same body can land on a different mode after an `updateMarginMode`. API clients should send `m` explicitly. The margin mode is part of the position key, so it also selects which position the order opens into or reduces.

"cross""isolated"
rbooleanoptional

Reduce-only. Defaults to `false`. Long form: `reduceOnly`.

typestringrequired

Must be `order`.

"order"
builderBuilderoptional

Optional builder code. The order signature covers this object.

bstring · addressrequired

Builder wallet address.

finteger · uint32required

Fee in tenths of a basis point: `rate = f / 100,000`, so `f = 10` is 1 bp (`0.01%`).

Request example
curl -X POST https://rpc.txflow-testnet.xyz/exchange \
  -H "Content-Type: application/json" \
  -H "x-api-version: 2026-08-16" \
  -d '{
  "action": {
    "type": "order",
    "grouping": "na",
    "orders": [
      {
        "a": 1,
        "b": true,
        "p": "50000.0",
        "s": "0.01",
        "r": false,
        "t": {
          "limit": {
            "tif": "Gtc"
          }
        }
      }
    ]
  },
  "signature": {
    "r": "0x<r>",
    "s": "0x<s>",
    "v": 27
  },
  "nonce": 1757992743994,
  "vaultAddress": null,
  "signatureChainId": null
}'
Try it
testnet · no account yet
Generates a throwaway key in your browser, claims testnet USDC and authorizes an agent key. The account is kept while you browse the docs and lost on reload.
Response · PlaceOrder 200
codeinteger

`0` on success.

dataobject
dataobject
typestring

The action's internal name, which does not always match the request `type`.

"PlaceOrder"
statusstring

A rejected request returns `err` with a non-zero `code` and the reason in `message` (or `response`).

"ok"
Response example
{
  "status": "ok",
  "code": 0,
  "data": {
    "type": "PlaceOrder",
    "data": {
      "statuses": [
        "success"
      ]
    }
  }
}

Outcome orders

For an Outcome market, a is its instrument_id. YES is the long leg and NO the short leg; b and r together encode the leg and direction:

Intentbr
Buy YEStruefalse
Buy NOfalsefalse
Sell YESfalsetrue
Sell NOtruetrue

p is the price of the traded leg, between 0 and 1: buying NO at 0.30 sends b: false, r: false, p: "0.30". Outcome orders use grouping: "na" and do not support trigger/TP-SL order types. Time-in-force must be Gtc, Gtd, or Alo; an Ioc order is rejected with Outcome limit orders only support GTC, GTD, and ALO orders, reported asynchronously on outcomeOrderUpdate.

The initial HTTP response can be an asynchronous acceptance ({"status":"ok","traceId":…}) rather than a fill. If the queued order fails, outcomeOrderUpdate pushes the reason under that traceId; successes are not pushed. Follow the matching lifecycle on outcomeOrderUpdates or read outcomeFrontendOpenOrders.

Order bodies use abbreviated keys. The long forms noted above are accepted on input, but the abbreviated keys are what the signature covers. The optional builder object is documented under Attach a builder to an order.

Order body

ainteger · uint32required

Instrument's external id — the `index` value from `perpMeta`; Outcome markets use the `instrument_id`. Long form: `asset`.

bbooleanrequired

`true` to buy, `false` to sell. Long form: `isBuy`.

pstringrequired

Limit price. The literal `"bbo"` prices at the current best bid/offer. Long form: `limitPx`.

sstringrequired

Size in base units. Long form: `sz`.

toneOfrequired

Either a `limit` or a `trigger` body. Long form: `orderType`.

oneOf · variant 1
limitobjectrequired
oneOf · variant 2
triggerobjectrequired
cstringoptional

Client order id, used later by `cancelByCloid`. Long form: `cloid`.

expiresAtinteger · uint64optional

Required when `tif` is `Gtd`. Unix milliseconds, and must be in the future.

mstringoptional

Margin mode. Long form: `marginMode`. Optional: when omitted the node routes the order to the account's current margin mode for this market (its saved position profile, `cross` for an account that has never set one) — so the same body can land on a different mode after an `updateMarginMode`. API clients should send `m` explicitly. The margin mode is part of the position key, so it also selects which position the order opens into or reduces.

"cross""isolated"
rbooleanoptional

Reduce-only. Defaults to `false`. Long form: `reduceOnly`.

Price, size, and client order id

RuleRejected with
p is a multiple of the instrument's priceTick from perpMeta, with no more decimals than the tickPrice precision does not match the tick size: <tick> / Tick size does not match
s has at most szDecimals decimals and lies between the minimum size and maxLimitOrderSize / maxMarketOrderSizeMinimum order amount is <x> <BASE> / Maximum limit order amount is …
A limit price stays inside the oracle price bandOrder buy price is not within the price limit (Minimum price: …; Maximum price: …)
c is any string up to 64 bytes, unique among your open orders. A 0x prefix is reserved for liquidity-provider accounts, on every marketcloid length exceeds maximum / Duplicate client order ID <cloid> / Invalid cloid format

Order type

A limit order carries a time-in-force:

{ "limit": { "tif": "Gtc" } }
tifBehavior
GtcGood-til-canceled; rests on the book
IocImmediate-or-cancel; unfilled remainder is canceled
AloAdd-liquidity-only (post-only); rejected if it would take
GtdGood-til-date; requires expiresAt
FrontendMarketTreated as a market order

A trigger order carries a trigger price instead:

{
  "trigger": {
    "isMarket": true,
    "triggerPx": "48000.0",
    "tpsl": "sl"
  }
}

tpsl is tp (take-profit) or sl (stop-loss). Trigger orders are only accepted under a normalTpsl, positionTpsl, or normalTrigger grouping; sending one with grouping: "na" is rejected with Trigger orders are not supported for grouping na.

Triggered is not filled

A TP/SL that reaches its trigger price is fired, not guaranteed to execute. Two separate things happen:

  1. Trigger — the protection order's trigger state becomes Triggered, and in a TP/SL pair the other side is canceled at the same moment (Canceled trigger state). This is OCO: it happens on trigger, not on fill.
  2. Execution — the fired order is then submitted to the matcher like any other order, and can be fully filled, partially filled, canceled, or rejected.

A fired order that does not fill does not revert to a pending protection order — it is in a terminal state and the position is left unprotected. Common reasons the fired leg does not fill:

OutcomeWhy
Canceled with no or partial fillA fired market order carries the oracle price-protection band; the remainder past the band, or past the book's available liquidity, is canceled
RejectedThe limit price falls outside the price band or off the tick, or the instrument is halted / delisted, or the order is over the open-interest cap
Skipped entirelyThe underlying position is already flat (closed, liquidated, or closed by the other side of the pair) when the trigger fires

Because the sibling was already canceled in step 1, a failed fill leaves neither protection order live. Re-arm the protection yourself after confirming the outcome.

Confirm the result rather than assuming it: read the pair back with tpslOrders (live) and historicalTpslOrders (terminal, carrying cancelSource / cancelReason), check the resulting order on historicalOrders, and follow orderUpdates for the live transitions.

Next steps

Read resting orders back with frontendOpenOrders. To reprice or resize a resting order, use modify2.