Orders

Place, cancel, and query orders on the 4rho prediction market CLOB.

Place Order

POST /v1/orders

Scope: trade:orders

Placing orders requires both HMAC API key authentication (request headers) and an EIP-712 signature (request body). See the EIP-712 Signing guide for prerequisites and examples.

Sign the correct fee. fee_rate_bps is part of the signed order. It MUST equal the market's canonical effective fee or placement is rejected 422 (fee_rate_bps mismatch), and a resting order silently stops matching if the canonical fee later moves (#3672). Read GET /v1/market-data/:market_id/fee-rate and sign maker_fee_bps (currently 50 platform-wide). Details: Fees.

Request Body

{
  "market_id": "550e8400-e29b-41d4-a716-446655440000",
  "token_id": "12345678901234567890",
  "side": "BUY",
  "maker_amount": "1000000",
  "taker_amount": "2000000",
  "maker": "0xYourWalletAddress",
  "signer": "0xYourWalletAddress",
  "taker": "0x0000000000000000000000000000000000000000",
  "salt": "123456789",
  "nonce": 0,
  "expiration": 0,
  "fee_rate_bps": 50,
  "signature": "0x...",
  "outcome_index": 0,
  "time_in_force": "GTC",
  "post_only": false
}
FieldTypeRequiredDescription
market_idUUIDYesMarket to trade on
token_idstringYesERC-1155 token ID for the outcome
sidestringYesBUY or SELL
maker_amountstringYesAmount the maker provides (wei)
taker_amountstringYesAmount the maker receives (wei)
makerstringYesMaker wallet address
signerstringYesSigner wallet address
takerstringYesMust be the zero address - directed orders are not supported
saltstringYesRandom salt for order uniqueness
nonceintYesOrder nonce
expirationintNoUnix timestamp (0 = no expiry)
fee_rate_bpsintYesFee rate in basis points
signaturestringYesEIP-712 signature (signing guide)
outcome_indexintYesOutcome index (0 = Yes, 1 = No)
time_in_forcestringNoGTC, GTD, FOK, FAK (default: GTC)
post_onlyboolNoReject if would cross the book

Response

{
  "order_id": "550e8400-e29b-41d4-a716-446655440000",
  "order_hash": "0xabc123...",
  "status": "open",
  "matches": 0
}
StatusDescription
openResting on the book, no fills
partially_filledSome fills, remainder resting
filledFully filled

Cancel Order

DELETE /v1/orders/:hash

Scope: trade:orders

Cancels an open or partially filled order by its order hash.

Response

{ "message": "order cancelled" }

Get Order

GET /v1/orders/:hash

Scope: read:account

Returns the full order details including current status and fill amounts.

Response

{
  "id": "550e8400-...",
  "order_hash": "0xabc123...",
  "market_id": "...",
  "side": "BUY",
  "price": "0.50000000",
  "status": "open",
  "remaining": "1000000",
  "filled_amount": "0",
  "time_in_force": "GTC",
  "post_only": false,
  "created_at": "2024-03-01T00:00:00Z"
}

Get Open Orders

GET /v1/orders/open/:market_id

Scope: read:account

Returns all open and partially filled orders for the authenticated user in a specific market.

Get Order Book

GET /v1/orders/book/:market_id?outcome_index=0&levels=20

Public - No authentication required.

ParameterTypeDefaultDescription
outcome_indexint0Outcome index (0 or 1). Ignored when both is set.
levelsint20Max price levels per side (1-100).
bothbool-When true (or 1), return both outcome books in one response - see below.

Each level is { "price": "0.50", "size": "5000000", "num_orders": 3 }. size is the total remaining wei at that price; num_orders is the count of resting orders there.

Response

{
  "market_id": "...",
  "outcome_index": 0,
  "bids": [
    { "price": "0.50", "size": "5000000", "num_orders": 3 },
    { "price": "0.49", "size": "3000000", "num_orders": 1 }
  ],
  "asks": [
    { "price": "0.52", "size": "2000000", "num_orders": 2 },
    { "price": "0.55", "size": "4000000", "num_orders": 1 }
  ]
}

Both outcomes in one request

GET /v1/orders/book/:market_id?both=true&levels=20

Pass both=true (or both=1) to get outcome 0 and outcome 1 in a single response. outcome_index is ignored. For a market maker quoting two-sided this is one rate-limited request instead of two. The keys are outcome_0 and outcome_1:

{
  "market_id": "...",
  "outcome_0": {
    "bids": [ { "price": "0.50", "size": "5000000", "num_orders": 3 } ],
    "asks": [ { "price": "0.52", "size": "2000000", "num_orders": 2 } ]
  },
  "outcome_1": {
    "bids": [ { "price": "0.48", "size": "1000000", "num_orders": 1 } ],
    "asks": [ { "price": "0.50", "size": "3000000", "num_orders": 2 } ]
  }
}

Cancel-Replace

POST /v1/orders/cancel-replace

Scope: trade:orders

Atomically cancels an existing order and places a new one. If the cancellation fails, the new order is not placed.

Request Body

{
  "cancel_hash": "0xoriginal_order_hash...",
  "new_order": {
    "market_id": "...",
    "side": "BUY",
    "maker_amount": "1500000",
    "taker_amount": "3000000",
    ...
  }
}

Amend Order

PUT /v1/orders/:hash/amend

Scope: trade:orders

Re-price or re-size a resting order. Because maker_amount and taker_amount are part of the signed EIP-712 order, any change to the amounts requires a freshly signed replacement - supply it as new_order (a full Place Order body). The server cancels the old order and places the re-signed one atomically (a cancel-replace). A price change or quantity increase loses time priority.

The bare maker_amount / taker_amount fields are retained for backwards compatibility but now reject any actual amount change with 422 AMEND_RESIGN_REQUIRED - they can no longer silently invalidate a signature. Always use new_order to re-price or re-size.

Request Body

{
  "new_order": {
    "market_id": "market-id-1",
    "outcome_index": 0,
    "maker": "0xYourWallet",
    "maker_amount": "2000000",
    "taker_amount": "4000000",
    "expiration": 0,
    "nonce": "1718900000000",
    "signature": "0x... (EIP-712 signature over the NEW amounts)"
  }
}

Response

{
  "order_hash": "0xnewhash...",
  "status": "open",
  "price": "0.50000000",
  "maker_amount": "2000000",
  "taker_amount": "4000000",
  "remaining": "2000000",
  "time_priority": false,
  "price_changed": true
}