Skip to main content
Developers

API keys & security

Every request carries an API key. A key belongs to one trading account, allows only the scopes you chose, and carries limits the server enforces on every order.

How keys work

  • The account owner creates keys in the web terminal under Developers. Creating or rolling a key needs a fresh login with the account's master password; the investor password cannot create keys. That login also starts the keys' trading session.
  • A key belongs to one account on one server: the Live Server or the Demo Server, the two choices on the terminal's sign-in. Account numbers are per server, so live account 210 and demo account 210 are two different accounts, each with its own keys. GET /me shows the key's server (live or demo) and mode.
  • A key is shown once, when it is created. JAFX stores only a one-way hash, so nobody can show it to you again. If you lose it, roll or revoke it and create another.
  • Keys look like jafx_demo_k7mx2v9qr4tz8w1b6nfa_…: the account mode (demo for a Demo Server account, live for a Live Server account), a public key ID (shown in the terminal and in GET /me) and the secret.
  • Send the key on every request as Authorization: Bearer <key>. Never put it in a URL.
  • An account can hold up to 10 active keys. Keys expire after 1 to 365 days (default 90).

Trading sessions: around the clock, or 24 hours after each sign-in

Your keys place orders through your account's own trading session, the way JAFX Terminal places a manual trade, so the broker treats them as your own requests. For a bot or AI assistant that runs for days, switch on Keep my bots trading around the clock: JAFX then renews the session by itself, and your keys keep trading without you signing in.

With it off, the session comes from your latest sign-in: a password sign-in to JAFX Terminal, creating or rolling a key, or Renew on the Developers page. It lasts 24 hours from that sign-in, whether or not the terminal stays open, and the next sign-in renews it.

  • Without an active session, orders answer 409 sign_in_required and nothing reaches the broker. Retry with the same Idempotency-Key once you have signed in again or pressed Renew. On the Live Server, account data (the account, positions, orders and history) needs the session too.
  • GET /me shows it under session: whether it is active, and until when (expires_at). The MCP tool get_limits shows the same.
  • Stop API trading now on the Developers page ends it at once. So does a password change, or signing out of that session elsewhere. Signing out of JAFX Terminal itself does not stop your keys: the terminal's own session is a separate one.
  • An AI assistant connected over MCP can press the same Stop when you ask it to, with stop_api_trading, whatever its key. Nothing over MCP starts trading again: that is a sign-in to JAFX Terminal, or Renew.
  • Two hours before the session ends, and when it has ended (with why), JAFX leaves a notification on the Developers page and for your AI assistants, unless around-the-clock trading is on.
JSON
{ "session": { "active": true, "renews_automatically": false, "signed_in_at": "2026-11-04T18:20:00.000Z", "expires_at": "2026-11-05T18:20:00.000Z",
  "note": "Orders go through account 123456's own session until expires_at. Signing in to JAFX Terminal again renews it for 24 hours." } }

Around the clock

For bots and AI assistants that run for days, switch on Keep my bots trading around the clock on the Developers page, or tick it when you create a trading or proposals key. JAFX then keeps your trading password encrypted and signs your keys' session in again by itself, so they keep trading, reading and streaming without you signing in to JAFX Terminal.

  • To switch it on you enter your master password once. JAFX signs in with it straight away to check it, and keeps it only if the sign-in works. The investor password can't be used.
  • JAFX renews the session ahead of its 24 hours while your program is connected to the stream or has used its key in the last day, so a stream sees no gap. Otherwise it signs in again at your next request, which then takes a moment longer.
  • It is off by default. JAFX deletes the password at once when you switch it off, press Stop API trading now, or revoke the account's last key that can trade or propose.
  • If your trading account refuses the saved password, for example after you changed it, JAFX deletes it and never tries it again. Orders then answer 409 sign_in_required, GET /me shows session.ended_reason: password_refused, and the Developers page says around-the-clock trading stopped. Switch it on again with your current password.
  • If the trading server can't be reached, JAFX keeps the password and tries again shortly: meanwhile account data and trading answer 503 broker_unavailable with Retry-After.
