TICKERALL!
Developer reference

TickerAll API Docs

Everything you need to connect a broker account and trade it from your own code — REST endpoints, the realtime WebSocket, authentication, and copy-paste examples in curl, TypeScript, and Python.

Overview

TickerAll is a hosted API for connecting to and automating your own MT4/MT5 broker accounts. You write your strategy in any language; we hold a fast, persistent connection straight to your broker and keep it live for you, exposed over a clean REST + WebSocket API — so there's no MT4/MT5 terminal in the path, no EA bridge to wire up, and no reconnect churn when your strategy needs it.

The API has two planes:

REST control + data plane

https://api.tickerall.com

Connect accounts, read balance and positions, list symbols, and place / close / modify orders. Standard JSON over HTTPS.

Realtime data plane

wss://api.tickerall.com

A single long-lived WebSocket streams live ticks, position updates, and account updates as they happen.

One API key can hold many broker accounts at once — each scoped by its accountId. Symbol names are pass-through: you see the broker’s native names (e.g. EURUSDm, BTCUSDm), with no remapping. Prefer a typed client over raw HTTP? Grab the official SDKs linked at the top — TypeScript and Python, both wrapping this same REST + WebSocket API.

Authentication

Every request authenticates with a TickerAll API key sent as a bearer token. Sign up, open API keys in your dashboard, and create a key — it looks like cf_api_…. Treat it like a password; it carries the access of your whole account.

HTTP header
Authorization: Bearer cf_api_xxxxxxxxxxxxxxxxxxxx

Send this header on every REST call. For the WebSocket, send the same header on the upgrade request, or pass ?token=<key> in the URL where headers are awkward (e.g. browser clients).

A missing or invalid key returns 401 UNAUTHORIZED. Keys are validated on our side; revoking a key from the dashboard takes effect within a few minutes.

Quickstart

From zero to a live order in four calls. Each step builds on the last. Prefer to click through it first? The dashboard's Test panel runs every one of these calls from your browser — no code.

01

Connect a broker account

POST your broker credentials to /v1/sessions. We authenticate against the broker and return an accountId. Your password is held in memory only while your connection is live, never saved to disk.

curl -X POST https://api.tickerall.com/v1/sessions \
  -H "Authorization: Bearer cf_api_xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "broker": "mt5",
    "server": "Exness-MT5Trial7",
    "account": 12345678,
    "password": "your-broker-password",
    "terminalType": "MOBILE"
  }'
# terminalType is optional — "MOBILE" (default) or "WEB".

# => { "accountId": "acc_8Kd3...", "isDemo": true, "status": "connected", ... }
02

Read account state

Use the accountId to read balance, equity, and open positions.

curl https://api.tickerall.com/v1/accounts/acc_8Kd3... \
  -H "Authorization: Bearer cf_api_xxxx"

# => { "status": "online", "account": { "balance": 9871.42, ... }, "positions": [...] }
03

Place and close an order

State-changing calls require an Idempotency-Key header — a unique string per logical action, so a retried request never double-fires.

# Open a 0.10-lot BUY market order (note the unique Idempotency-Key)
curl -X POST https://api.tickerall.com/v1/accounts/acc_8Kd3.../orders \
  -H "Authorization: Bearer cf_api_xxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "type": "market", "symbol": "BTCUSDm", "side": "BUY",
        "volume": 0.10, "stopLoss": 71000, "takeProfit": 84000 }'
# => { "ticket": 4072808150, "status": "open", ... }

# Close it (ticket from the response above)
curl -X DELETE https://api.tickerall.com/v1/accounts/acc_8Kd3.../positions/4072808150 \
  -H "Authorization: Bearer cf_api_xxxx" \
  -H "Idempotency-Key: $(uuidgen)"
# => { "ticket": 4072808150, "closed": true, ... }
04

Stream live ticks

Open the WebSocket and subscribe to the symbols you care about.

# curl can't speak WebSocket; use websocat (or any WS client).
# Install websocat: brew install websocat | cargo install websocat | apt install websocat
websocat "wss://api.tickerall.com/v1/stream?token=cf_api_xxxx"

