Trading
Place, cancel and close, as signed requests through the relay.
There is no REST endpoint called place-order. Every write is a request you sign yourself and POST /api/prep/relay forwards unchanged, which is what keeps a trading key out of this server entirely. Read Authentication first; this page is only what to put in the envelope.
Place an order
Sign POST /v1/order with the body below, then relay it. The body you sign is the exact string you send.
| Parameter | Type | Required | Notes |
|---|---|---|---|
| symbol | string | yes | PERP_<BASE>_USDC. |
| side | string | yes | BUY opens or increases a long, SELL a short. |
| order_type | string | yes | LIMIT, MARKET, IOC, FOK, POST_ONLY, ASK or BID. |
| order_quantity | number | no | Size in the base asset. A multiple of base_tick, worth at least min_notional. |
| order_price | number | no | Required unless order_type is MARKET, ASK or BID — so LIMIT, IOC, FOK and POST_ONLY all need one. A multiple of quote_tick. |
| order_amount | number | no | Quote-asset notional, as an alternative to order_quantity. |
| reduce_only | boolean | no | When true the order can only shrink an existing position. |
| client_order_id | string | no | Your own id, echoed back on the result. |
| visible_quantity | number | no | How much of the size rests visibly on the book. |
| slippage | number | no | Tolerance for a market order. |
| order_tag | string | no | Free-form tag carried on the order. |
| margin_mode | string | no | CROSS or ISOLATED. |
POST /api/prep/relay
{
"method": "POST",
"path": "/v1/order",
"body": "{\"symbol\":\"PERP_ETH_USDC\",\"order_type\":\"MARKET\",\"side\":\"BUY\",\"order_quantity\":0.5,\"reduce_only\":false}",
"auth": {
"accountId": "0x<64 hex characters>",
"key": "ed25519:<base58 public key>",
"signature": "<base64url signature>",
"timestamp": "1717171717171"
}
}{
"order_id": 883712441,
"client_order_id": null,
"order_type": "MARKET",
"order_price": null,
"order_quantity": 0.5
}An error_message field may accompany the result when the request was accepted and the order rejected. Any priced order without order_price is refused, and that is every order_type except MARKET, ASK and BID: IOC, FOK and POST_ONLY need a price exactly as LIMIT does, since they replace LIMIT's resting behaviour rather than modify it.
Close a position
There is no close endpoint. A close is a reduce-only market order on the opposite side, which is exactly what the app and the agent tools do.
- 1Sign GET /v1/positions and relay it. Find the row whose symbol matches and whose position_qty is not zero.
- 2The side is the opposite of the sign of position_qty: a positive quantity is long, so it closes with SELL.
- 3The size is the absolute value of position_qty, or less for a partial close. Never more.
- 4Sign POST /v1/order with order_type MARKET and reduce_only true, and relay it.
{
"symbol": "PERP_ETH_USDC",
"order_type": "MARKET",
"side": "SELL",
"order_quantity": 0.5,
"reduce_only": true
}Cancel an order
Sign DELETE /v1/order with order_id and symbol in the query string, and no body. The path you sign includes the query string exactly as you send it.
{
"method": "DELETE",
"path": "/v1/order?order_id=883712441&symbol=PERP_ETH_USDC",
"auth": { "...": "as above" }
}The response is the upstream payload for the cancel, scrubbed. This app does not reshape it, so its fields are the upstream's own and are not restated here.
Cancelling removes an instruction, not exposure. An order that already filled cannot be cancelled.
Reading your own account
Signed GETs through the same relay. These are forwarded pass-throughs: the field names are the upstream's, and the ones worth naming are called out below.
| Path | What it answers |
|---|---|
| /v1/client/info | Equity, free collateral, unsettled profit and the margin ratios. |
| /v1/client/holding | Collateral held, per asset. |
| /v1/positions | Every open position. |
| /v1/position/{symbol} | One position. |
| /v1/position_history | Positions that have been closed. |
| /v1/orders?status=INCOMPLETE | Resting orders. COMPLETED for filled and cancelled. |
| /v1/order/{id} | One order. |
| /v1/trades | Your own fills. /v1/trade/{id} for one. |
| /v1/funding_fee/history | Funding paid and received. |
| /v1/asset/history | Deposits and withdrawals. |
| /v1/client/statistics | Aggregate account statistics. |
| /v1/liquidations | Your own liquidations. |
| /v1/volume/user/daily | Your traded volume by day. /v1/volume/user/stats for totals. |
- On /v1/client/info the fields the app reads are total_collateral_value, free_collateral, total_unsettled_pnl, margin_ratio and maintenance_margin_ratio. The gap between the last two is the account's whole cushion.
- On /v1/positions each row carries position_qty, average_open_price, mark_price, unsettled_pnl and est_liq_price. A positive position_qty is long, a negative one short.
- est_liq_price is an estimate and moves on its own as funding and fees drain collateral, and under cross margin as other positions lose.
What this API will not do
| Not possible | Why |
|---|---|
| Withdraw with a trading key alone | A withdrawal carries a second, wallet signature upstream. The path relays; the key does not authorise it. |
| Set leverage on an order | There is no leverage field. Size the order against the collateral you mean to commit. |
| Dry-run an order | There is no simulation mode and no undo. |
| Reach an arbitrary upstream path | The relay allowlist is anchored and closed. Anything outside it is forbidden. |
| Trade on someone else's behalf | This server holds no key and cannot produce a signature. It can only carry one you made. |