Futures Configuration
Set leverage, margin mode, and position mode (one-way / hedge).
Code samples assume the signed-request helper from Endpoints / Overview → Client setup.
POST /v2/futures/leverage
Set the leverage for a symbol.
| Auth | API_KEY (TRADE) |
Body
{
symbol: string;
leverage: number; // 1 – 125
forceWithOpenPosition?: boolean; // default false
}Behavior
- No open position on the symbol → leverage is updated immediately,
200. - Open position present without
forceWithOpenPosition: true→409:
{
"ok": false,
"error": "Symbol has an open position. Re-send with forceWithOpenPosition=true to confirm leverage change (this re-prices your liquidation level).",
"code": "OPEN_POSITION_LEVERAGE_GUARD"
}- With
forceWithOpenPosition: truethe venue is called; if the venue accepts and the liquidation re-pricing succeeds, response is200.
Recommended pattern — on 409 with code: OPEN_POSITION_LEVERAGE_GUARD,
escalate to the user (or your risk model) and only then resend with
forceWithOpenPosition: true.
Response
{ "ok": true, "data": { "leverage": 20, "symbol": "BTCUSDT" } }Example
TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{"symbol":"BTCUSDT","leverage":20}' \
"$BASE_URL/v2/futures/leverage?${QUERY}&signature=${SIG}"const res = await signedRequest('POST', '/v2/futures/leverage', {
body: { symbol: 'BTCUSDT', leverage: 20 },
});res = signed_request("POST", "/v2/futures/leverage",
body={"symbol": "BTCUSDT", "leverage": 20}).json()res, _ := zdex.SignedRequest("POST", "/v2/futures/leverage", nil,
map[string]any{"symbol": "BTCUSDT", "leverage": 20})let res = signed_request(reqwest::Method::POST, "/v2/futures/leverage",
&[], Some(&json!({ "symbol": "BTCUSDT", "leverage": 20 }))).await?;$res = signed_request('POST', '/v2/futures/leverage', [],
['symbol' => 'BTCUSDT', 'leverage' => 20]);POST /v2/futures/margin-type
Switch between cross and isolated margin.
| Auth | API_KEY (TRADE) |
Body
{
symbol: string;
marginType: "ISOLATED" | "CROSSED";
forceWithOpenPosition?: boolean;
}Same guard logic as leverage — open positions require
forceWithOpenPosition: true, otherwise 409 with
code: OPEN_POSITION_MARGIN_GUARD.
Response
{ "ok": true, "data": { "marginType": "ISOLATED", "symbol": "BTCUSDT" } }No-op response — when the venue reports the symbol is already in the
target mode, the response carries an extra unchanged: true field:
{ "ok": true, "data": { "marginType": "ISOLATED", "symbol": "BTCUSDT", "unchanged": true } }Branch on unchanged === true if you need to suppress "switched" toasts.
Example
TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{"symbol":"BTCUSDT","marginType":"ISOLATED"}' \
"$BASE_URL/v2/futures/margin-type?${QUERY}&signature=${SIG}"const res = await signedRequest('POST', '/v2/futures/margin-type', {
body: { symbol: 'BTCUSDT', marginType: 'ISOLATED' },
});res = signed_request("POST", "/v2/futures/margin-type",
body={"symbol": "BTCUSDT", "marginType": "ISOLATED"}).json()res, _ := zdex.SignedRequest("POST", "/v2/futures/margin-type", nil,
map[string]any{"symbol": "BTCUSDT", "marginType": "ISOLATED"})let res = signed_request(reqwest::Method::POST, "/v2/futures/margin-type",
&[], Some(&json!({ "symbol": "BTCUSDT", "marginType": "ISOLATED" }))).await?;$res = signed_request('POST', '/v2/futures/margin-type', [],
['symbol' => 'BTCUSDT', 'marginType' => 'ISOLATED']);POST /v2/futures/close-and-switch-margin
Atomically close every open position and cancel every working order on a
symbol, then flip the sub-account-wide margin mode. Use this when the
plain POST /v2/futures/margin-type returns OPEN_POSITION_MARGIN_GUARD
(or OPEN_POSITION_MARGIN_REJECT) and the trader has accepted closing
the position to make the switch happen.
| Auth | API_KEY (TRADE) |
Body
{
symbol: string; // "BTCUSDT" — drives close + cancel
targetMarginType: "ISOLATED" | "CROSSED"; // mode to flip to
}Behavior — runs three legs sequentially. Each completes before the next starts, but there is no rollback: if leg 2 succeeds and leg 3 fails, your position is closed and you'll need to retry the toggle from the UI.
- Cancel every working order on the symbol (
PENDING_NEW,NEW,PARTIALLY_FILLED). - Close every open position on the symbol with reduce-only
MARKETorders. In hedge mode bothLONGandSHORTlegs are closed independently. - Call the venue's
setMarginType(which is sub-wide, not per-symbol — same scope as/v2/futures/margin-type).
Response — full success
{
"ok": true,
"data": {
"symbol": "BTCUSDT",
"marginType": "ISOLATED",
"canceledOrders": ["12345678", "12345679"],
"closedPositions": [
{ "id": "cmpos...", "venuePositionId": "venue_pos_42", "quantity": "0.5" }
]
}
}Response — partial failure (leg 3 failed after leg 2 succeeded)
502 with the legs that did complete echoed back so the client can
explain to the trader exactly what state the account is in:
{
"ok": false,
"error": "Position closed but margin mode switch failed — please retry the toggle from the UI.",
"stage": "switch",
"closedPositions": [/* same shape as success */],
"canceledOrders": ["12345678"],
"details": { /* venue raw error */ }
}Response — leg 2 (close) failed
502 with stage: "close" and the venue's own error message surfaced as
error so the trader knows whether it was a margin conflict, a
quantity reject, or insufficient balance:
{
"ok": false,
"error": "Failed to close position before margin mode switch: <venue message>",
"stage": "close",
"venueErrorCode": -2010,
"details": { /* venue raw error */ }
}The endpoint detects "already closed venue-side" close failures
(-2010 + an "already closed/filled" or "reduce-only reject" message)
and reconciles the DB row instead of failing — your trader sees a clean
success in that race.
Side effects — order_canceled, position_update (one per closed
position) WebSocket pushes.
Example
TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{"symbol":"BTCUSDT","targetMarginType":"ISOLATED"}' \
"$BASE_URL/v2/futures/close-and-switch-margin?${QUERY}&signature=${SIG}"const res = await signedRequest('POST', '/v2/futures/close-and-switch-margin', {
body: { symbol: 'BTCUSDT', targetMarginType: 'ISOLATED' },
});res = signed_request("POST", "/v2/futures/close-and-switch-margin",
body={"symbol": "BTCUSDT", "targetMarginType": "ISOLATED"}).json()res, _ := zdex.SignedRequest("POST", "/v2/futures/close-and-switch-margin", nil,
map[string]any{"symbol": "BTCUSDT", "targetMarginType": "ISOLATED"})let res = signed_request(reqwest::Method::POST, "/v2/futures/close-and-switch-margin",
&[], Some(&json!({ "symbol": "BTCUSDT", "targetMarginType": "ISOLATED" }))).await?;$res = signed_request('POST', '/v2/futures/close-and-switch-margin', [],
['symbol' => 'BTCUSDT', 'targetMarginType' => 'ISOLATED']);POST /v2/futures/position-mode
Toggle account-wide position mode.
| Auth | API_KEY (TRADE) |
Body
{ "positionMode": "ONE_WAY" }positionMode is ONE_WAY or HEDGE. The change is account-wide; the
venue rejects with 400 if any open position exists.
Response
{ "ok": true, "data": { "positionMode": "ONE_WAY" } }Example
TS=$(($(date +%s) * 1000)); QUERY="timestamp=${TS}"
SIG=$(sign "$SECRET" "$QUERY")
curl -X POST -H "X-API-KEY: $API_KEY" -H "Content-Type: application/json" \
-d '{"positionMode":"ONE_WAY"}' \
"$BASE_URL/v2/futures/position-mode?${QUERY}&signature=${SIG}"const res = await signedRequest('POST', '/v2/futures/position-mode', {
body: { positionMode: 'ONE_WAY' },
});res = signed_request("POST", "/v2/futures/position-mode",
body={"positionMode": "ONE_WAY"}).json()res, _ := zdex.SignedRequest("POST", "/v2/futures/position-mode", nil,
map[string]any{"positionMode": "ONE_WAY"})let res = signed_request(reqwest::Method::POST, "/v2/futures/position-mode",
&[], Some(&json!({ "positionMode": "ONE_WAY" }))).await?;$res = signed_request('POST', '/v2/futures/position-mode', [],
['positionMode' => 'ONE_WAY']);