API documentation

Bots — overview

Bots are LEXX’s flagship feature: strategy engines that run server-side, 24/7, placing and managing orders for you. The API gives you full control — create, configure, start, stop, command and monitor — everything the Terminal UI can do. Managing bots requires a trade-tier key. The terminal and the knowledge base call bots “strategies” — same thing; these docs say “bot”, matching the API.

The seven types

Type In one line Trades?
FIBO Fibonacci grid built for the “Aftershock” strategy — buys on retracement levels, sells one level up, averages into breakeven
CHANNEL Horizontal price channels — three flavors: GRID (order grid), LEVELS (manual levels), SCALE (Fibonacci-hybrid template)
SQUEEZE Squeeze (price-drop) trading — buys a sharp drop from the previous candle’s binding, sells on the bounce
INTRADAY Bounce or breakout of a level/trendline you define, with laddered take-profits
ALGO Named execution primitives: bracket, TP/SL pair, TWAP
ALARM Price/RSI alert — fires a notification when a level is crossed 🔕 service
NOTIFY Market scanner — notifies when pairs match volume/price filters 🔕 service

Lifecycle

POST /bots            →  bot created  (status NEW)
POST /bots/{id}/runs  →  running      (status STARTED, runId assigned)
   …POST /bots/{id}/runs/{runId}/message — command it while it runs…
DELETE /bots/{id}/runs/{runId}?cleanup=… →  stopped  (STOPPED / ERROR)
PATCH /bots/{id}      →  reconfigure  (only while stopped)
DELETE /bots/{id}     →  gone forever (history included)

In code, with the reference client:

// create → start → … → stop
const { data: bot } = await lexx.request("POST", "/bots", {
  body: { type: "FIBO", settings: { /* per-type config — see the type's page */ } },
  headers: { "X-Idempotency-Key": crypto.randomUUID() },
});

const { data: started } = await lexx.request("POST", `/bots/${bot.id}/runs`, {
  headers: { "X-Idempotency-Key": crypto.randomUUID() },
});
console.log(started.status, started.runId);      // "STARTED", current run id

// … live events arrive on the WebSocket `botStatus` channel …

await lexx.request("DELETE", `/bots/${bot.id}/runs/${started.runId}`, {
  query: { cleanup: "cancelAllOrders" },
  headers: { "X-Idempotency-Key": crypto.randomUUID() },
});

Key rules:

  • Statuses: NEW (never started) → STARTEDSTOPPED / ERROR. While running the bot carries a runId — a new one for every start.
  • Stopping options: cleanup = leaveAllOrders | cancelBuyOrders | cancelAllOrders; action=stop_and_sell additionally market-sells remaining position; force=true stops a run stuck in a transient state.
  • Reconfiguring: PATCH /bots/{id} with {config, options?, metadata?, restart?} works only on a stopped bot (409 otherwise); restart: true starts it again right after the update. The response contains {bot, old} — the new and previous versions. Note: X-Idempotency-Key is not honored on PATCH.
  • Deleting: running bots must be stopped first, or pass force=true to stop all runs and delete in one call.
  • Listing: GET /bots returns all your bots, filter only by ?type=; not paginated.

Batch operations — up to 20 bots per request

Call Body
Start many — POST /bots/batch/runs { "bots": ["id1", "id2", …] }
Stop many — DELETE /bots/batch/runs { "bots": [["botId","runId"], …], "cleanup"?, "action"?, "force"? }
Delete many — DELETE /bots/batch { "bots": ["id1", "id2", …] }

The response is always an array of per-bot results {id, success, runId?, error?, bot?} — one entry per requested bot, successes and failures mixed. Batch calls count as one request against the rate limit.

The create request

{
  "type": "FIBO",                   authoritative bot type
  "settings": {  },                per-type config; settings.exchange is REQUIRED
  "options":  {  },                optional runtime options (type-specific)
  "metadata": "…",                  optional string for your own tracking
  "tag": "scalping" optional label 50 chars, for grouping
}
  • The top-level type is authoritative; a type inside settings is optional and, if present, must match.
  • The gateway validates only type and settings.exchange at creation — deep validation happens when the bot is built/started, so a config mistake typically surfaces as a start failure or ERROR status, not as a 400 on create.
  • If your API key has the allowedExchanges risk shield, it is enforced on the exchange inside bot settings too.

Runtime commands — POST /bots/{id}/runs/{runId}/message

Talk to a running bot without stopping it. Body: { "message": "...", "params": { … } }.

Command params
add_stoploss / update_stoploss A stop-loss object — required: strategy (e.g. breakeven, price_percent_buy), trigger ({type: "kline" | "exchange", value?}), order (e.g. {type: "STOP_MARKET", stopPrice: "…"}); optional: disabled, complete, snoozeDuration, maxStops. A stop whose trigger has already fired is rejected
delete_stoploss Same shape — the bot matches the existing stop to remove

