curl --request POST \
--url https://api.arcus.xyz/v1/adjustIsolatedMargin \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-Signature: <api-key>' \
--header 'X-Timestamp: <api-key>' \
--data '
{
"address": "<string>",
"marketId": 32767,
"amount": "100",
"accountIndex": 0
}
'import requests
url = "https://api.arcus.xyz/v1/adjustIsolatedMargin"
payload = {
"address": "<string>",
"marketId": 32767,
"amount": "100",
"accountIndex": 0
}
headers = {
"X-API-Key": "<api-key>",
"X-Timestamp": "<api-key>",
"X-Signature": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-API-Key': '<api-key>',
'X-Timestamp': '<api-key>',
'X-Signature': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({address: '<string>', marketId: 32767, amount: '100', accountIndex: 0})
};
fetch('https://api.arcus.xyz/v1/adjustIsolatedMargin', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.arcus.xyz/v1/adjustIsolatedMargin",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'address' => '<string>',
'marketId' => 32767,
'amount' => '100',
'accountIndex' => 0
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-Signature: <api-key>",
"X-Timestamp: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.arcus.xyz/v1/adjustIsolatedMargin"
payload := strings.NewReader("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"amount\": \"100\",\n \"accountIndex\": 0\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("X-Timestamp", "<api-key>")
req.Header.Add("X-Signature", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.arcus.xyz/v1/adjustIsolatedMargin")
.header("X-API-Key", "<api-key>")
.header("X-Timestamp", "<api-key>")
.header("X-Signature", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"amount\": \"100\",\n \"accountIndex\": 0\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.arcus.xyz/v1/adjustIsolatedMargin")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["X-Timestamp"] = '<api-key>'
request["X-Signature"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"amount\": \"100\",\n \"accountIndex\": 0\n}"
response = http.request(request)
puts response.read_body{
"requestId": "<string>",
"address": "<string>",
"accountIndex": 4,
"marketId": 32767,
"amount": "100",
"newIsolatedMarginQuoteBalance": "-850.5",
"status": "ACK",
"rejectReason": "UNKNOWN_MARKET"
}{
"requestId": "<string>",
"address": "<string>",
"accountIndex": 4,
"marketId": 32767,
"amount": "100",
"newIsolatedMarginQuoteBalance": "-850.5",
"status": "ACK",
"rejectReason": "UNKNOWN_MARKET"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"requestId": "<string>",
"address": "<string>",
"accountIndex": 4,
"marketId": 32767,
"amount": "100",
"newIsolatedMarginQuoteBalance": "-850.5",
"status": "ACK",
"rejectReason": "UNKNOWN_MARKET"
}{
"error": "rate limited",
"reason": "account_empty",
"retryAfterMs": 850,
"clientId": "my-order-42"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}Add or remove margin on an isolated-mode position
Move margin between the cross bucket and an isolated-mode position’s leg.
curl --request POST \
--url https://api.arcus.xyz/v1/adjustIsolatedMargin \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-Signature: <api-key>' \
--header 'X-Timestamp: <api-key>' \
--data '
{
"address": "<string>",
"marketId": 32767,
"amount": "100",
"accountIndex": 0
}
'import requests
url = "https://api.arcus.xyz/v1/adjustIsolatedMargin"
payload = {
"address": "<string>",
"marketId": 32767,
"amount": "100",
"accountIndex": 0
}
headers = {
"X-API-Key": "<api-key>",
"X-Timestamp": "<api-key>",
"X-Signature": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-API-Key': '<api-key>',
'X-Timestamp': '<api-key>',
'X-Signature': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({address: '<string>', marketId: 32767, amount: '100', accountIndex: 0})
};
fetch('https://api.arcus.xyz/v1/adjustIsolatedMargin', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.arcus.xyz/v1/adjustIsolatedMargin",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'address' => '<string>',
'marketId' => 32767,
'amount' => '100',
'accountIndex' => 0
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-Signature: <api-key>",
"X-Timestamp: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.arcus.xyz/v1/adjustIsolatedMargin"
payload := strings.NewReader("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"amount\": \"100\",\n \"accountIndex\": 0\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("X-Timestamp", "<api-key>")
req.Header.Add("X-Signature", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.arcus.xyz/v1/adjustIsolatedMargin")
.header("X-API-Key", "<api-key>")
.header("X-Timestamp", "<api-key>")
.header("X-Signature", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"amount\": \"100\",\n \"accountIndex\": 0\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.arcus.xyz/v1/adjustIsolatedMargin")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["X-Timestamp"] = '<api-key>'
request["X-Signature"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"amount\": \"100\",\n \"accountIndex\": 0\n}"
response = http.request(request)
puts response.read_body{
"requestId": "<string>",
"address": "<string>",
"accountIndex": 4,
"marketId": 32767,
"amount": "100",
"newIsolatedMarginQuoteBalance": "-850.5",
"status": "ACK",
"rejectReason": "UNKNOWN_MARKET"
}{
"requestId": "<string>",
"address": "<string>",
"accountIndex": 4,
"marketId": 32767,
"amount": "100",
"newIsolatedMarginQuoteBalance": "-850.5",
"status": "ACK",
"rejectReason": "UNKNOWN_MARKET"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"requestId": "<string>",
"address": "<string>",
"accountIndex": 4,
"marketId": 32767,
"amount": "100",
"newIsolatedMarginQuoteBalance": "-850.5",
"status": "ACK",
"rejectReason": "UNKNOWN_MARKET"
}{
"error": "rate limited",
"reason": "account_empty",
"retryAfterMs": 850,
"clientId": "my-order-42"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}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 returns200 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
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.
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).
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:
placeOrder: {"ad":"0x…","ai":N,[,"c":"…"],"ct":N,"g":N,"m":N,"op":1,"p":N,"q":N,"r":0|1,"s":N,"t":N,"v":1}
cancelOrder: {"ad":"0x…","ai":N,[,"c":"…"],"ct":N,[,"id":"…"],"m":N,"op":2,"v":1}
modifyOrder: {"ad":"0x…","ai":N,[,"c":"…"],"ct":N,"g":N,[,"id":"…"],"m":N,"op":3,"p":N,"q":N,"r":0|1,"s":N,"t":N,"v":1} (exactly one of id / c)
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
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 a–f after 0x.
^(0x|0X)?[0-9a-fA-F]{40}$Subaccount index (0–9) to scope the request to. Defaults to 0 (the primary account). Values above 9 → 400.
0 <= x <= 9Body
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.
^(0x|0X)?[0-9a-fA-F]{40}$Perpetual market identifier (uint16). Map to display name via GET /markets. Used for orders, positions, funding, and market metadata.
0 <= x <= 65535Dollar 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.
"100"
"-40.5"
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.
0 <= x <= 9Response
Engine confirmed the margin move (status: APPLIED). amount and newIsolatedMarginQuoteBalance are dollars as decimal strings, not quote quantums.
Server-generated UUID identifying this request in subsequent WebSocket events.
20-byte EVM address as hex: optional 0x or 0X prefix and exactly 40 hexadecimal digits. API responses normalize to lowercase a–f after 0x.
^(0x|0X)?[0-9a-fA-F]{40}$Account index (account index, 0–9). Identifies the account for orders, positions, fills, and API keys.
0 <= x <= 9Perpetual market identifier (uint16). Map to display name via GET /markets. Used for orders, positions, funding, and market metadata.
0 <= x <= 65535The requested dollar amount, echoed back as a decimal string (not quote quantums).
"100"
"-40.5"
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.
"-850.5"
"0"
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 thepositionsWebSocket channel for the engine-confirmed value.APPLIED(HTTP 200): engine accepted the move.newIsolatedMarginQuoteBalanceis the post-move isolated-leg balance in dollars (decimal string, not quote quantums).REJECTED(HTTP 422): engine rejected the move; seerejectReason.
ACK, APPLIED, REJECTED Engine-side rejection reason, present on HTTP 422 responses:
UNKNOWN_MARKET:marketIdis not configured.INVALID_AMOUNT:amountis 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.
UNKNOWN_MARKET, INVALID_AMOUNT, NOT_ISOLATED, NO_OPEN_POSITION, UNDERCOLLATERALIZED, MISSING_MARK_PRICE Was this page helpful?