# then paste a subscribe frame:
{"type":"subscribe","channels":[{"kind":"ticks","accountId":"acc_8Kd3...","symbols":["BTCUSDm"]}]}

# server streams:
# {"type":"tick","symbol":"BTCUSDm","bid":77512.73,"ask":77514.10,"timestamp":"..."}

Postman & Insomnia

Prefer a GUI client? Import a ready-made collection — every REST endpoint below, with the Authorization bearer token wired up, an auto-generated Idempotency-Key on every write, example request bodies, and an example response on each call. Set two variables and start sending. Download the file, or use the Copy to clipboard option and paste it straight into the app.

PostmanInsomnia

Use the Download ▾ menu to switch between saving the .json file and Copy to clipboard — then paste it straight into Postman or Insomnia, no file needed.

Postman
  1. Import → drop in the file, or Raw text → paste the copied JSON.
  2. Open the collection’s Variables and set apiKey to your cf_api_… key.
  3. Run Open a broker session, then set accountId (and ticket once you have one).
Insomnia
  1. ImportFrom File, or From Clipboard after copying.
  2. Open Manage Environments and set apiKey, then accountId.
  3. The realtime feed is included as a ready WebSocket request.

baseUrl and wsBaseUrl come pre-filled. The WebSocket connect URL and subscribe frame are bundled in too — as a runnable request in Insomnia, and documented in the WebSocket (realtime) folder in Postman.

Conventions

Base URLs

REST: https://api.tickerall.com · WebSocket: wss://api.tickerall.com/v1/stream

Content type

Request and response bodies are JSON. Send Content-Type: application/json on calls with a body.

Idempotency-Key (required on writes)

Every state-changing call (POST orders, DELETE / PATCH positions) requires an Idempotency-Key: <unique-string> header. We store (key → response) for 24 hours; resending the same key replays the original response without re-executing. Omitting the header is a VALIDATION_ERROR. Use a fresh UUID per logical action.

Timestamps & numbers

Timestamps are ISO-8601 UTC strings. Tickets are integers. Prices and volumes are JSON numbers (lots for volume, e.g. 0.10).

Connection warmth

We keep a broker connection “hot” for a window after you start a session. If it cools, calls return 409 BROKER_ACCOUNT_NOT_HOT — just POST /v1/sessions again to re-warm it.

Sessions

A session is a warm, authenticated connection to one broker account. Start one to get an accountId; delete it to disconnect.

POST/v1/sessions

Connect a broker account. We authenticate and warm a live connection, then hand back an accountId — the handle for THIS broker connection. One API key can hold several broker accounts, so the id lives in this response (and in GET /v1/accounts), NOT in the key. Use it in every later /v1/accounts/:id call. Your password is held in memory only while the connection is live, never saved to disk.

