Perps are off by default, and they are off on
https://router.raze.bot. Enable them on your own router with ROUTER_PERP=all (or jupiter, gmtrade). A disabled venue answers 422 venue_disabled, and GET /perp/markets lists no venue.The flow
1
Markets
GET /perp/markets lists each venue’s markets with the live mark price, and the open fee where the venue publishes one.2
Quote (optional)
POST /perp/quote prices an open: size, entry, estimated liquidation, fee, and the funding swap when the user pays in another token.3
Build
POST /perp/instructions with an op returns the instructions, or the unsigned transaction with serialize: true.4
Sign, send, watch
The transaction creates a request or an order; a venue keeper executes it seconds later in its own transaction. Watch
GET /perp/account to see the position change.Markets
A market id is
<venue>:<SYMBOL>-PERP, case-insensitive (jupiter:SOL-PERP, gmtrade:ZEC-PERP). A GMTrade index with more than one pool spells the pool: gmtrade:SOL-WSOL-USDC-PERP. jup: and gm: are accepted as venue aliases.
Units
Notional is collateral × leverage. The router enforces leverage of at least 1x and no maximum: an over-levered order is built, and the venue’s keeper refuses it at execution.
estLiquidationE6 is an estimate with a 0.6% maintenance margin, not the venue’s rule.
Operations
POST /perp/instructions takes op, wallet, marketId, side (long or short) and clientOrderId on every operation, plus the fields of the operation:
open on a market and side where the wallet already has a position adds to it (on GMTrade, when that position uses the collateral the router picks; one held in the pool’s other token stays separate). A partial reduce is close with closeBps. The trigger of a take profit on a long, or a stop loss on a short, must be above the mark; the other two below.
Paying with any token
fundingMint chooses what the user pays with on open, limit and deposit:
Every operation is one transaction: the funding swap, the deposit and the order land together or not at all (
atomic in the response says which parts it contains). A routed operation depends on your swap deploy like a swap does: paused, it answers 503.
Execution is asynchronous
Neither venue fills inside the user’s transaction. The transaction queues a request (Jupiter) or an order (GMTrade), and the venue’s keeper executes it in its own transaction, at the price of that moment. A landed transaction means “queued”, not “filled”. WatchGET /perp/account: positions show size and entry, orders lists resting limit, take profit and stop loss orders.
Transactions
Perp transactions are v1, like swaps (see Transactions):serialize: true returns transaction (base64, unsigned) and lastValidBlockHeight. If you assemble the transaction yourself from instructions, set the header from computeUnits and loadedAccountsDataSize, or post them to POST /tx/v1.
detail.counter in Jupiter responses is a 64-bit integer, beyond JavaScript’s safe range: read it as a string if you need it.