Skip to main content
POST
Add or remove margin on an isolated-mode position
The response body shown here is a static example, not live data. After you click Send, your live result appears in a separate panel headed 200 OK. The panel under the status-code tabs is a fixed sample from the spec — its field values (fees, prices, sizes, IDs, timestamps) are placeholders. Use Send, or call the endpoint, for current values.
Move margin between the cross bucket and an isolated-mode position’s leg. Requires address query parameter or JSON address field (must match X-API-Key’s master if both are present). accountIndex is required in the signed JSON body (default 0); it may also be sent as ?accountIndex=. If both are present they must match. The signed body always includes accountIndex so a signature cannot be replayed against a different subaccount. amount is dollars as a decimal string (e.g. "100" for $100) — do not send quote quantums; the gateway converts dollars to quantums for the engine. Positive adds margin to the leg (cross → isolated), negative removes margin from the leg (isolated → cross).

Response behavior

Asynchronous. The endpoint returns 200 OK (engine confirmed the move), 422 Unprocessable Entity (engine rejected — see rejectReason), or 202 Accepted (request forwarded but the confirmation didn’t arrive within the timeout; the engine may still apply the move — observe the next positions WebSocket frame to confirm). Adding margin fails with UNDERCOLLATERALIZED if the cross bucket doesn’t have enough free collateral to fund the transfer. An already-underwater isolated leg may still be topped up: the add is accepted as long as it does not make either domain’s free collateral worse. Removing margin fails with UNDERCOLLATERALIZED if it would leave the isolated leg’s equity below its initial margin requirement, or deepen an already-undercollateralized leg. The engine rolls back atomically on either path. An amount that would overflow int64 quote balances is rejected as INVALID_AMOUNT.

Authorizations

X-API-Key
string
header
required

Hex-encoded Ed25519 public key (64 chars). The public key IS the API key — register it via POST /createApiKey. Required on every authenticated request, both read-only and signed.

X-Timestamp
string
header
required

Unix time in nanoseconds as a decimal string (e.g. "1713825891591000000"). Millisecond or second epochs are rejected with 401 Unauthorized. Must be within ±30,000 ms (MaxTimestampDriftMs, the drift window stays configured in milliseconds) of server wall-clock, or the request is rejected with 401 Unauthorized. Required on all mutating / credential-creating endpoints. This same value must appear as the ct field in the ordersign typed canonical payload (single-order endpoints) or in each element's ct field (batch endpoints).

X-Signature
string
header
required

Lowercase hex-encoded Ed25519 signature (128 chars).

Single-order endpoints (placeOrder, cancelOrder, modifyOrder, and other non-batch mutating routes) sign over the ordersign typed canonical payload — a compact, key-sorted JSON object built from parsed request fields using engine-native integer values:

ct must equal the X-Timestamp header value. Keys in brackets are conditional (omitted when empty). op values: 1=place, 2=cancel, 3=modify. See the ordersign package for field definitions and reference signing code.

Other signed routes (e.g. createApiKey, tokens, userPreferences) still use the legacy scheme: signing_message = X-Timestamp + ACTION + canonicalJSON(body), where ACTION is the camelCase final path segment.

Batch endpoints (batchPlaceOrders, batchCancelOrders, batchModifyOrders) do NOT use this header. They authenticate with per-element typed ordersign signatures embedded in the request body (see the global auth description and the per-field signature descriptions on OrderRequest / CancelOrderRequest / ModifyOrderRequest).

Read endpoints are authenticated by ?address= (and optionally X-API-Key) only — no signature is required. The one exception is GET /v1/affiliate/inviteCodes, which returns bearer secrets and therefore requires the full header triple; with no body its signing message is X-Timestamp + ACTION. canonicalJSON(body) is the JSON body with object keys sorted lexicographically at every level and no whitespace; the server canonicalizes the received body before verifying, so only the bytes signed over must be canonical. Required on all mutating / credential-creating endpoints.

Query Parameters

address
string
required

Master Ethereum address for this API key (must match address from POST /createApiKey for the same key). Required on REST for account-scoped reads and for place/cancel. Invalid hex → 400; mismatch with key → 403.

20-byte EVM address as hex: optional 0x or 0X prefix and exactly 40 hexadecimal digits. API responses normalize to lowercase af after 0x.

Pattern: ^(0x|0X)?[0-9a-fA-F]{40}$
accountIndex
integer
default:0