Request body (JSON)
FieldTypeDescription
brokerreq"mt4" | "mt5"Which platform your broker server runs.
serverreqstringBroker server name, e.g. "Exness-MT5Trial7".
accountreqnumber | stringYour numeric broker login — the account number your broker assigns (e.g. 12345678). NOT your TickerAll email.
passwordreqstringBroker (investor or master) password. Used once to authenticate; never persisted.
terminalTypeoptional"MOBILE" | "WEB"Which client the connection presents AS — MOBILE (default) or WEB. Both expose the full surface (account, quotes, positions, history). Omit for MOBILE.
webTerminalUrloptionalstringThe broker’s web-terminal URL, e.g. https://mt5.yourbroker.com. REQUIRED when terminalType is "WEB" — web terminals are per-broker-domain, so the URL must be supplied. Ignored for MOBILE.
webEndpointoptionalstringAdvanced, optional: an explicit WebSocket endpoint override (e.g. wss://host/path) for the rare broker whose WS host/path differs from the webTerminalUrl derivation. Ignored for MOBILE.
200 OK
{
  "accountId": "acc_8Kd3...",
  "isDemo": true,
  "status": "connected",
  "expiresAt": "2026-05-22T18:42:10.000Z"
}
  • On the Free tier, only demo broker accounts are accepted — a real-money login is rejected with FREE_TIER_LIVE_REJECTED.
  • The connection stays warm for a while (see expiresAt). If it cools, calls return BROKER_ACCOUNT_NOT_HOT — just POST /v1/sessions again to reconnect.
DELETE/v1/sessions/:accountId

Disconnect a broker account and release its connection. Returns no body.

Path parameters
FieldTypeDescription
accountIdreqstringThe accountId returned by POST /v1/sessions.
204 No Content
(empty body)

Accounts

List your connected accounts, or fetch one account’s live financials and open positions.

GET/v1/accounts

List every broker account attached to your API key, with connection state.

200 OK
[
  {
    "id": "acc_8Kd3...",
    "broker": "mt5",
    "server": "Exness-MT5Trial7",
    "accountNumber": "****5678",
    "isDemo": true,
    "status": "CONNECTED",
    "hot": true,
    "lastHotAt": "2026-05-22T18:30:01.000Z",
    "createdAt": "2026-05-20T09:11:55.000Z"
  }
]
  • accountNumber is masked to the last 4 digits. hot=false means the connection cooled — POST /v1/sessions to re-warm it.
GET/v1/accounts/:id

Live account info — balance, equity, margin, leverage — plus the current open positions.

Path parameters
FieldTypeDescription
idreqstringaccountId.
200 OK (status: "online")
{
  "id": "acc_8Kd3...",
  "broker": "mt5",
  "server": "Exness-MT5Trial7",
  "accountNumber": "****5678",
  "isDemo": true,
  "status": "online",
  "account": {
    "name": "Demo Account 12345678",
    "accountType": "demo",
    "leverage": 500,
    "balance": 9871.42,
    "currency": "USD",
    "equity": 9863.10,
    "margin": 142.50,
    "freeMargin": 9720.60,
    "marginLevel": 6921.5
  },
  "positions": [
    {
      "ticket": 4072808150,
      "symbol": "BTCUSDm",
      "side": "BUY",
      "volume": 0.10,
      "entryPrice": 77512.73,
      "stopLoss": 71000,
      "takeProfit": 84000,
      "currentPrice": 77640.10,
      "profit": 12.74,
      "swap": 0,
      "commission": 0,
      "comment": "my-strategy",
      "magic": 0,
      "openTime": "2026-05-22T17:55:03.000Z"
    }
  ]
}
  • If the connection has cooled, you get status:"offline" with a hint instead of live data — POST /v1/sessions to reconnect.
  • Money fields (equity, margin, freeMargin, marginLevel) may be null on an MT4 account that has not yet pushed a balance frame — null is honest "not available yet", never a misleading 0.
DELETE/v1/accounts/:id

Remove a broker account from your roster. We disconnect its live connection and drop it from your account list and from billing — this does NOT touch the broker account itself or any open positions. Reversible: reconnect the same login with POST /v1/sessions to re-add it.

Path parameters
FieldTypeDescription
idreqstringaccountId.
200 OK
{
  "id": "acc_8Kd3...",
  "status": "DISCONNECTED",
  "removed": true,
  "billableCount": 0
}
  • Idempotent — removing an already-removed account returns the same 200 shape.
  • If the account had always-hot enabled, that per-connection charge stops immediately; billableCount is your remaining always-hot connection count.
POST/v1/accounts/:id/migrateIdempotency-Key

Switch which terminal type the account presents AS ("MOBILE" or "WEB"). Your open positions, pending orders and balance live on the broker account, not the connection, so they are preserved across the switch.

Path parameters
FieldTypeDescription
idreqstringaccountId.
Request body (JSON)
FieldTypeDescription
toreq"MOBILE" | "WEB"The transport to switch to.
200 OK
{
  "id": "acc_8Kd3...",
  "terminalType": "MOBILE",
  "status": "noop"
}
  • status is "noop" when the account is already on the requested transport.
  • Switching runs only when the account is idle (no in-flight trade — otherwise 409).
  • Both terminal types expose the full surface (account, quotes, positions, history).
  • The switch is zero-gap — the new transport is warmed before the old session is dropped — so open positions, orders and balance carry over untouched.

Symbols

Discover the instruments you can trade on an account, in the broker’s native names.

GET/v1/accounts/:id/symbols

List tradeable symbols on the account, in the broker’s native names (pass-through, no normalization). symbols is the full catalog; watched is the subset that is actively streaming live ticks right now.

Path parameters
FieldTypeDescription
idreqstringaccountId.
200 OK
{
  "symbols": ["BTCUSDm", "ETHUSDm", "EURUSDm", "XAUUSDm", "USOILm", "..."],
  "watched": ["BTCUSDm", "ETHUSDm", "EURUSDm"]
}
  • Use a name from symbols when placing orders; subscribe to a name to start it ticking on the WebSocket.

Candles & history

Historical OHLC bars are included on every plan — no extra charge. The public endpoint GET /v1/public/candles (no API key required) returns bars at any of nine timeframes: M1, M5, M15, M30, H1, H4, D1, W1, MN1. Coarser timeframes reach further back — daily bars reach back years; a single request returns as much as fits in a few seconds.

GET/v1/accounts/:id/candles

Fetch historical OHLC bars from your connected broker, for any symbol the broker streams on this account. Returns the most-recent N hours of bars at the requested timeframe. Coarser timeframes (H4, D1, W1, MN1) reach much further back — daily bars typically cover years of history.

Path parameters
FieldTypeDescription
idreqstringaccountId.
Query parameters
FieldTypeDescription
symbolreqstringBroker-native symbol name, e.g. "BTCUSDm". Discover names via GET /v1/accounts/:id/symbols.
hoursoptionalnumberHow many hours of data to return, counted backwards from now. Defaults to 24, capped at ~5 years.
timeframeoptional"M1"|"M5"|"M15"|"M30"|"H1"|"H4"|"D1"|"W1"|"MN1"Bar interval. Defaults to "M5". Coarser timeframes go back further for the same hours value.
200 OK
{
  "symbol": "BTCUSDm",
  "hours": 17520,
  "timeframe": "D1",
  "candles": [
    { "timestamp": 1747699200, "open": 104200.10, "high": 107840.55, "low": 103520.00, "close": 106910.73, "bid": 106910.73 },
    { "timestamp": 1747785600, "open": 106910.73, "high": 108100.00, "low": 105480.20, "close": 107512.40, "bid": 107512.40 }
  ]
}
  • Authed — needs your API key (same as the rest of the customer API). Works for any symbol your broker exposes on the connected account.
  • Each candle is { timestamp, open, high, low, close, bid }. timestamp is the bar OPEN time in Unix seconds (UTC); bid mirrors close.
  • Timeframes: M1, M5, M15, M30, H1, H4, D1, W1, MN1. Daily and coarser reach back years; intraday (M1–H4) covers recent months. One request returns as much history as fits in a few seconds — pass a large hours and take what comes back.
  • Deep look-backs are isolated onto a dedicated history connection — a big walk never disturbs your live tick stream.
  • If the broker returns no decodable bars for the symbol/range (e.g. an illiquid pair), the response is a 200 with an empty candles array — never a 500.
GET/v1/public/candles

Unauthenticated read of the always-on demo feed — powers the sparklines and chart on tickerall.com. Limited to TickerAll’s demo symbol list and only callable from tickerall.com (origin-gated). For arbitrary broker symbols from your own code, use GET /v1/accounts/:id/candles above.

Query parameters
FieldTypeDescription
symbolreqstringOne of the demo feed’s symbols (e.g. BTCUSDm, ETHUSDm, EURUSDm, XAUUSDm).
hoursoptionalnumberHow many hours of data to return. Defaults to 24, capped at ~5 years.
timeframeoptional"M1"|"M5"|"M15"|"M30"|"H1"|"H4"|"D1"|"W1"|"MN1"Bar interval. Defaults to "M5". Coarser timeframes go back further for the same hours value.
200 OK
{
  "symbol": "BTCUSDm",
  "hours": 17520,
  "timeframe": "D1",
  "candles": [
    { "timestamp": 1747699200, "open": 104200.10, "high": 107840.55, "low": 103520.00, "close": 106910.73, "bid": 106910.73 },
    { "timestamp": 1747785600, "open": 106910.73, "high": 108100.00, "low": 105480.20, "close": 107512.40, "bid": 107512.40 }
  ]
}
  • No API key needed, but origin-gated: this endpoint accepts requests from tickerall.com only and exists to drive the public demo widgets. For programmatic access from your own code use GET /v1/accounts/:id/candles instead — it works on any symbol your broker exposes.
  • Each candle is { timestamp, open, high, low, close, bid }. timestamp is the bar OPEN time in Unix seconds (UTC); bid mirrors close.
  • Only the demo feed’s symbol list is available here. For any other symbol, connect a broker account and call GET /v1/accounts/:id/candles instead.

Orders

Place market or pending orders, close positions (full or partial), and modify stop-loss / take-profit. All three require an Idempotency-Key header.

POST/v1/accounts/:id/ordersIdempotency-Key

Place a market order (fills immediately) or a pending limit/stop order (rests until price is hit).

Path parameters
FieldTypeDescription
idreqstringaccountId.
Request body (JSON)
FieldTypeDescription
typereq"market" | "limit" | "stop"Order type.
symbolreqstringBroker-native symbol, e.g. "BTCUSDm".
sidereq"BUY" | "SELL"Trade direction.
volumereqnumberLots, e.g. 0.10. Must be positive.
priceoptionalnumberTrigger price. Required for limit and stop; ignored for market.
stopLossoptionalnumberStop-loss price. Omit for none.
takeProfitoptionalnumberTake-profit price. Omit for none.
commentoptionalstring (≤ 31 chars)Optional strategy tag stored on the order.
201 Created
{
  "ticket": 4072808150,
  "symbol": "BTCUSDm",
  "side": "BUY",
  "type": "market",
  "volume": 0.10,
  "price": null,
  "stopLoss": 71000,
  "takeProfit": 84000,
  "comment": "my-strategy",
  "status": "open",
  "timestamp": "2026-05-22T17:55:03.000Z"
}
  • Requires an Idempotency-Key header (see Conventions). Re-sending the same key returns the original response without placing a second order.
  • status is "open" for market orders and "pending" for limit/stop orders.
  • A broker rejection (bad volume, market closed, stop-level too tight, insufficient margin) comes back as 422 BROKER_REJECTED with the broker’s reason in message.
DELETE/v1/accounts/:id/positions/:ticketIdempotency-Key

Close an open position. Omit volume for a full close, or pass a smaller volume for a partial close.

Path parameters
FieldTypeDescription
idreqstringaccountId.
ticketreqnumberTicket of the position to close (from the order response or GET /v1/accounts/:id).
Request body (JSON)
FieldTypeDescription
volumeoptionalnumberPartial-close volume in lots. If omitted, the whole position is closed.
200 OK
{
  "ticket": 4072808150,
  "symbol": "BTCUSDm",
  "side": "BUY",
  "volume": 0.10,
  "closed": true,
  "timestamp": "2026-05-22T18:10:44.000Z"
}
  • Requires an Idempotency-Key header.
  • If the ticket is not an open position on this account you get 404 TICKET_NOT_FOUND.
PATCH/v1/accounts/:id/positions/:ticketIdempotency-Key

Modify the stop-loss and/or take-profit of an open position. Provide at least one of stopLoss / takeProfit.

Path parameters
FieldTypeDescription
idreqstringaccountId.
ticketreqnumberTicket of the position to modify.
Request body (JSON)
FieldTypeDescription
stopLossoptionalnumberNew stop-loss price. Omit to leave unchanged.
takeProfitoptionalnumberNew take-profit price. Omit to leave unchanged.
200 OK
{
  "ticket": 4072808150,
  "symbol": "BTCUSDm",
  "side": "BUY",
  "volume": 0.10,
  "stopLoss": 72000,
  "takeProfit": 85000,
  "timestamp": "2026-05-22T18:12:09.000Z"
}
  • Requires an Idempotency-Key header.
  • You must supply at least one of stopLoss or takeProfit; sending neither is a VALIDATION_ERROR.
  • Some brokers enforce a minimum stop distance (stop level). Too-tight values come back as 422 BROKER_REJECTED.

Trade history

Your account’s closed-trade history — executed trades paired into round-trips (entry + exit) with realised P/L, the equivalent of MT5’s history_deals_get. Returns the recent window your broker provides on connect plus anything closed live during the session; filter by symbol and close-time range.

GET/v1/accounts/:id/history

Closed-trade history for the account — executed trades paired into round-trips (entry + exit), the equivalent of MT5’s history_deals_get. Returns the recent window your broker provides on connect plus any trades closed live during the session. Filter by symbol and close-time range.

Path parameters
FieldTypeDescription
idreqstringaccountId.
Query parameters
FieldTypeDescription
symboloptionalstringNarrow to one broker-native symbol, e.g. "ETHUSDm". Omit for all symbols.
fromoptionalISO-8601 | epoch secondsOnly trades closed at/after this time.
tooptionalISO-8601 | epoch secondsOnly trades closed at/before this time.
limitoptionalnumberMax rows returned, newest-first. Defaults to 500, capped at 5000.
waitMsoptionalnumberHow long to wait (ms) for history to populate on a just-connected account. Defaults to 4000; pass 0 to skip the wait on a warm connection.
200 OK
{
  "trades": [
    {
      "ticket": "4072808150",
      "symbol": "ETHUSDm",
      "side": "BUY",
      "volume": 0.10,
      "openPrice": 2500.50,
      "closePrice": 2510.25,
      "openTime": "2026-05-20T10:00:00.000Z",
      "closeTime": "2026-05-20T12:30:00.000Z",
      "profit": 0.98,
      "swap": 0,
      "commission": 0,
      "stopLoss": 0,
      "takeProfit": 0,
      "closeTicket": "4072808151",
      "complete": true
    }
  ],
  "count": 1,
  "limit": 500
}
  • Returns the recent window your broker pushes on connect (typically the last few weeks) plus trades closed live during the current session. from/to filter those rows — they do not fetch further back than the broker’s window.
  • Each row is a round-trip: ticket is the open/position ticket; closeTicket is the closing deal (may be null for a trade closed live this session). profit is realised P/L in the account currency.
  • complete=true is a confirmed round-trip with trustworthy P/L. complete=false marks an incomplete/unmatched row, where profit is reported as null rather than a misleading 0.
  • swap and commission are reported as 0 (not carried in this data set).
  • A cheap read that never disturbs your live tick stream. On a connection that has cooled you get 409 BROKER_ACCOUNT_NOT_HOT — POST /v1/sessions to reconnect.

WebSocket — realtime data

Open a single long-lived WebSocket to wss://api.tickerall.com/v1/stream for live data. Authenticate with the same bearer token (header on the upgrade, or ?token=… in the URL). After connecting, send a subscribe message listing the channels you want.

There are three channel kinds — ticks (per-symbol price updates), positions (open/update/close events), and account (balance / equity snapshots). All are scoped by accountId.

Client → server: subscribe
send
{
  "type": "subscribe",
  "channels": [
    { "kind": "ticks", "accountId": "acc_8Kd3...", "symbols": ["BTCUSDm", "ETHUSDm"] },
    { "kind": "positions", "accountId": "acc_8Kd3..." },
    { "kind": "account", "accountId": "acc_8Kd3..." }
  ],
  "correlationId": "sub-1"
}

The server replies with a subscribed frame echoing which channels were accepted and which were rejected (with a code — see below). Unsubscribe with the same channel shape and "type": "unsubscribe". Send { "type": "ping" } to get a pong and keep the connection alive.

Server → client: pushes
receive
// price tick
{ "type": "tick", "accountId": "acc_8Kd3...", "symbol": "BTCUSDm",
  "bid": 77512.73, "ask": 77514.10, "timestamp": "2026-05-22T18:01:22.317Z" }

// position lifecycle (event: "opened" | "updated" | "closed")
{ "type": "position_update", "accountId": "acc_8Kd3...", "event": "opened",
  "position": { "ticket": 4072808150, "symbol": "BTCUSDm", "side": "BUY",
                "volume": 0.10, "entryPrice": 77512.73, "profit": 0 } }

// account snapshot
{ "type": "account_update", "accountId": "acc_8Kd3...",
  "snapshot": { "balance": 9871.42, "equity": 9863.10, "margin": 142.50 } }

// subscribe acknowledgement
{ "type": "subscribed", "channels": [ ... ], "rejected": [], "correlationId": "sub-1" }
Subscribe rejection codes
CodeMeaning
INVALID_MESSAGEThe frame was not valid JSON or did not match the message schema.
RATE_LIMITYou sent messages too fast. Slow down and retry.
NOT_FOUNDSubscribe rejected: no account with that accountId.
FORBIDDENSubscribe rejected: that account is not yours.
BROKER_ACCOUNT_NOT_HOTSubscribe rejected: connection cooled. Call POST /v1/sessions to reconnect.
CHANNEL_LIMITSubscribe rejected: too many channels on this connection.

Protocol-level problems arrive as an error frame: { "type": "error", "code": "RATE_LIMIT", "message": "Slow down." }. The connection sends WebSocket ping frames as a heartbeat — reply with pong (most client libraries do this automatically) or you will be disconnected.

Errors

Every REST error uses the same envelope and a meaningful HTTP status. error is a stable machine code; message is human-readable. Validation failures add a details array naming the offending fields.

error envelope
{
  "error": "BROKER_REJECTED",
  "message": "Broker rejected the order: invalid volume",
  "details": [ /* present only on VALIDATION_ERROR */ ]
}
Common error codes
CodeHTTPMeaning
UNAUTHORIZED401Missing, malformed, or invalid Authorization header / API key.
VALIDATION_ERROR400The request body or params failed validation. A details array lists the offending fields.
BROKER_AUTH_FAILED401The broker rejected the credentials at POST /v1/sessions.
BROKER_UNREACHABLE503Could not reach the broker, or it did not complete the handshake in time. Retry shortly.
BROKER_ACCOUNT_NOT_HOT409The connection cooled. Call POST /v1/sessions with credentials to reconnect.
BROKER_REJECTED422The broker refused the order/close/modify. The reason is in message (e.g. bad volume, market closed, stop level).
TICKET_NOT_FOUND404The position ticket is not open on this account.
BROKER_ACCOUNT_NOT_FOUND404No broker account with that id belongs to your key.
BROKER_ACCOUNT_ALREADY_LINKED409That broker account is already linked to another TickerAll customer.
FREE_TIER_LIVE_REJECTED403The Free tier only supports demo accounts. Upgrade to Pro to connect a real-money account.
DEMO_ACCOUNT_RESERVED403That broker account is reserved by TickerAll for the public demo and cannot be attached.
TIER_ACCOUNT_CAP_REACHED403You hit your plan’s broker-account cap. Upgrade, or contact us for Enterprise.
INTERNAL_ERROR500Unexpected server error. Safe to retry idempotent calls.

Pricing & limits

Reads — positions, balance, ticks, bars — are uncapped on every tier. Only real-account order placements are metered. The full breakdown lives on the pricing section.

Free — $0

Up to 5 demo broker accounts. Unlimited demo orders. No real-money accounts (a live login is rejected with FREE_TIER_LIVE_REJECTED). The demo-only gate makes abuse pointless — build and test forever, free.

Pro — $39/mo

30 live accounts included (demo accounts always free), with per-account overage on live accounts above that. Unlimited real-account orders. Historical OHLC candles across all timeframes (M1–MN1), and real-time WebSocket streaming.

Exceeding your plan’s account cap returns 403 TIER_ACCOUNT_CAP_REACHED. Need more than Pro covers? Talk to us about Enterprise.

Ready to ship?

Grab an API key and make your first POST /v1/sessions in five minutes.

Sign up — free
API Docs · Ticker All!