Account Operations
Execute advanced account operations including contract calls, upgrades, and asset withdrawals.
Owner Contract Call
Execute a contract call as the account owner.
POST /v1/accounts/call
Headers
Request Body
curl -X POST \
"https://api.o2.app/v1/accounts/call" \
-H "Accept: application/json" \
-H "O2-Owner-Id: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" \
-H "Content-Type: application/json"Rate Limit: 10 requests/minute (Owner ID-based)
Source: packages/api/src/app/routes/v1/accounts.rs:owner_call_contract_handler
Owner Multiple Contract Calls
Execute multiple contract calls in batch as account owner.
POST /v1/accounts/calls
Headers
Request Body
curl -X POST \
"https://api.o2.app/v1/accounts/calls" \
-H "Accept: application/json" \
-H "O2-Owner-Id: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" \
-H "Content-Type: application/json"Owner calls with the typed signature variant also accept a parallel_nonce instead of nonce (the typed signature then covers ParallelMultiCallContractArgs), allowing concurrent owner calls. See Parallel Nonces.
Rate Limit: 10 requests/minute (Owner ID-based)
Source: packages/api/src/app/routes/v1/accounts.rs:owner_call_contracts_handler
Upgrade Account
Upgrade trading account contract to newer version.
POST /v1/accounts/upgrade
Headers
Request Body
curl -X POST \
"https://api.o2.app/v1/accounts/upgrade" \
-H "Accept: application/json" \
-H "O2-Owner-Id: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" \
-H "Content-Type: application/json"Rate Limit: 10 requests/minute (Owner ID-based)
Source: packages/api/src/app/routes/v1/accounts.rs:upgrade_account_handler
Withdraw Assets
Withdraw assets from trading account.
POST /v1/accounts/withdraw
Headers
Request Body
curl -X POST \
"https://api.o2.app/v1/accounts/withdraw" \
-H "Accept: application/json" \
-H "O2-Owner-Id: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" \
-H "Content-Type: application/json"With parallel_nonce (and the typed signature variant), any number of withdrawals can be in flight concurrently — the typed signature covers ParallelWithdrawArgs instead of WithdrawArgs. See Parallel Nonces.
Rate Limit: 10 requests/minute (Owner ID-based)
Source: packages/api/src/app/routes/v1/accounts.rs:withdraw_handler
Parallel Nonces
Every nonce-authorized account operation (session actions, withdrawals, session updates, owner actions) accepts either the account's sequential nonce or a parallel nonce. Sequential nonces force one usable transaction at a time, confirmed in order. Parallel nonces remove that constraint: clients generate them locally, keep any number of requests in flight at once, and inclusion order does not matter.
A parallel nonce is a packed u256, transmitted as a decimal string:
| Bits (from LSB) | Width | Field |
|---|---|---|
| 0–7 | 8 | Bitmap position (0–127) |
| 8–135 | 128 | Word position inside the sliding window |
| 136–167 | 32 | Expiry — unix timestamp in seconds; the nonce is unusable after it |
| 168–175 | 8 | Nonce session id (lane), 0–4 |
| 176–255 | 80 | Reserved, must be zero |
Each (session id) lane has an on-chain sliding window of 8 words × 128 bits = 1024 usable positions; consuming positions in the upper half of the window slides it forward. Recommended client flow:
- Read the current window once at startup via
GET /v1/accounts/window. - Initialize a local cursor strictly after the highest consumed position and increment it per request — never reuse a handed-out position, and skip holes (they may belong to still-in-flight transactions).
- Stamp a fresh expiry (e.g. now + 120s) into each nonce at issuance.
- Optionally subscribe to
subscribe_nonce_v2over WebSocket to observe consumption.
Parallel nonces always require the typed signature variant. A consumed, expired, or out-of-window nonce is rejected with HTTP 400 before a transaction is submitted; the contract remains the final authority.
Get Parallel Nonce Window
Read the current parallel-nonce sliding window of a trading account. This is the client's nonce-cursor initialization read; nonce generation itself is local and needs no further server calls.
GET /v1/accounts/window?trade_account_id=0x...&nonce_session_id=0
| Query Parameter | Type | Required | Description |
|---|---|---|---|
trade_account_id | string | Yes | Trading account contract ID. Unknown accounts return an error |
nonce_session_id | number | No | Which nonce session (lane) to read, 0–4. Defaults to 0 |
Response:
{
"nonce_session_id": 0,
"base": "0",
"slots": [
{ "word_position": "0", "bitmap": "15" },
{ "word_position": "1", "bitmap": "0" },
{ "word_position": "2", "bitmap": "0" },
{ "word_position": "3", "bitmap": "0" },
{ "word_position": "4", "bitmap": "0" },
{ "word_position": "5", "bitmap": "0" },
{ "word_position": "6", "bitmap": "0" },
{ "word_position": "7", "bitmap": "0" }
]
}base— lower bound of the active word range[base, base + 8).slots[i]— the slot for wordword_position % 8; bitnofbitmapset means bitmap positionnof that word is consumed. A slot whoseword_positionis outside the active range was recycled by a window slide and counts as empty.
Rate Limit: shared IP-based aggregated limit
Source: packages/api/src/app/routes/v1/parallel_nonce.rs:get_parallel_nonce_window_handler