Subaccount index (0–9) to scope the request to. Defaults to 0 (the primary account). Values above 9 → 400.

Required range: 0 <= x <= 9

Body

application/json
address
string
required

Master EVM address for this account. May also be supplied via the ?address= query parameter; if both are present they must match. When X-API-Key is enforced the body / query address must match the key's master, otherwise the request is rejected with HTTP 403.

Pattern: ^(0x|0X)?[0-9a-fA-F]{40}$
marketId
integer
required

Perpetual market identifier (uint16). Map to display name via GET /markets. Used for orders, positions, funding, and market metadata.

Required range: 0 <= x <= 65535
amount
string
required

Dollar amount to move, as a decimal string (e.g. "100" for $100, "-40.5" to remove $40.50). Do not send quote quantums — the gateway converts dollars to quantums (1e9 = $1) for the engine. Positive adds margin to the isolated leg (cross → isolated); negative removes it (isolated → cross). Zero is rejected with HTTP 400. The (account, market) must already be in isolated mode with an open position, otherwise the engine rejects with NOT_ISOLATED / NO_OPEN_POSITION.

Examples:

"100"

"-40.5"

accountIndex
integer
default:0

Subaccount index (0–9). Required in the signed body; omit or send 0 for the primary account. May also be supplied via the ?accountIndex= query parameter; if both are present they must match. When X-API-Key is enforced the index must match the key's authorized subaccount, otherwise the request is rejected with HTTP 403.

Required range: 0 <= x <= 9

Response

Engine confirmed the margin move (status: APPLIED). amount and newIsolatedMarginQuoteBalance are dollars as decimal strings, not quote quantums.

requestId
string
required

Server-generated UUID identifying this request in subsequent WebSocket events.

address
string
required

20-byte EVM address as hex: optional 0x or 0X prefix and exactly 40 hexadecimal digits. API responses normalize to lowercase af after 0x.

Pattern: ^(0x|0X)?[0-9a-fA-F]{40}$
accountIndex
integer
required

Account index (account index, 0–9). Identifies the account for orders, positions, fills, and API keys.

Required range: 0 <= x <= 9
marketId
integer
required

Perpetual market identifier (uint16). Map to display name via GET /markets. Used for orders, positions, funding, and market metadata.

Required range: 0 <= x <= 65535
amount
string
required

The requested dollar amount, echoed back as a decimal string (not quote quantums).

Examples:

"100"

"-40.5"

newIsolatedMarginQuoteBalance
string
required

The isolated leg's quote balance after the move, in dollars as a decimal string (converted from quote quantums). Always present: "0" on ACK (engine not yet confirmed); the applied (or pre-move, on reject) leg balance otherwise.

Examples:

"-850.5"

"0"

status
enum<string>
required

Engine-lifecycle marker for the adjustIsolatedMargin response body. Distinct from the HTTP status code, which is a transport-level signal.

  • ACK (HTTP 202): the request was accepted; the engine has not yet confirmed. Not a failure — subscribe to the positions WebSocket channel for the engine-confirmed value.
  • APPLIED (HTTP 200): engine accepted the move. newIsolatedMarginQuoteBalance is the post-move isolated-leg balance in dollars (decimal string, not quote quantums).
  • REJECTED (HTTP 422): engine rejected the move; see rejectReason.
Available options:
ACK,
APPLIED,
REJECTED
rejectReason
enum<string>

Engine-side rejection reason, present on HTTP 422 responses:

  • UNKNOWN_MARKET: marketId is not configured.
  • INVALID_AMOUNT: amount is zero, not a valid USD decimal, or the move would overflow int64 quote balances.
  • NOT_ISOLATED: the (account, market) is not in isolated mode.
  • NO_OPEN_POSITION: the account has no open position on this market.
  • UNDERCOLLATERALIZED: adding margin would leave insufficient free collateral on the cross side, or would make either domain's free collateral worse; removing margin would leave the isolated leg below its initial margin requirement (or deepen an already- undercollateralized leg). The move was rolled back atomically.
  • MISSING_MARK_PRICE: the market has no live mark price (a transient oracle gap), so the mark-based solvency gate cannot be evaluated. The move was not applied; retry once pricing resumes.
Available options:
UNKNOWN_MARKET,
INVALID_AMOUNT,
NOT_ISOLATED,
NO_OPEN_POSITION,
UNDERCOLLATERALIZED,
MISSING_MARK_PRICE