One HTTP API, keyed and versioned
JSON over HTTPS at trade-logx.com/v1: personal API keys, cursor pagination, stable error codes and signed webhooks. It covers strategies, decisions, positions and backtests; the dashboard also uses internal endpoints that are not part of it.
Authentication
A bearer token in the header. Create keys in the dashboard under Settings → Security → API keys; each is scoped (read, or read and control), revocable, and shown only once.
curl https://trade-logx.com/v1/positions \
-H "Authorization: Bearer $NEXUS_API_KEY" \
-H "Nexus-Version: 2026-09-24"Versioning
Nexus-Version header pins the response shape to a date. Omit it and you get the version your key was created against — never the newest, so a deploy on our side cannot change your parsing. The current version is 2026-09-24.Rate limits
X-RateLimit-Remaining; a 429 always carries Retry-After.Strategies
Returns the strategies the platform can run, each with the version that produced its record, its lifecycle (production or research-only), the timeframes it supports and its execution mode. Every strategy is in paper mode: live order routing is locked.
example{ "data": [ { "id": "brain", "name": "Decision Brain", "version": "1.0.0", "lifecycle": "production", "mode": "paper", "timeframes": ["15m", "1h", "4h"], "markets": ["binance_usdm:perpetual"] } ], "live_routing": "locked" }Needs the control scope. Paper is the only mode available, so a request for paper succeeds without changing anything, and a request for live is refused while live order routing is locked.
example{ "mode": "live" } → 409 { "error": { "code": "live_routing_locked", "message": "Live order routing is locked on this platform; every strategy runs in paper mode." } } → 200 { "id": "brain", "mode": "paper", "changed": false } // for { "mode": "paper" }
Decisions
Newest first. Filter by verdict (accepted or rejected), symbol and since (an ISO date). The rejections are the point: they are the only place you can see what the system nearly did, and why it did not. Pages of up to 200; pass next_cursor back as cursor for the next page.
exampleGET /v1/decisions?verdict=rejected&since=2026-09-01&limit=50 { "data": [ { "id": "dec_41", "ts": "2026-09-24T09:15:00+00:00", "symbol": "XRPUSDT", "strategy": "Decision Brain", "verdict": "rejected", "quality_score": 48, "blocked_by": "quality", "reason": "Quality score 48 is below the minimum of 60.", "rules_failed": ["min_quality_score"], "executed": false } ], "next_cursor": "dec_41" }Decisions are stored with their scores, rules and reason, but not the full market inputs they were made from, so they cannot be re-run. The endpoint answers 501 until those inputs are kept.
example→ 501 { "error": { "code": "not_available", "message": "Decisions are stored with their scores and rules, not the full market inputs they were made from, so they cannot be re-run yet." } }
Positions
Every open paper position, with the latest observed mark, unrealised P&L and R multiple. Stops and targets are managed by the engine on every candle — they are not orders held at an exchange, and the response says so.
example{ "data": [ { "id": "7c1e…", "instance_id": "eb1a2ce8", "symbol": "XRPUSDT", "side": "long", "size": 1250.0, "entry": 0.5412, "mark": 0.5498, "r_multiple": 0.86, "unrealized_pnl": 10.75, "mode": "paper", "protective": { "stop": 0.5312, "target": 0.5712, "managed_by": "engine" } } ] }Needs the control scope. Closes at a fresh observed price and never at a guessed one — if there is no recent mark the request is refused with no_mark. The close is written to the audit log under the key's name.
example{ "reason": "manual flatten before travel" } → 200 { "id": "7c1e…", "status": "closed", "close": { "exit": 0.5498, "pnl": 10.75 } } → 409 { "error": { "code": "no_mark", ... } }
Backtests
Needs the control scope. Runs a built-in strategy over the Binance candles cached on the server (300 to 1,500 bars). If the server has no data for that symbol and timeframe, the backtest fails with that reason rather than reporting an empty result. Parameter sweeps are not available through the API yet.
example{ "strategy": "brain", "symbol": "BTCUSDT", "timeframe": "15m", "bars": 1000 } → 202 { "id": "bt_2f77a1c9e0b4", "status": "queued" }Gross performance and performance after modelled fees, spread and slippage are reported side by side, with the difference in R. A strategy whose edge disappears once costs are applied shows as exactly that. Results are kept while the server runs; only the key that queued a backtest can read it.
example{ "id": "bt_2f77a1c9e0b4", "status": "complete", "result": { "gross": { "trades": 38, "win_rate": 42.1, "expectancy_r": 0.12, "net_r": 4.56 }, "net": { "trades": 38, "win_rate": 39.5, "expectancy_r": -0.05, "net_r": -1.9 }, "costs": { "cost_pct_per_side": 0.0006, "net_r_drag": 6.46 } } }
Webhooks
Every decision the engine records, pushed to your endpoint as it happens. Add endpoints in the dashboard under Settings → Security → Webhooks; the signing secret is shown once.
{
"id": "evt_dec_41",
"type": "decision.rejected",
"occurred_at": "2026-09-24T09:18:00Z",
"sequence": 41,
"idempotency_key": "dec_41:rejected",
"data": { "...": "the same object GET /v1/decisions/dec_41 returns" }
}Events
decision.accepted, decision.rejected, and webhook.test when you press Send test. A new endpoint starts from the next decision; history is not replayed to it.Signatures
Nexus-Signature: t=…,v1=… is HMAC-SHA256 of t.body with your secret. Verify the raw body before parsing and reject stale timestamps; every SDK has a helper for it.Delivery is at-least-once, so handlers must be idempotent — the idempotency_key is stable across retries. Any answer other than 2xx is retried after 30 seconds, doubling up to an hour, for 24 hours. Every attempt, with the status code your endpoint returned, is listed under the endpoint in the dashboard.
Errors
Every error has the same shape: {"error": {"code": "…", "message": "…"}}. Branch on the code; the message is for people.
| Status | Code | Means |
|---|---|---|
| 400 | invalid_request | Malformed body, an unknown Nexus-Version, or a parameter outside its allowed range. |
| 401 | unauthenticated | Missing, malformed or revoked API key. |
| 403 | insufficient_scope | The key is valid but read-only; this operation needs the control scope. |
| 404 | not_found | No such strategy, decision, position or backtest (for this key). |
| 409 | live_routing_locked | A request to trade live. Live order routing is locked for every caller. |
| 409 | no_mark | A close without a fresh price to close at. Nothing is closed at a guessed price. |
| 409 | ambiguous_close | The position's instance holds several positions; close them from the dashboard. |
| 429 | rate_limited | Retry after the seconds given in Retry-After. |
| 501 | not_available | The endpoint exists but the capability does not yet (decision replay). |
409 live_routing_locked is by design