API documentation

Idempotency

The nightmare scenario of trading APIs: you POST /orders, the connection times out, and you have no idea whether the order was placed. Retry blindly and you might buy twice; don’t retry and you might not be in the market at all.

The fix is one header. Send a client-generated UUID as X-Idempotency-Key with every mutating request — if the same operation arrives again, the server recognizes it and replays the original response instead of executing twice.

How to use it

Generate one UUID per logical operation (not per attempt!) and attach it:

// JavaScript — reference client from the Authentication page
import crypto from "node:crypto";

const idempotencyKey = crypto.randomUUID();
const order = await lexx.request("POST", "/orders", {
  body: {
    exchange: "binance-spot", symbol: "BTCUSDT", side: "BUY", type: "LIMIT",
    quantity: "0.001", price: "60000.00", timeInForce: "GTC", marketType: "spot",
  },
  headers: { "X-Idempotency-Key": idempotencyKey },
});
# Python
import uuid

idempotency_key = str(uuid.uuid4())
order = lexx.request("POST", "/orders", body={
    "exchange": "binance-spot", "symbol": "BTCUSDT", "side": "BUY", "type": "LIMIT",
    "quantity": "0.001", "price": "60000.00", "timeInForce": "GTC", "marketType": "spot",
}, headers={"X-Idempotency-Key": idempotency_key})

On a successful mutating request the key is echoed back in the envelope — meta.idempotencyKey — so you can correlate logs.

Exactly what the server does

You send… Within Server responds
Same key + same parameters 1 hour Replays the original response (status + body) without re-executing
Same key + different parameters 1 hour 409 IDEMPOTENCY_CONFLICT“Idempotency key already used with different request parameters”
Same key while the original is still processing 409 IDEMPOTENCY_CONFLICT“Request is already processing”
Same key after the original ended in a 5xx 5xx responses are not cached — the request executes anew
Same key more than 1 hour later Treated as a brand-new request

Note the fine print: every completed response is cached — including 4xx errors. If your first attempt failed validation with a 400, the retry with the same key replays that 400; fix the request and use a new key, because the fixed parameters differ.

The safe-retry recipe

Two rules, and they come from different layers — don’t mix them up:

  1. Idempotency key: same across attempts. It is the identity of the operation.
  2. Signature: fresh on every attempt. Timestamp + signature are the identity of the HTTP request — replaying an identical signature is rejected as a duplicate (details). The reference client re-signs automatically on each call.

Put together:

// JavaScript — retries network failures and 5xx safely
import crypto from "node:crypto";

async function placeOrderReliably(lexx, order, attempts = 3) {
  const idempotencyKey = crypto.randomUUID();       // ONE key per logical order
  for (let i = 1; ; i++) {
    try {
      return await lexx.request("POST", "/orders", {
        body: order,
        headers: { "X-Idempotency-Key": idempotencyKey },
      });
    } catch (e) {
      const retryable = e.status === undefined      // network error / timeout
                     || e.status >= 500;            // 5xx are not cached — safe to retry
      if (retryable && i < attempts) {
        await new Promise(r => setTimeout(r, 1000 * i));
        continue;                                   // same key, fresh signature
      }
      throw e;
    }
  }
}
# Python — same idea
import time, uuid
import requests

def place_order_reliably(lexx, order, attempts=3):
    idempotency_key = str(uuid.uuid4())             # ONE key per logical order
    for i in range(1, attempts + 1):
        try:
            return lexx.request("POST", "/orders", body=order,
                                headers={"X-Idempotency-Key": idempotency_key})
        except LexxError as e:
            if e.status >= 500 and i < attempts:    # 5xx are not cached — safe to retry
                time.sleep(i)
                continue
            raise
        except requests.RequestException:           # network error / timeout
            if i < attempts:
                time.sleep(i)
                continue
            raise

Whatever happened during the timeout — order placed or not — the outcome of this function is exactly one order and the true response for it.

Handling the two 409 flavors:

  • “…already used with different request parameters” — a client bug: you reused a key for a different operation. Generate a new UUID for every new logical operation.
  • “Request is already processing” — the original attempt is still in flight. Wait a moment and retry with the same key; once the original completes you will get its replayed response.

Scope and caveats

  • Applies to POST / PUT / DELETE. The key is ignored on other methods — notably PATCH /bots/{id} runs without idempotency protection.
  • The key must be a UUID (e.g. 550e8400-e29b-41d4-a716-446655440000).
  • The header is optional everywhere — but strongly recommended for order creation and cancellation, and a good habit for every mutating call (bot start/stop, leverage changes).
  • The replay window is 1 hour; the cache stores the response exactly as first produced.

Verified against API spec v2.0.0 · 2026-07-11

Cookie Preferences

Manage your cookie preferences below. Necessary cookies are always active as they are essential for the website to function properly.

Strictly Necessary

Essential for the website to function. These cookies cannot be disabled.

Analytics

Help us understand how visitors interact with our website by collecting and reporting information anonymously.

Marketing

Used to track visitors across websites to display relevant advertisements.

Preferences

Allow the website to remember choices you make, such as language or region.