The account model
Three terms show up throughout the API. They nest:- Wallet — your Ethereum EOA (the address that owns everything). One wallet ↔ one account.
- Subaccount — the unit you actually trade from. It holds collateral and positions and is identified by a numeric
subaccount_id. A wallet can own many. - Manager — the margin/risk model a subaccount runs under: standard (cross) margin or portfolio margin. You pick a manager when the subaccount is created; it also fixes the subaccount’s risk universe.
A brand-new wallet’s first deposit creates two subaccounts: the funded one you asked for, plus a fallback
subaccount (under manager id
0) that catches any deposit that can’t be applied to its intended target. Expect two
ids to appear the first time — the fallback is normal.v3 has no
private/create_subaccount method — subaccounts are created on-chain by depositing. See the
changelog for the v2 → v3 method changes.Step 1 — Choose deposit params
A deposit is routed by three choices: what asset to credit, what manager the subaccount runs under, and what risk universe it lives in. All three come frompublic/get_all_currencies, which needs no authentication — for each currency it
lists the registered spot assets and the managers that risk-price it.
What asset
A deposit credits a protocol spot asset — the on-book balance — not the ERC-20 token you send. Read these from the currency’sspot[] entry:
What manager
The manager sets the subaccount’s margin model:managers[].sm is the Standard
(cross-margin) id and managers[].pm the Portfolio-margin id. Pass your chosen id as
manager_id when creating the subaccount. See
Managers & risk universes for how to choose.
What risk universe
Each manager belongs to one risk universe (managers[].risk_universe_id), so
choosing the manager_id also fixes the universe — the risk boundary that bounds what
the subaccount can trade and hold. See
Managers & risk universes.
Step 2 — Deposit
You can deposit 3 different ways - each ideal for different types of users:- Direct: call the
Deposit()orDepositNewSubaccount()calls on theOnchainActionManager.sol. (~2 min) - Standard: less integration work as simply requires user to send funds to a custom ETH address from where a keeper will auto deposit funds into the exchange. (~2 min)
- Instant: fastest deposit times at ~15 seconds, with same integration simplicity to
standard. Currently only supported for USDC (reach out if you’d like other collaterals) and for amounts <$1k. There also may be a small fee depending on network conditions.

- Direct
- Standard
- Instant
Your own wallet calls the settlement contract (
ACTION_MANAGER, address per Contracts). First
approve the contract to pull your ERC-20, then call one of:depositToNewSubaccount(asset, amount, managerId, owner)— create a new subaccount undermanagerId, owned byowner.deposit(asset, amount, subaccountId, fallbackRecipient)— fund an existingsubaccountId;fallbackRecipientreceives the funds into its fallback subaccount if the deposit cannot be applied.
Mainnet settlement-contract addresses are deployment-specific — do not hardcode them from the docs. Confirm the
ACTION_MANAGER address for your target deployment on Contracts before mainnet use.Step 3 — Confirm the deposit was credited
A mined deposit transaction is not the end of the story: the exchange credits the funds asynchronously, and the newsubaccount_id is not carried in the transaction receipt. Two endpoints cover the gap.
First feedback — public/get_pending_deposits
Whichever method you used, an entry appears here the moment the exchange picks the deposit up: Direct and
Standard deposits as soon as the action lands in the OnchainActionManager (for Standard, when the keeper sweeps
the deposit address); Instant deposits as soon as the keeper indexes the transfer. It is a public call, so it works
before your account exists. From there the paths diverge:
- Instant deposits are processed straight from this feed — keep polling it until every entry reads
credited(the lifecycle above); the SDK’sclient.deposits.awaitFastDepositdoes exactly that. - Direct / Standard deposits sit here (
pending→confirmed) while the exchange waits roughly two minutes of confirmations before including them in state — once your entry shows up, switch to pollingprivate/get_subaccountsbelow.
Crediting — private/get_subaccounts
Discover a new subaccount by snapshotting your subaccount ids before depositing and polling
private/get_subaccounts afterward for the id that appears — the SDK’s client.deposits.awaitNewSubaccount does this.
For a deposit into an existing subaccount, poll private/get_subaccount and watch its collateral balance increase.
public/get_onchain_action_history. It lists each OnchainActionManager action the sequencer
scraped and its status — applied (with an op_uuid), consumed as a fallback no-op, or still retrying. (Instant
deposits are keeper-fronted and do not appear here.)
private/get_deposit_history, scoped to the
whole wallet or a single subaccount_id. Amounts and fee are decimal strings; the net credited amount is
amount - fee. Instant deposits are credited as transfers, so they do not appear here — they show up as incoming
rows in private/get_erc20_transfer_history (see Transfers & Withdrawals), with their
crediting lifecycle in public/get_pending_deposits.
private/get_subaccounts and private/get_deposit_history are private methods — authenticate the connection with
session login first. Once a subaccount is funded, you can log in and start trading.Next steps
Quickstart
Now that your subaccount is funded, log in, sign an order, and stream your fills.
Authentication
Session login and the per-action signing model.
Transfers & Withdrawals
Move collateral between subaccounts and back on-chain.