A successful command returns data: null — effects show up in the bot’s behavior and the botStatus stream.

Config building blocks

The per-type pages document only their specific fields; these blocks are shared.

Which shape does each type use?

Watch the differences — they are the #1 source of config errors:

Type symbol form timeFrame units Trader fields (deposit/orders/stop)
FIBO object {base, quote} milliseconds
CHANNEL object {base, quote} milliseconds (optional — omitted = every tick)
SQUEEZE object {base, quote} milliseconds
INTRADAY object {base, quote} — (no timeFrame field)
ALGO string "BTCUSDT" minutes
ALARM object {base, quote} + ticker milliseconds — (service bot)
NOTIFY string (optional — omit to scan all pairs) milliseconds, required, minimum 300000 (5 min) — (service bot)

deposit — how much capital the bot may use

{ "value": "500", "asset": "USDT", "strategy": "fixed", "allocate": "auto" }
Field Meaning
value Amount (string). Interpreted per strategy
asset Denomination — quote asset on spot, margin asset on futures
strategy fixedvalue is an absolute amount · percentvalue is a % of available balance (optionally bounded by min/max)
allocate reserve — reserve the balance · auto — automatic · no_reserve — no reservation

stop — stop-loss rules (single object or array)

{ "strategy": "breakeven", "disabled": true, "complete": true,
  "trigger": { "type": "kline" }, "order": { "type": "MARKET" } }
Field Meaning
strategy Rule identifier. Values seen across verified configs: breakeven, price, price_percent_buy, trend_percent_price, timeout_buy, fixed, trailing
trigger.type kline (candles) · exchange (exchange price feed) · time (at a timestamp) · timeout (after a duration)
trigger.value Level in Fn.Format or a duration for timeout
trigger.edge / .closed / .timeFrame Candle edge; use closed candles only; candle timeframe
order Exit order: {type: MARKET | LIMIT} (INTRADAY extends it with stopPrice, workingType, correction, …)
complete true = closes the whole position
disabled Rule defined but inactive (common pattern: a pre-configured breakeven you enable later via update_stoploss)
snoozeDuration / maxStops Cooldown (ms) between firings / max firings per run

orders — how the bot places its buy/sell orders

{ "buy":  { "type": "LIMIT", "price": 0.3, "size": 1 },
  "sell": { "type": "LIMIT", "price": 0.5, "priceStrategy": "fixed" } }

type LIMIT/MARKET; price — typically a % offset for limit orders (0/omit = market); size — lots per order; priceStrategy (sell side only) — fixed | dynamic | trailing.

timeout — lifetime and inactivity rules (single object or array)

{ "type": "ttl", "value": 604800000 }

value is milliseconds. The engine recognizes only type: "ttl" (total lifetime; 7 d = 604800000, 30 d = 2592000000) — any other type string is silently ignored (per the spec), so there are no timeout-level “inactivity actions”.

filters — entry conditions (all must pass)

{ "volume": { "minVal": 500000, "percentChange": 5 },
  "price":  { "minVal": 0.01,  "percentChange": -3 },
  "market": { "rsi": 65, "trend": "up" },
  "blacklist": ["LUNAUSDT", "USTUSDT"] }

Fn.Format — price lines

LEXX encodes levels and trendlines as an object with exactly two {timestamp: price} entries — two points define a line:

{ "1743300000000": 94.08, "1746000000000": 96.50 }    ← rising trendline
{ "1743300000000": 60,    "1746000000000": 60 }        ← horizontal level at 60

Keys are string Unix-millisecond timestamps; values are numbers. Used in stop-loss triggers, ALARM ranges and the INTRADAY trend.

Common trader fields

profitAsset (accumulate profits in this asset), short (futures short-selling), positionSide (LONG/SHORT/BOTHhedge mode), marginType (ISOLATED/CROSSED), onetime (stop after the first full cycle), noticeLevel (notification verbosity 0–3), name (display name), range (price-range constraints, {type, min?, max?} — types seen: price, kline_percent, scaled_price, trend_percent_price).

Reading a bot back

PublicBot is an open object: guaranteed are only id, type, exchange. status and runId appear per lifecycle; the config may live under settings, config or options depending on the bot; there is no guaranteed createdAt/updatedAt. Internal fields (userId, credentials, worker info) are stripped and never present.

Live lifecycle events (BOT_STARTED, BOT_STOPPED, BOT_ERROR, BOT_UPDATE) stream on the botStatus WebSocket channel. Orders placed by a bot are marked creator: "BOT" and their IDs end with _{runId} (Orders).

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.