JSON
{ "session": { "active": true, "renews_automatically": true, "signed_in_at": "2026-11-04T18:20:00.000Z", "expires_at": "2026-11-05T18:20:00.000Z",
  "note": "Orders go through account 123456's own session. Around-the-clock trading is on: JAFX signs the account in again by itself before expires_at, so your keys keep trading." } }
Demo and live accounts

A key's mode follows its account: Demo Server accounts get demo keys, Live Server accounts get live keys. Start with a demo account: if you have none, open one in the JAFX client area, under Accounts. A live key starts with tighter limits (0.10 lot per order, 10 open positions, 10 orders a minute, a 2% daily loss stop) and confirm mode on, so every order waits for your confirmation until you choose otherwise. Creating a trading key for a live account asks you to confirm that it can trade real money.

Presets and scopes

The web terminal offers three presets. Each is a set of scopes:

PresetScopesUse it for
Read onlymarket:read account:readDashboards, journals, research agents. Cannot trade.
Tradingmarket:read account:read tradeBots that place and manage orders themselves.
Proposalsmarket:read account:read trade:proposeAI assistants. Orders become proposals that you confirm in the terminal.
ScopeAllows
market:readInstruments, quotes and candles; the quotes and candles stream channels.
account:readAccount summary, positions, pending orders, closed trades, balance operations and request status; the account and orders stream channels.
tradePlace, change, close and cancel orders. They go to the broker straight away, after the checks below.
trade:proposeThe same calls, but each order becomes a proposal; nothing reaches the broker until you confirm it.

A call outside the key's scopes answers 403 insufficient_scope. MCP tools follow the same scopes: an agent with a read-only key does not even see the trading tools.

Limits

Every key carries limits. The server checks them before anything reaches the broker, whatever your program or an AI agent sends. You set them when you create the key; GET /me shows them.

LimitDemo defaultLive defaultYou can setRefusal
max_volume_per_order1.00 lot0.10 lotUp to 100 lots422 volume_limit_exceeded
max_open_positions20101–200 (positions and pending orders together)422 position_limit_exceeded
orders_per_minute30101–120 (opens, closes, cancels)429 order_rate_limited
modifications_per_minute60301–240 (stop, target, price and expiry changes)429 modification_rate_limited
daily_loss_limit10% of the day's starting equity2%A percentage, an amount in the account currency, or none403 daily_loss_limit_reached
symbolsAll instrumentsAll instrumentsAn allow-list of up to 100403 symbol_not_allowed
ip_allowlistNone (recommended: set it)None (recommended: set it)Up to 20 IP addresses or CIDR ranges; see Keeping your key safe403 ip_not_allowed
confirm_modeOffOnOn: every order becomes a proposal—
mcp_enabledOnOnOff: the key cannot be used by MCP clients403 insufficient_scope

Daily loss stop

The baseline is the account's equity at the first reading of each broker day with money in it; the day starts at midnight Europe/Athens. While the account is empty there is no baseline, so a percentage stop starts once money is in. Once the day's loss reaches the limit, new positions are refused until the next broker day. Closing and reducing positions always works, and nothing is closed for you.

The stop reads the account's equity, so money moved out of the account during the day counts as a loss, and money moved in offsets one.

Trading halts

JAFX can pause API trading for everyone, for one account or for one key, either fully or for new risk only (closing still allowed). While a halt applies, refused calls answer 423 trading_halted, and GET /me shows it under trading:

JSON
{ "trading": { "mode": "close_only", "level": "global", "reason": "Market event" } }

mode is on, close_only or off. level says where the setting comes from: env (the service default), global, account or key.

Proposals (confirm mode)

With a Proposals key, or any key with confirm_mode on, order calls do not reach the broker. They create a proposal and answer 202:

JSON
{
  "request_id": "01JQ8ZB0Y4D2PQ7RS1VW3XHN6E",
  "kind": "market",
  "status": "awaiting_confirmation",
  "proposal_id": "01JQ8ZB0Y4D2PQ7RS1VW3XHN6E",
  "summary": "BUY 0.01 EURUSD market",
  "expires_at": "2026-10-13T09:50:00.000Z",
  "note": "Nothing was sent to the broker. The account owner must confirm this proposal in the JAFX web terminal (Developers → Proposals)."
}
  • You confirm or reject it in the web terminal under Developers → Proposals. Unconfirmed proposals expire after 10 minutes.
  • Proposals pass every check (limits, daily loss, halts) when they are created, and again at the moment a confirmed one executes. From there it follows the normal order path.
  • Your program can follow it with GET /accounts/{account}/proposals or GET /accounts/{account}/requests/{request_id}, and an AI assistant with the MCP tool list_proposals. How each one ended (confirmed and what its order did, rejected, or expired) is also a notification, so the assistant hears it the next time it connects.

Proposals are the recommended setup for AI agents that suggest trades: the agent does the analysis, you keep the last word.

Rolling, revoking and expiry

  • Roll a key in the terminal to get a new secret with the same settings. The old secret keeps working for 24 hours so you can update your program without downtime.
  • Revoke a key and it stops working within 5 seconds. Its open streams close with code 4401.
  • Expiry: GET /me shows expires_at. After that, requests answer 401 api_key_expired.

Activity: what your keys did

JAFX keeps a log of every call each of your keys makes, so you can see what your bots and AI assistants did on your account and find what went wrong. It is under Activity on the Developers page: the latest 100 calls, or one key's, each with its time, key, what it was and how it ended. An AI assistant connected over MCP reads the same list with get_activity.

  • What is logged: every REST call, every stream connection and every MCP tool call (and each time an MCP client connects), whether it worked or was refused: what was called, how it came (REST, the stream, or MCP with the client's name for itself), when, how long it took, and how it ended (OK, an order's status such as filled or waiting for your confirmation, or why it was refused). Calls refused because of the key itself count too: a revoked, expired or suspended key, or one used from an IP address it isn't locked to.
  • What it never holds: prices and stop levels, an order's comment and client_tag, search words, request bodies, IP addresses, and the key itself. A row's summary holds only the instrument, side, volume, ticket and which fields a change sets, such as BUY 0.01 EURUSD market, SL and TP. Calls with a wrong or unknown key aren't in it: they belong to no account.
  • Repeats share a row: the same read, or the same refusal, by one key within a quarter of an hour is one row with how many times it happened, from the first to the last. Each order request, and each stop of API trading, has a row of its own, with its request id and ticket.
  • How long: each row is kept for 180 days after its last call, then deleted.

Keeping your key safe

Anyone who gets a key can use it as you, within its limits, at any hour: a person, a program, or an AI assistant you paste it into, which a web page or document it reads can talk into placing trades. The Developers page says so when you create a key that can trade or propose.

  • Lock it to your bot's IP addresses. Under Only allow these IP addresses, enter your bot's server address (up to 20 addresses or CIDR ranges). A locked key answers 403 ip_not_allowed from anywhere else, even if it leaks. Leaving a trading or proposals key open to any IP address takes a tick, Let this key be used from any IP address. The lock is set when the key is created; the key list shows each key's lock.
  • Proposals keys for AI assistants in the cloud. Hosted assistants and their connectors (ChatGPT, Claude and the like) call from their provider's servers, whose addresses change, so an IP lock can't hold them. Give them a Proposals key: every order waits for your OK in the terminal.
  • Never share a key. Not in a chat, a website, a screenshot or code you share. Read it from an environment variable or a secret manager, never commit it, and keep it out of logs.
  • Server-side only. Never ship a key in a web page, a browser extension or a mobile app. The API does not accept cross-origin browser requests.
  • One key per program. Then you can see which program did what under Activity, and revoke one without stopping the others.
  • Least privilege. A dashboard needs a read-only key. An AI agent that suggests trades needs a proposals key.
  • Revoke at once if a key may have leaked, then create a new one.
  • JAFX never asks for your password or your API key by email, chat or phone.

Repeated invalid keys from one IP address are blocked for 10 minutes after 10 failures in a minute.

Automated and AI-driven trading can lose money quickly; nothing in these docs is investment advice.

JAFX (PTY) LTD · FSCA FSP No. 52058 · Trading leveraged derivatives with JAFX carries a high risk of losing money rapidly. It is not suitable for everyone.