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
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 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) 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, except for the signed affiliate reads (see the Referral tag), which require the full header triple; with no body their 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}$Body
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}$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.
"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.
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?