include_isolated: true.
This guide covers the behavior that differs from cross-margin trading and how
to integrate against the JSON-RPC API. Examples use SOL_USDC-PERPETUAL.
123456 stands for a discovered integer subaccount ID; subaccount_id is an
integer on the wire, not a string.
1. How isolated margin works
Four behaviors differ from ordinary cross trading. Read these before the walkthrough; most integration bugs come from assuming one of them away.1.1 The API provisions hidden subaccounts for you
You never create an isolated subaccount yourself. Sendingprivate/buy or
private/sell from the main account with isolated: true:
- claims a free isolated subaccount (slot) or creates one if none is free,
- binds it to the requested instrument,
- places the order under that subaccount’s ID.
user_id, for
example 123456), not the main account. Responses also carry main_uid,
which identifies the owning main account.
Cross and isolated positions can coexist on the same instrument. A main account
can maintain a cross position while simultaneously holding an isolated position on
the same instrument via a provisioned slot. Each position is margined, tracked,
and managed independently under its respective account ID (user_id).
1.2 Two flags: routing versus visibility
Because isolated records live on subaccounts, most operations take one of two flags. Mixing them up is the most common integration mistake.isolated: trueroutes a single-order operation (place, edit, cancel, close, leverage, per-order reads) to the subaccount that owns the instrument or order. The default isfalse, so omitting it silently targets cross margin instead of producing an error.include_isolated: truewidens a main-account list, snapshot, or mass cancel to include hidden isolated subaccounts. Without it, hidden isolated slots are excluded.subaccount_idtargets one discovered subaccount directly. History calls for a slot requiresubaccount_id; they do not aggregate withinclude_isolated.
1.3 Slots are recycled and IDs are reused
A slot binds to one instrument at a time, reported asisolated_margin_instrument. A slot is recycled only when both conditions
hold:
- no position has a non-zero size;
- no open order remains.
- History for one
subaccount_idcan span multiple instruments. Key audit trails bysubaccount_id,instrument_name, and timestamp. - Do not cache an instrument-to-subaccount mapping. Rediscover it.
1.4 Orders auto-allocate margin and slots auto-sweep on close
Placing a risk-increasing order withisolated: true automatically transfers the
required margin from the main account to the slot, unless you supply allocated_margin
explicitly. If passed, allocated_margin must meet the required minimum, or placement
fails with 14033 isolated_allocated_too_low.
When an isolated position is completely closed and has no open orders, an auto-sweep
automatically transfers all remaining collateral and P&L back to the main account and
recycles the slot. Partial position reductions or leverage increases do not trigger a
partial auto-sweep; excess margin remains in the slot until complete closure or manual transfer.
2. Integration walkthrough
2.1 Authenticate and subscribe
Authenticate HTTP and WebSocket sessions as the main account before you call private methods or subscribe. For the authentication flow, see the Global Derivatives technical guide. Subscribe to the isolated order, isolated trade, isolated change, isolated portfolio, and isolated liquidation channels. For all private channels and the AsyncAPI specification, see Global Derivatives WebSocket endpoints:- For
orders,trades, andchanges:user.isolated.<family>.<kind>.<currency>.<interval>, where<kind>isfutureorany,<currency>is a currency code orany, and<interval>israw,100ms, oragg2. An instrument name can replace<kind>.<currency>, for exampleuser.isolated.orders.SOL_USDC-PERPETUAL.raw. - For
portfolio:user.isolated.portfolio.<currency>, where<currency>is a currency code orany(e.g.USDCoruser.isolated.portfolio.any). - For
liquidation:user.isolated.liquidation.
result array against the channels you requested: unsupported
channels are silently omitted. Base channels (user.orders.*, user.trades.*,
user.changes.*) carry main-account activity only; subscribe to both sets if
you track cross and isolated activity.
Events carry the owning slot’s user_id, plus main_uid and isolated: true
on order, trade, and change records. When a slot is recycled, the portfolio
channel emits a final frame with zeroed equity and margin fields. A
liquidation notification reports an event, not slot readiness; refresh
positions, orders, portfolio state, and the binding afterward.
2.2 Discover isolated subaccounts
Callprivate/get_subaccounts with include_isolated: true on application startup
or reconnection to discover existing active slots and their assigned subaccount_ids.
If you have not placed an isolated order yet,
private/get_subaccounts returns only your main account. Isolated subaccounts are lazily provisioned when you submit your first order with isolated: true (see Place an isolated order).id is the value to pass as subaccount_id on direct reads and history
queries. isolated: true distinguishes a managed slot from a regular
subaccount. isolated_margin_instrument is the reported binding. It becomes
null after recycling and may later name another instrument.
For per-slot positions and open orders in one call, use
private/get_subaccounts_details:
2.3 Monitor risk
private/get_account_summaries endpoint does not parse a currency
parameter; summaries for all portfolio currencies are always returned for both main
and isolated subaccounts. With include_isolated: true, it returns active
isolated subaccounts under isolated_account_summaries as a list of entries
with the structure { "id": 123456, "summaries": [ ... ] }. The risk fields
(equity, margin_balance, initial_margin, maintenance_margin,
available_funds) live on the per-currency rows inside the nested summaries
array, not flat on the slot entry.
Callers must select the matching currency row (e.g. USDC) from summaries
client-side. Only active/bound slots appear in isolated_account_summaries
(recycled slots are omitted). Fields are numeric (zero where applicable); nulls
are anomalous. If a slot’s aggregation fails, the slot is omitted entirely.
Evaluate risk per isolated slot, not against the cross account. Call private/get_account_summary with subaccount_id for a direct, per-slot check.
2.4 Place an isolated order
Before placing an isolated order, useprivate/get_margins with isolated: true to preview the margin requirement in isolated scope.
order.user_id.
2.5 Manage collateral
Collateral moves between the main account and the slot in three ways. Automatic allocation: on a risk-increasing order withallocated_margin
omitted, the API calculates the required amount. If you supply it, the amount
must meet the required minimum, or the order fails with 14033 isolated_allocated_too_low; the error data returns required_minimum and
suggested_amount (see 3.3).
Manual top-up with private/submit_transfer_between_subaccounts:
source is the main account ID and destination the slot ID. Common failures:
10009 not_enough_funds (insufficient balance or wrong currency) and
12100 transfer_not_allowed (invalid or unauthorized destination subaccount ID).
Confirm completion through the portfolio channel or a fresh account summary, not
the transfer response alone.
On a risk-reducing order, a supplied allocated_margin is transferred as-is.
Omit it on closes unless you mean to add collateral.
Collateral returns to the main account automatically when the slot is
recycled; there is no separate withdrawal step.
2.6 Set leverage
Bothprivate/get_leverage and private/set_leverage take isolated: true to
target the isolated slot scope. Omitting isolated: true on private/get_leverage
or private/set_leverage silently acts on cross leverage instead of returning an
error. Direct targeting via subaccount_id is not a substitute for the flag on
leverage calls and is rejected with 14020 only_for_retail_brokers.
Isolated leverage can be configured before a slot is active or bound.
2.7 Edit an isolated order
Sendprivate/edit or private/edit_by_label from the main account with
isolated: true:
allocated_margin to top up the slot
in the same call. Editing by targeting the slot directly with subaccount_id is
rejected with 14020 only_for_retail_brokers; always edit from the main account
with isolated: true.
2.8 Cancel isolated orders
Single order:isolated: true, the cancel searches only the main account and
returns order_not_found or not_owner_of_order. Treat either code as “the
flag was missing or the ID is wrong”, not as proof the order no longer exists.
Mass cancel:
private/cancel_all, private/cancel_all_by_currency, and private/cancel_by_label take the same flag. With include_isolated: true, a mass-cancel method includes matching open orders from the main account and every active isolated-margin subaccount. private/cancel_all therefore cancels all open cross-margin and isolated-margin orders; filtered mass-cancel methods apply their instrument, currency, or label filter across both scopes.
2.9 Close, reduce, or reverse a position
The simplest close isprivate/close_position with isolated: true. The API
resolves the slot, reads the current position, and submits an opposite-side
reduce-only order for the full size:
isolated: true:
2.10 Read positions, open orders, and history
Main-account aggregates:private/get_position (singular) with an instrument name and include_isolated: true resolves a position by instrument. When a bound isolated slot exists for the instrument, the singular call returns the isolated position and does not show a coexisting cross position; omit include_isolated: true to read the cross position, or use plural get_positions with include_isolated: true to retrieve both.
subaccount_id:
subaccount_id. A recycled slot can contain records for multiple instruments, so key your records by subaccount_id and instrument_name.
Settlements and transaction logs are also slot-scoped:
To query isolated perpetual settlements, call private/get_settlement_history_by_currency
with subaccount_id:
subaccount_id.
Passing include_isolated: true to get_settlement_history_by_currency has no
effect on settlement history queries.
To audit full ledger movements for a slot, call private/get_transaction_log
with subaccount_id, start_timestamp, and end_timestamp (start_timestamp and end_timestamp are mandatory; omitting either returns -32602 value required):
info, because they can vary. Use the top-level cashflow field to review money movements. The role field is only available for some transfer types. Treat a cleared isolated_margin_instrument value as the confirmation that the isolated slot was recycled.
3. Runbooks and reference
3.1 Production startup sequence
Initialize in this order so you never trade on a partial view:- Authenticate the HTTP and WebSocket sessions as the main account.
- Subscribe to the
user.isolated.*channels and verify the accepted list. - Snapshot with
private/get_subaccounts(include_isolated: true),private/get_positions(include_isolated: true),private/get_open_orders(include_isolated: true), andprivate/get_account_summaries(include_isolated: true). - Reconcile positions and orders against slot IDs into local state.
- Enable order placement.
3.2 Cleanup checklist
- Fetch
private/get_subaccountswithinclude_isolated: trueand record each active slot’s binding. - Cancel the slot’s resting orders with
include_isolated: trueon mass cancels orisolated: trueon single cancels. - Close the remaining position with
private/close_positionandisolated: true, or with a manual reduce-only order. - Confirm that the slot has no open orders or position. If it is missing from an aggregate, query it directly with
subaccount_id. - Refresh subaccounts until
isolated_margin_instrumentclears and funds settle to the main account. - For audit evidence, key slot history by
subaccount_idandinstrument_name.
3.3 Error reference
Errors arrive in the JSON-RPCerror object; some isolated validation errors
include a data object with machine-readable fields: