{"openapi":"3.1.0","info":{"title":"5MTrader API","version":"1.0.0","description":"Everything you can do in the 5MTrader dashboard, available over HTTP with a personal API token. Scope your token to the minimum it needs: a token is a bearer credential and anyone holding it acts as you. Tokens themselves are deliberately not manageable here — creating, rotating and revoking them happens in the dashboard, so a leaked token cannot mint another one."},"servers":[{"url":"https://5mtrader.com/api"}],"tags":[{"name":"me"},{"name":"accounts"},{"name":"orders"},{"name":"positions"},{"name":"symbols"},{"name":"templates"},{"name":"risk"},{"name":"alerts"},{"name":"stream"},{"name":"history"},{"name":"stats"},{"name":"share"},{"name":"news"},{"name":"billing"},{"name":"affiliate"},{"name":"ai"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A personal API token, created in the dashboard under API & MCP. Send it as `Authorization: Bearer 5mt_…`."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}},"required":["error","message"]}},"responses":{"Error":{"description":"Something went wrong","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"security":[{"bearerAuth":[]}],"x-scopes":["read","accounts:write","copy:toggle","trade:execute","risk:write","risk:execute","alerts:read","alerts:write","history:sync","ai","profile:write","share:write","billing:write"],"paths":{"/v1/me":{"get":{"operationId":"me.get","summary":"Who this token belongs to","description":"Profile, plan, and the scopes and live rate-limit budget of the token making the call. The cheapest way to check that credentials work.","tags":["me"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/me/scopes":{"get":{"operationId":"me.scopes","summary":"Every scope this API defines","description":"The full permission vocabulary, and which of them the calling token holds. Useful for telling a user why a call was refused.","tags":["me"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/me/usage":{"get":{"operationId":"me.usage","summary":"Your API call log","description":"Every call made with any of your tokens, newest first, plus the counts behind your quotas. Request and response payloads are recorded with passwords, secrets and tokens already redacted, and oversized bodies stored as a preview.","tags":["me"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"How many events to return, newest first."},"description":"How many events to return, newest first."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":2147483647,"default":0,"description":"Events to skip, for paging further back."},"description":"Events to skip, for paging further back."},{"name":"include_payloads","in":"query","required":false,"schema":{"type":"boolean","default":false,"description":"Attach the redacted request and response of each call."},"description":"Attach the redacted request and response of each call."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/me/preferences":{"patch":{"operationId":"me.preferences.update","summary":"Update account preferences","description":"Locale, time zone, theme and economic-calendar filters. Changing the time zone re-pushes risk configuration to every connected account, because risk windows and day boundaries are resolved against it.","tags":["me"],"security":[{"bearerAuth":["profile:write"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"locale":{"type":"string","enum":["en","es","pt-BR","ru","zh-CN","ja","ar"],"description":"Interface language."},"timezone":{"type":"string","nullable":true,"description":"IANA time zone, or null to follow the browser."},"theme":{"type":"string","enum":["light","dark","system"],"description":"Dashboard colour scheme."},"news_filters":{"type":"object","additionalProperties":{},"nullable":true,"description":"Economic-calendar filter object, or null to clear."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts":{"get":{"operationId":"accounts.list","summary":"List your trading accounts","description":"Every account linked to your user, with its copy role, connection status and copier configuration. Broker credentials are never returned. \"enabled\" is the switch you set; whether copies are actually flowing is \"bridgeCopyEnabled\" plus the riskBlocked fields, which report what the copier server is enforcing right now.","tags":["accounts"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"accounts.create","summary":"Connect a new trading account","description":"Links an MT5 account and provisions it on a copier server. The broker password travels in the request body: send it over HTTPS only, and never log it. Subject to your plan's account limit. cTrader has no password — link those through accounts.ctrader.authorize instead. Counts against the hourly heavy-operation budget.","tags":["accounts"],"security":[{"bearerAuth":["accounts:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","minLength":1,"description":"Broker login number of the account to connect."},"server":{"type":"string","minLength":1,"description":"Broker server name, exactly as MT5 shows it. Resolve it with accounts.brokerServers."},"password":{"type":"string","minLength":1,"description":"Broker account password."}},"required":["account_id","server","password"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}":{"get":{"operationId":"accounts.get","summary":"Get one trading account","description":"","tags":["accounts"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"accounts.update","summary":"Update copier configuration","description":"Changes role, master link, lot sizing and symbol handling. Only the fields you send are touched, and the new configuration is pushed to the copier server in the background. Refused with 423 while the account is under a risk lockout.","tags":["accounts"],"security":[{"bearerAuth":["accounts:write"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["master","slave","pending"],"description":"Copy role. A master is followed; a slave follows."},"master_account_id":{"type":"string","nullable":true,"description":"Account this one follows. Null unlinks it."},"disconnect_from_master":{"type":"boolean","description":"Shorthand for clearing the master link."},"lot_type":{"type":"string","nullable":true,"description":"Lot sizing strategy, e.g. multiplier or fixed."},"lot_multiplier":{"type":"number","minimum":0.0001,"description":"Factor applied to the master's volume, e.g. 0.5 copies half."},"fixed_lot":{"type":"number","minimum":0,"description":"Always trade this volume, whatever the master traded."},"reverse_trading":{"type":"boolean","description":"Mirror trades in the opposite direction."},"exact_match":{"type":"boolean","description":"Copy only when the symbol name matches exactly, instead of resolving it through prefix, suffix and translations."},"no_trade_tag":{"type":"boolean","description":"Leave the copier's identifying tag off the orders it places."},"prefix":{"type":"string","nullable":true,"description":"Prepended to the master's symbol before trading it here, e.g. `m.` for `m.EURUSD`."},"suffix":{"type":"string","nullable":true,"description":"Appended to the master's symbol, e.g. `.pro` for `EURUSD.pro`."},"symbol_translations":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Explicit renames for symbols the affixes cannot resolve, each written `FROM:TO`, e.g. `GOLD:XAUUSD`."},"symbol_filter_mode":{"type":"string","enum":["off","allow","block"],"description":"How to read symbol_filter_list: `allow` copies only what is listed, `block` copies everything except it, `off` ignores it."},"symbol_filter_list":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Symbols the filter applies to, as the master names them."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"accounts.delete","summary":"Disconnect and delete an account","description":"Removes the account from its copier server and deletes it here. Slaves following it are unlinked. Irreversible — pass confirm with the account id. Counts against the hourly heavy-operation budget. Destructive: this changes real positions, data or billing.","tags":["accounts"],"security":[{"bearerAuth":["accounts:write"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"confirm","in":"query","required":true,"schema":{"type":"string","description":"Must equal the account key (platform~server~login), as an explicit acknowledgement."},"description":"Must equal the account key (platform~server~login), as an explicit acknowledgement."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/broker-servers":{"get":{"operationId":"accounts.brokerServers","summary":"Search broker server names","description":"Looks up MT5 server names in the broker catalogue, ranked by how well they match. Connecting an account needs the name spelled exactly as the terminal spells it, so resolve it here first.","tags":["accounts"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"search","in":"query","required":true,"schema":{"type":"string","minLength":2,"description":"Part of the broker or server name, at least two characters."},"description":"Part of the broker or server name, at least two characters."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/ctrader/authorize":{"post":{"operationId":"accounts.ctrader.authorize","summary":"Start the cTrader authorization flow","description":"cTrader accounts are linked by OAuth, not by password, so there is nothing to post to accounts.create. Send the returned URL to the account owner, let them grant access, then hand the `code` from the redirect to accounts.ctrader.link. The state value is returned for you to check against the redirect yourself — this endpoint keeps no session.","tags":["accounts"],"security":[{"bearerAuth":["accounts:write"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","minLength":8,"maxLength":128,"description":"Your own CSRF value, echoed back on the redirect. Generated for you if omitted."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/ctrader/link":{"post":{"operationId":"accounts.ctrader.link","summary":"Link cTrader accounts from an authorization code","description":"Exchanges the code for tokens and connects every trading account behind that cTrader login — one grant can produce several accounts. Accounts already linked are re-synced with the fresh tokens instead of being duplicated, and accounts beyond your plan's limit are skipped rather than failing the call. Codes are single-use. Counts against the hourly heavy-operation budget.","tags":["accounts"],"security":[{"bearerAuth":["accounts:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":1,"description":"Authorization code from the cTrader redirect."},"redirect_uri":{"type":"string","format":"uri","description":"Only if you sent a non-default redirect_uri to the authorize step."}},"required":["code"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/ctrader/refresh":{"post":{"operationId":"accounts.ctrader.refresh","summary":"Refresh cTrader access tokens","description":"Renews the OAuth tokens of your cTrader accounts and pushes them to the copier servers. This normally runs on a schedule; call it when an account reports that re-authorization is required. If the refresh token itself is dead the account stays flagged and you have to run the authorize flow again. Counts against the hourly heavy-operation budget.","tags":["accounts"],"security":[{"bearerAuth":["accounts:write"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","default":false,"description":"Refresh every cTrader account, not only those near expiry."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/reconnect":{"post":{"operationId":"accounts.reconnect","summary":"Reconnect an account with a fresh password","description":"Re-establishes the broker session, moving the account to a healthy server if needed. Use after a password change or a stuck session. MT5 only — a cTrader account is repaired with accounts.ctrader.refresh, or by running the authorize flow again. Counts against the hourly heavy-operation budget.","tags":["accounts"],"security":[{"bearerAuth":["accounts:write"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","minLength":1,"description":"Current broker account password."}},"required":["password"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/copy":{"post":{"operationId":"accounts.setCopy","summary":"Start or stop copy trading","description":"Turns copying on or off for one account. Disabling a master also disables the slaves that follow it. Refused with 423 while the account is under a risk lockout.","tags":["accounts"],"security":[{"bearerAuth":["copy:toggle"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"True starts copying, false stops it."}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/positions":{"get":{"operationId":"accounts.positions","summary":"Live positions, equity and open P&L","description":"A point-in-time snapshot straight off the copier servers: balance, equity, floating P&L, open positions and pending orders for every connected account. Every open position carries ticket, symbol, volume, profit and side — side is exactly \"buy\" or \"sell\", so filter on it per ticket when acting only on one direction. This is the polling equivalent of the dashboard's live stream.","tags":["accounts"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"account_key","in":"query","required":false,"schema":{"type":"string","minLength":1,"description":"Restrict the snapshot to a single account, as the platform~server~login key from accounts.list."},"description":"Restrict the snapshot to a single account, as the platform~server~login key from accounts.list."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/orders":{"post":{"operationId":"orders.create","summary":"Open a market order or place a pending order","description":"Places an order on the account. client_order_id is mandatory: if the connection drops after the broker accepted, retrying with the same id returns the original ticket (duplicate: true) instead of doubling the position. On a master account the order is copied to its followers by default; pass copy: false to keep it out of the copy stream. Every order passes the account's risk rules first — a blocked order returns 423 with the rule that refused it. Destructive: this changes real positions, data or billing.","tags":["orders"],"security":[{"bearerAuth":["trade:execute"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client_order_id":{"type":"string","description":"Your unique id for this order (8-48 chars: letters, digits, dot, dash, underscore). Retries with the same id are safe."},"symbol":{"type":"string","minLength":1,"maxLength":32,"description":"Instrument, in the broker's naming."},"side":{"type":"string","enum":["buy","sell"]},"volume":{"type":"number","minimum":0,"description":"Lots (or contracts on futures rails)."},"order_type":{"type":"string","enum":["market","limit","stop"],"default":"market","description":"market executes now; limit and stop wait at price."},"price":{"type":"number","minimum":0,"description":"Entry price. Required for limit and stop orders."},"sl":{"type":"number","minimum":0,"description":"Stop loss price."},"tp":{"type":"number","minimum":0,"description":"Take profit price."},"copy":{"type":"boolean","default":true,"description":"Master accounts only: false keeps this order out of the copy stream."}},"required":["client_order_id","symbol","side","volume"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"get":{"operationId":"orders.list","summary":"Pending orders on one account","description":"Limit and stop orders that have not executed yet, served from the trading server's 1s snapshot cache — the broker is never queried on this path.","tags":["orders"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/orders/{orderId}":{"get":{"operationId":"orders.get","summary":"One pending order","description":"","tags":["orders"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"orderId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The broker ticket of the order or position."},"description":"The broker ticket of the order or position."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"orders.modify","summary":"Modify a pending order's price, SL or TP","description":"","tags":["orders"],"security":[{"bearerAuth":["trade:execute"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"orderId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The broker ticket of the order or position."},"description":"The broker ticket of the order or position."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"price":{"type":"number","minimum":0,"description":"New entry price."},"sl":{"type":"number","minimum":0,"description":"New stop loss. 0 clears it."},"tp":{"type":"number","minimum":0,"description":"New take profit. 0 clears it."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"orders.cancel","summary":"Cancel a pending order","description":"","tags":["orders"],"security":[{"bearerAuth":["trade:execute"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"orderId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The broker ticket of the order or position."},"description":"The broker ticket of the order or position."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/state":{"get":{"operationId":"accounts.state","summary":"Live balance, equity and floating P&L of one account","description":"A lightweight live read of the account's money state — balance, equity, floating P&L and how many positions and pending orders are open — served from the trading server's 1s snapshot cache without the full position payload. Poll this between orders instead of GET /positions when you only need the numbers.","tags":["accounts"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/positions":{"get":{"operationId":"positions.list","summary":"Open market positions on one account","description":"Open positions with floating P&L, served from the trading server's snapshot cache. For a fleet-wide snapshot use GET /positions.","tags":["positions"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/positions/{positionId}":{"get":{"operationId":"positions.get","summary":"One open position","description":"A single open position by ticket, served from the trading server's snapshot cache — the broker is never queried on this path.","tags":["positions"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"positionId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The broker ticket of the order or position."},"description":"The broker ticket of the order or position."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"positions.modify","summary":"Modify a position's SL or TP","description":"","tags":["positions"],"security":[{"bearerAuth":["trade:execute"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"positionId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The broker ticket of the order or position."},"description":"The broker ticket of the order or position."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"sl":{"type":"number","minimum":0,"description":"New stop loss. 0 clears it."},"tp":{"type":"number","minimum":0,"description":"New take profit. 0 clears it."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"positions.close","summary":"Close a position, fully or partially","description":"Closes the position at market. Pass volume to close only part of it. To flatten the whole account in one call use POST /risk/flatten (risk:execute).","tags":["positions"],"security":[{"bearerAuth":["trade:execute"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"positionId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"description":"The broker ticket of the order or position."},"description":"The broker ticket of the order or position."},{"name":"volume","in":"query","required":false,"schema":{"type":"number","minimum":0,"description":"Partial close volume in lots; omit to close the whole position."},"description":"Partial close volume in lots; omit to close the whole position."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/positions/close-all":{"post":{"operationId":"positions.closeAll","summary":"Close every open position on the account","description":"Flattens the account: closes all open positions and cancels all pending orders at market, in one call. Returns how many tickets were requested, closed and refused. For flattening several accounts at once with an audit trail use POST /risk/flatten (risk:execute). Destructive: this changes real positions, data or billing.","tags":["positions"],"security":[{"bearerAuth":["trade:execute"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/accounts/{accountKey}/symbols/{symbol}":{"get":{"operationId":"symbols.get","summary":"Volume limits for a symbol on this account","description":"Minimum, maximum and step of the tradable volume, straight from the broker's symbol spec. Validate against this before sending orders to avoid 400s.","tags":["symbols"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"accountKey","in":"path","required":true,"schema":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account."},{"name":"symbol","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":32}}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/history":{"get":{"operationId":"history.deals","summary":"Closed trades","description":"Paginated trade history across your accounts, read from the stored history rather than the broker. Call history.sync first if you need it fresher than the last sync.","tags":["history"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"account_keys","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated account keys (platform~server~login, from the \"key\" field of accounts.list). Defaults to all of yours."},"description":"Comma-separated account keys (platform~server~login, from the \"key\" field of accounts.list). Defaults to all of yours."},{"name":"from","in":"query","required":false,"schema":{"type":"integer","description":"Start of range, unix milliseconds."},"description":"Start of range, unix milliseconds."},{"name":"to","in":"query","required":false,"schema":{"type":"integer","description":"End of range, unix milliseconds."},"description":"End of range, unix milliseconds."},{"name":"symbols","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated symbols, as the broker names them. Matched case-insensitively."},"description":"Comma-separated symbols, as the broker names them. Matched case-insensitively."},{"name":"ticket","in":"query","required":false,"schema":{"type":"string","description":"Return the single trade carrying this broker ticket."},"description":"Return the single trade carrying this broker ticket."},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":2147483647,"default":1,"description":"1-based page number."},"description":"1-based page number."},{"name":"page_size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100,"description":"Trades per page. The response carries the total to page through."},"description":"Trades per page. The response carries the total to page through."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["time","symbol","profit","volume"],"default":"time","description":"Column to order by. `time` is the close time."},"description":"Column to order by. `time` is the close time."},{"name":"dir","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc","description":"Order direction. The default puts the newest trade first."},"description":"Order direction. The default puts the newest trade first."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/history/sync":{"post":{"operationId":"history.sync","summary":"Pull fresh history from the brokers","description":"Asks every connected account's bridge for trades it has not stored yet. This talks to remote servers and is charged against the hourly heavy-operation budget. Counts against the hourly heavy-operation budget.","tags":["history"],"security":[{"bearerAuth":["history:sync"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"account_keys":{"type":"string","description":"Comma-separated account keys (platform~server~login, from the \"key\" field of accounts.list). Defaults to all of yours."},"force":{"type":"boolean","default":false,"description":"Ignore the per-account sync throttle."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/stats":{"get":{"operationId":"stats.get","summary":"Performance statistics","description":"Pre-aggregated performance across your accounts: totals, win rate, profit factor, best and worst symbols, and a daily P&L series. Buckets are UTC days, and from/to are snapped to the UTC day they fall in. A filtered range is rebuilt from those daily buckets, where `tradesWithTp` is not stored and reads 0.","tags":["stats"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"account_keys","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated account keys (platform~server~login, from the \"key\" field of accounts.list). Defaults to all of yours."},"description":"Comma-separated account keys (platform~server~login, from the \"key\" field of accounts.list). Defaults to all of yours."},{"name":"from","in":"query","required":false,"schema":{"type":"integer","description":"Start of range, unix milliseconds. Snapped to its UTC day."},"description":"Start of range, unix milliseconds. Snapped to its UTC day."},{"name":"to","in":"query","required":false,"schema":{"type":"integer","description":"End of range, unix milliseconds. Snapped to its UTC day."},"description":"End of range, unix milliseconds. Snapped to its UTC day."},{"name":"symbol_limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"How many symbols to return in each of the best/worst lists."},"description":"How many symbols to return in each of the best/worst lists."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/news/events":{"get":{"operationId":"news.events","summary":"Economic calendar","description":"Scheduled macro events in a time range, with impact, forecast, previous and actual values. The range may not exceed one year.","tags":["news"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"integer","description":"Start of range, unix milliseconds."},"description":"Start of range, unix milliseconds."},{"name":"to","in":"query","required":true,"schema":{"type":"integer","description":"End of range, unix milliseconds."},"description":"End of range, unix milliseconds."},{"name":"impact","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated impact levels to keep: high, medium, low or holiday."},"description":"Comma-separated impact levels to keep: high, medium, low or holiday."},{"name":"currencies","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated currency codes to keep, e.g. `USD,EUR`."},"description":"Comma-separated currency codes to keep, e.g. `USD,EUR`."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/templates":{"get":{"operationId":"templates.list","summary":"List copier templates","description":"","tags":["templates"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"templates.create","summary":"Create a copier template","description":"A reusable bundle of copier settings you can apply to accounts later.","tags":["templates"],"security":[{"bearerAuth":["accounts:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lot_type":{"type":"string","nullable":true,"description":"Lot sizing strategy, e.g. multiplier or fixed."},"lot_multiplier":{"type":"number","description":"Factor applied to the master's volume, e.g. 0.5 copies half."},"fixed_lot":{"type":"number","description":"Always trade this volume, whatever the master traded."},"reverse_trading":{"type":"boolean","description":"Mirror trades in the opposite direction."},"exact_match":{"type":"boolean","description":"Copy only when the symbol name matches exactly, instead of resolving it through prefix, suffix and translations."},"no_trade_tag":{"type":"boolean","description":"Leave the copier's identifying tag off the orders it places."},"prefix":{"type":"string","nullable":true,"description":"Prepended to the master's symbol before trading it here, e.g. `m.` for `m.EURUSD`."},"suffix":{"type":"string","nullable":true,"description":"Appended to the master's symbol, e.g. `.pro` for `EURUSD.pro`."},"symbol_translations":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Explicit renames for symbols the affixes cannot resolve, each written `FROM:TO`, e.g. `GOLD:XAUUSD`."},"symbol_filter_mode":{"type":"string","enum":["off","allow","block"],"description":"How to read symbol_filter_list: `allow` copies only what is listed, `block` copies everything except it, `off` ignores it."},"symbol_filter_list":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Symbols the filter applies to, as the master names them."},"name":{"type":"string","minLength":1,"maxLength":100,"description":"Label for the template."}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/templates/{templateId}":{"put":{"operationId":"templates.update","summary":"Update a copier template","description":"","tags":["templates"],"security":[{"bearerAuth":["accounts:write"]}],"parameters":[{"name":"templateId","in":"path","required":true,"schema":{"type":"string","description":"Numeric template id."},"description":"Numeric template id."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"lot_type":{"type":"string","nullable":true,"description":"Lot sizing strategy, e.g. multiplier or fixed."},"lot_multiplier":{"type":"number","description":"Factor applied to the master's volume, e.g. 0.5 copies half."},"fixed_lot":{"type":"number","description":"Always trade this volume, whatever the master traded."},"reverse_trading":{"type":"boolean","description":"Mirror trades in the opposite direction."},"exact_match":{"type":"boolean","description":"Copy only when the symbol name matches exactly, instead of resolving it through prefix, suffix and translations."},"no_trade_tag":{"type":"boolean","description":"Leave the copier's identifying tag off the orders it places."},"prefix":{"type":"string","nullable":true,"description":"Prepended to the master's symbol before trading it here, e.g. `m.` for `m.EURUSD`."},"suffix":{"type":"string","nullable":true,"description":"Appended to the master's symbol, e.g. `.pro` for `EURUSD.pro`."},"symbol_translations":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Explicit renames for symbols the affixes cannot resolve, each written `FROM:TO`, e.g. `GOLD:XAUUSD`."},"symbol_filter_mode":{"type":"string","enum":["off","allow","block"],"description":"How to read symbol_filter_list: `allow` copies only what is listed, `block` copies everything except it, `off` ignores it."},"symbol_filter_list":{"type":"array","items":{"type":"string"},"nullable":true,"description":"Symbols the filter applies to, as the master names them."},"name":{"type":"string","minLength":1,"maxLength":100,"description":"Label for the template."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"templates.delete","summary":"Delete a copier template","description":"","tags":["templates"],"security":[{"bearerAuth":["accounts:write"]}],"parameters":[{"name":"templateId","in":"path","required":true,"schema":{"type":"string","description":"Numeric template id."},"description":"Numeric template id."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/templates/{templateId}/apply":{"post":{"operationId":"templates.apply","summary":"Apply a copier template to accounts","description":"Copies every setting in the template onto the given accounts and pushes the result to their copier servers. Refused with 423 if any of them is under a risk lockout.","tags":["templates"],"security":[{"bearerAuth":["accounts:write"]}],"parameters":[{"name":"templateId","in":"path","required":true,"schema":{"type":"string","description":"Numeric template id."},"description":"Numeric template id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account_ids":{"type":"array","items":{"type":"string","minLength":1},"description":"Accounts to overwrite with the template's settings."}},"required":["account_ids"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/rules":{"get":{"operationId":"risk.rules.get","summary":"Read the risk rules of an account","description":"","tags":["risk"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"account_key","in":"query","required":true,"schema":{"type":"string","minLength":1,"description":"Account whose rules to read, as the platform~server~login key from accounts.list."},"description":"Account whose rules to read, as the platform~server~login key from accounts.list."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"put":{"operationId":"risk.rules.set","summary":"Replace the risk rules of one or more accounts","description":"The rule list you send becomes the complete rule set for each account — anything omitted is removed. The new configuration is pushed to the copier bridge, which is what actually enforces it.","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account_keys":{"type":"array","items":{"type":"string","minLength":1},"description":"One or more account keys (platform~server~login, as returned in the \"key\" field of accounts.list). Rules are applied to each of them."},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":0,"nullable":true,"description":"Instance id from risk.rules.get. Rules are multi-instance: send the id to update that rule in place (renaming stays renaming); omit it to create a new one."},"type":{"type":"string","enum":["daily_loss","max_drawdown","equity_floor","profit_target","max_positions","max_lot","trading_window","news_window"],"description":"Which limit this rule enforces."},"name":{"type":"string","maxLength":100,"nullable":true,"description":"Optional label to tell instances of the same type apart."},"severity":{"type":"string","enum":["info","warning","critical"],"nullable":true,"description":"Ordering and message tone; purely informational."},"enabled":{"type":"boolean","default":true},"outcomes":{"type":"array","items":{"type":"string","enum":["email","webhook","telegram","discord","block_new","disable_copy","close_all"]},"default":[],"description":"What happens when the rule fires, from notify to close-all."},"params":{"type":"object","additionalProperties":{},"default":{},"description":"Rule-specific settings such as the limit value or the window."}},"required":["type"],"additionalProperties":false},"description":"The complete desired rule set."},"starting_balance":{"type":"number","minimum":0,"maximum":100000000000000,"nullable":true,"description":"The balance drawdown and profit rules measure from. Null clears it back to the automatically captured value; omitted leaves it untouched."},"risk_timezone":{"type":"string","nullable":true,"description":"IANA timezone the trading day is anchored in for these accounts. Null falls back to your profile timezone; omitted leaves it untouched."},"day_start_minutes":{"type":"integer","minimum":0,"maximum":1439,"nullable":true,"description":"Minutes past midnight at which the trading day resets (e.g. 1020 for 17:00). Null or 0 means midnight; omitted leaves it untouched."}},"required":["account_keys","rules"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"risk.rules.clear","summary":"Delete every risk rule of an account","description":"Wipes the rules and pushes a configuration with no risk values, leaving the account exactly as it was before any rule was written.","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"parameters":[{"name":"account_keys","in":"query","required":true,"schema":{"type":"array","items":{"type":"string","minLength":1},"description":"One or more account keys (platform~server~login, as returned in the \"key\" field of accounts.list). Rules are applied to each of them."},"description":"One or more account keys (platform~server~login, as returned in the \"key\" field of accounts.list). Rules are applied to each of them."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/enabled":{"post":{"operationId":"risk.setEnabled","summary":"Master switch for risk enforcement","description":"Turns rule enforcement off or on without deleting the rules. Off pushes a configuration with no risk values; on pushes the whole rule set back out.","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account_keys":{"type":"array","items":{"type":"string","minLength":1},"description":"One or more account keys (platform~server~login, as returned in the \"key\" field of accounts.list). Rules are applied to each of them."},"enabled":{"type":"boolean","description":"True enforces the rules, false suspends them."}},"required":["account_keys","enabled"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/templates":{"get":{"operationId":"risk.templates.list","summary":"List saved risk templates","description":"","tags":["risk"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"risk.templates.create","summary":"Save a risk template","description":"","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Label for the template."},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":0,"nullable":true,"description":"Instance id from risk.rules.get. Rules are multi-instance: send the id to update that rule in place (renaming stays renaming); omit it to create a new one."},"type":{"type":"string","enum":["daily_loss","max_drawdown","equity_floor","profit_target","max_positions","max_lot","trading_window","news_window"],"description":"Which limit this rule enforces."},"name":{"type":"string","maxLength":100,"nullable":true,"description":"Optional label to tell instances of the same type apart."},"severity":{"type":"string","enum":["info","warning","critical"],"nullable":true,"description":"Ordering and message tone; purely informational."},"enabled":{"type":"boolean","default":true},"outcomes":{"type":"array","items":{"type":"string","enum":["email","webhook","telegram","discord","block_new","disable_copy","close_all"]},"default":[],"description":"What happens when the rule fires, from notify to close-all."},"params":{"type":"object","additionalProperties":{},"default":{},"description":"Rule-specific settings such as the limit value or the window."}},"required":["type"],"additionalProperties":false},"default":[],"description":"The rules to store, in the same shape risk.rules.set takes."}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/templates/{templateId}":{"put":{"operationId":"risk.templates.update","summary":"Update a risk template","description":"","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"parameters":[{"name":"templateId","in":"path","required":true,"schema":{"type":"string","description":"Numeric template id."},"description":"Numeric template id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Label for the template."},"rules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":0,"nullable":true,"description":"Instance id from risk.rules.get. Rules are multi-instance: send the id to update that rule in place (renaming stays renaming); omit it to create a new one."},"type":{"type":"string","enum":["daily_loss","max_drawdown","equity_floor","profit_target","max_positions","max_lot","trading_window","news_window"],"description":"Which limit this rule enforces."},"name":{"type":"string","maxLength":100,"nullable":true,"description":"Optional label to tell instances of the same type apart."},"severity":{"type":"string","enum":["info","warning","critical"],"nullable":true,"description":"Ordering and message tone; purely informational."},"enabled":{"type":"boolean","default":true},"outcomes":{"type":"array","items":{"type":"string","enum":["email","webhook","telegram","discord","block_new","disable_copy","close_all"]},"default":[],"description":"What happens when the rule fires, from notify to close-all."},"params":{"type":"object","additionalProperties":{},"default":{},"description":"Rule-specific settings such as the limit value or the window."}},"required":["type"],"additionalProperties":false},"default":[],"description":"Replaces the stored rules entirely."}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"risk.templates.delete","summary":"Delete a risk template","description":"","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"parameters":[{"name":"templateId","in":"path","required":true,"schema":{"type":"string","description":"Numeric template id."},"description":"Numeric template id."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/channels":{"get":{"operationId":"risk.channels.get","summary":"Read your risk notification channels","description":"Secrets are masked: you get whether a channel is configured, not the token behind it.","tags":["risk"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"put":{"operationId":"risk.channels.update","summary":"Configure risk notification channels","description":"Sets where risk alerts are delivered. Send an empty string to clear a channel. Webhook URLs must resolve to a public host.","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"webhook_url":{"type":"string","nullable":true,"description":"Endpoint to POST the alert to as JSON."},"telegram_bot_token":{"type":"string","nullable":true,"description":"Token of the bot that sends the alert, from BotFather."},"telegram_chat_id":{"type":"string","nullable":true,"description":"Chat the bot posts to. Needs the bot token to be set as well."},"discord_webhook_url":{"type":"string","nullable":true,"description":"Discord channel webhook to post the alert to."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/channels/test":{"post":{"operationId":"risk.channels.test","summary":"Send a test alert","description":"Delivers a sample risk alert through the configured channels so you can verify the wiring. Counts against the hourly heavy-operation budget.","tags":["risk"],"security":[{"bearerAuth":["risk:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["webhook","telegram","discord","email"],"description":"Which channel to exercise."}},"required":["channel"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/flatten":{"post":{"operationId":"risk.flatten","summary":"Close every open position on an account","description":"Closes real positions immediately and records the request so it still runs if the bridge is unreachable right now. Masters are closed before their slaves. Irreversible — pass confirm with the account keys joined by commas. Counts against the hourly heavy-operation budget. Destructive: this changes real positions, data or billing.","tags":["risk"],"security":[{"bearerAuth":["risk:execute"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account_keys":{"type":"array","items":{"type":"string","minLength":1},"description":"One or more account keys (platform~server~login, as returned in the \"key\" field of accounts.list). Rules are applied to each of them."},"confirm":{"type":"string","description":"Must equal account_keys joined by commas, as an explicit acknowledgement that real positions are about to be closed."}},"required":["account_keys","confirm"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/risk/lockout":{"post":{"operationId":"risk.lockout","summary":"Lock an account out of trading","description":"Closes open positions, disables copying and refuses further changes until the deadline. Locking a master locks the slaves following it. The deadline is pushed to the bridge, so it survives restarts and server moves, and it cannot be lifted early — pass confirm with the account keys joined by commas. Counts against the hourly heavy-operation budget. Destructive: this changes real positions, data or billing.","tags":["risk"],"security":[{"bearerAuth":["risk:execute"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"account_keys":{"type":"array","items":{"type":"string","minLength":1},"description":"One or more account keys (platform~server~login, as returned in the \"key\" field of accounts.list). Rules are applied to each of them."},"until":{"type":"integer","description":"Unix milliseconds when the lockout expires. Max 30 days out."},"confirm":{"type":"string","description":"Must equal account_keys joined by commas, as an explicit acknowledgement that real positions are about to be closed."}},"required":["account_keys","until","confirm"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/alerts":{"get":{"operationId":"alerts.list","summary":"List your trading alerts","description":"Alerts inform and can never act on an account — that is what risk rules are for. One alert can watch several event types at once; account_key null means it watches all of your accounts.","tags":["alerts"],"security":[{"bearerAuth":["alerts:read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"alerts.create","summary":"Create a trading alert","description":"Types: trade_placed / trade_modified / trade_closed fire on the account's real activity no matter where the trade came from (API, copier, EA or hand); news warns before economic events; copy_health watches for disconnected accounts; behaviour watches your own trading (overtrading, loss streaks, revenge trading). Alerts only notify — they cannot touch the account.","tags":["alerts"],"security":[{"bearerAuth":["alerts:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"string","enum":["trade_placed","trade_modified","trade_closed","news","copy_health","behaviour"]},"description":"Event types this alert watches — one alert can watch several at once."},"account_key":{"type":"string","minLength":1,"description":"Restrict to one account, as the platform~server~login key from accounts.list; omit or null to watch all of them.","nullable":true},"name":{"type":"string","maxLength":100,"nullable":true},"enabled":{"type":"boolean","default":true},"channels":{"type":"array","items":{"type":"string","enum":["email","webhook","telegram","discord"]}},"params":{"type":"object","properties":{"symbols":{"type":"array","items":{"type":"string","minLength":1,"maxLength":32}},"minVolume":{"type":"number","minimum":0},"minChange":{"type":"number","minimum":0},"impacts":{"type":"array","items":{"type":"string","enum":["low","medium","high"]}},"currencies":{"type":"array","items":{"type":"string"}},"minutesBefore":{"type":"integer","minimum":1,"maximum":240},"offlineMinutes":{"type":"integer","minimum":1,"maximum":1440},"detectors":{"type":"array","items":{"type":"string","enum":["overtrading","loss_streak","revenge_trading"]}},"maxTradesPerDay":{"type":"integer","minimum":1,"maximum":500},"lossStreak":{"type":"integer","minimum":2,"maximum":50},"reentryMinutes":{"type":"integer","minimum":1,"maximum":240}},"additionalProperties":false,"description":"Type-specific filters: symbols/minVolume/minChange for trade events, impacts/currencies/minutesBefore for news, offlineMinutes for copier health, detectors and thresholds for behaviour.","default":{}},"cooldown_seconds":{"type":"integer","minimum":0,"maximum":86400}},"required":["types","channels"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/alerts/{alertId}":{"patch":{"operationId":"alerts.update","summary":"Update a trading alert","description":"","tags":["alerts"],"security":[{"bearerAuth":["alerts:write"]}],"parameters":[{"name":"alertId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"maximum":2147483647}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"string","enum":["trade_placed","trade_modified","trade_closed","news","copy_health","behaviour"]}},"account_key":{"type":"string","minLength":1,"description":"The account key, as returned in the \"key\" field of accounts.list: platform~server~(for example \"mt5~ICMarketsSC-Live~12345678\"). The broker login alone is not enough: the same login can exist on two servers, and on two platforms, so all three parts are required to name one account.","nullable":true},"name":{"type":"string","maxLength":100,"nullable":true},"enabled":{"type":"boolean"},"channels":{"type":"array","items":{"type":"string","enum":["email","webhook","telegram","discord"]}},"params":{"type":"object","properties":{"symbols":{"type":"array","items":{"type":"string","minLength":1,"maxLength":32}},"minVolume":{"type":"number","minimum":0},"minChange":{"type":"number","minimum":0},"impacts":{"type":"array","items":{"type":"string","enum":["low","medium","high"]}},"currencies":{"type":"array","items":{"type":"string"}},"minutesBefore":{"type":"integer","minimum":1,"maximum":240},"offlineMinutes":{"type":"integer","minimum":1,"maximum":1440},"detectors":{"type":"array","items":{"type":"string","enum":["overtrading","loss_streak","revenge_trading"]}},"maxTradesPerDay":{"type":"integer","minimum":1,"maximum":500},"lossStreak":{"type":"integer","minimum":2,"maximum":50},"reentryMinutes":{"type":"integer","minimum":1,"maximum":240}},"additionalProperties":false,"description":"Type-specific filters: symbols/minVolume/minChange for trade events, impacts/currencies/minutesBefore for news, offlineMinutes for copier health, detectors and thresholds for behaviour."},"cooldown_seconds":{"type":"integer","minimum":0,"maximum":86400}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"alerts.delete","summary":"Delete a trading alert","description":"","tags":["alerts"],"security":[{"bearerAuth":["alerts:write"]}],"parameters":[{"name":"alertId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"maximum":2147483647}}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/alerts/{alertId}/enabled":{"post":{"operationId":"alerts.setEnabled","summary":"Enable or disable a trading alert","description":"","tags":["alerts"],"security":[{"bearerAuth":["alerts:write"]}],"parameters":[{"name":"alertId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"maximum":2147483647}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/alerts/{alertId}/test":{"post":{"operationId":"alerts.test","summary":"Send a test notification through this alert's channels","description":"Fires a fake event through the alert's configured channels so you can check they are wired up. Counts against the hourly heavy-operation budget.","tags":["alerts"],"security":[{"bearerAuth":["alerts:write"]}],"parameters":[{"name":"alertId","in":"path","required":true,"schema":{"type":"integer","minimum":0,"maximum":2147483647}}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/stream/ticket":{"post":{"operationId":"stream.ticket","summary":"One-time ticket for the live stream","description":"Browsers cannot send Authorization headers on an EventSource, so trade your token for a single-use ticket (30s validity) and open GET /v1/stream?ticket=... with it. Server-side clients can skip this and pass the bearer token directly to /v1/stream.","tags":["stream"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/billing":{"get":{"operationId":"billing.get","summary":"Your subscription and its status","description":"Current plan, tier, seat count, billing period, renewal or expiry date, and whether it is in trial or scheduled to cancel.","tags":["billing"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/billing/plans":{"get":{"operationId":"billing.plans","summary":"Available plans and their price ids","description":"Every purchasable tier with its monthly rate, billing model and the Stripe price ids you pass to billing.changePlan or billing.checkout.","tags":["billing"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/billing/invoices":{"get":{"operationId":"billing.invoices","summary":"Your billing history","description":"Invoices Stripe has issued to you, newest first, with amounts in the currency's minor unit and links to the hosted invoice and its PDF. Empty until you have paid for something.","tags":["billing"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"How many invoices to return, newest first."},"description":"How many invoices to return, newest first."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/billing/plan":{"post":{"operationId":"billing.changePlan","summary":"Change your plan or seat count","description":"Switches an existing subscription to another price and/or quantity, invoicing the proration immediately — this charges the payment method on file, and ends a running free trial there and then. Upgrades take effect at once. Requires an active subscription — use billing.checkout to start one. Pass confirm with the price id. Counts against the hourly heavy-operation budget. Destructive: this changes real positions, data or billing.","tags":["billing"],"security":[{"bearerAuth":["billing:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"price_id":{"type":"string","minLength":1,"description":"Stripe price id from billing.plans."},"confirm":{"type":"string","description":"Must equal price_id, as an explicit acknowledgement that money moves."},"quantity":{"type":"integer","minimum":1,"description":"Seats, for per-account plans."},"region":{"type":"string","description":"Required when moving to a private-server tier from a plan that has no region yet. A subscription that already runs in a region keeps it: the region is fixed until the plan is cancelled and bought again."}},"required":["price_id","confirm"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/billing/checkout":{"post":{"operationId":"billing.checkout","summary":"Start a subscription","description":"Returns a Stripe-hosted checkout URL. Payment details cannot be collected through an API, so open the URL in a browser to finish. Use billing.changePlan if you already subscribe. Counts against the hourly heavy-operation budget.","tags":["billing"],"security":[{"bearerAuth":["billing:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"price_id":{"type":"string","minLength":1,"description":"Stripe price id from billing.plans."},"quantity":{"type":"integer","minimum":1,"description":"Seats to buy on a per-seat plan. Defaults to one."},"region":{"type":"string","description":"Required for private-server tiers. The region is fixed for the life of the subscription."}},"required":["price_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/billing/portal":{"post":{"operationId":"billing.portal","summary":"Open the Stripe billing portal","description":"Returns a short-lived URL where payment methods can be updated and the subscription cancelled.","tags":["billing"],"security":[{"bearerAuth":["billing:write"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"history":{"type":"boolean","default":false,"description":"Open the invoice-history view instead of the management view."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/share":{"post":{"operationId":"share.create","summary":"Create a public performance link","description":"Builds a signed report URL for the accounts and metrics you choose. Anyone holding the link can open it without authenticating, and the link carries its own configuration — there is nothing to revoke, so treat it as public the moment you share it.","tags":["share"],"security":[{"bearerAuth":["share:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"preset":{"type":"string","description":"Time preset for the report, e.g. the last 30 days."},"mode":{"type":"string","enum":["profit","percent"],"default":"profit","description":"Headline figure: money made, or return on the capital you declare."},"account_type":{"type":"string","enum":["all","live","demo"],"default":"all","description":"Restrict the report to real or demo accounts."},"account_keys":{"type":"array","items":{"type":"string"},"default":[],"description":"Account keys (platform~server~login, from accounts.list) to include. Empty means all of yours."},"from_ms":{"type":"integer","nullable":true,"description":"Range start when the preset is a custom one, unix milliseconds."},"to_ms":{"type":"integer","nullable":true,"description":"Range end when the preset is a custom one, unix milliseconds."},"capital":{"type":"number","minimum":0,"default":0,"description":"Capital the percentage is calculated against."},"include_commission":{"type":"boolean","default":false,"description":"Subtract commission from the reported profit."},"include_swap":{"type":"boolean","default":false,"description":"Subtract swap from the reported profit."},"percent_only":{"type":"boolean","default":false,"description":"Hide monetary amounts and publish percentages alone."},"custom_name":{"type":"string","nullable":true,"description":"Title shown on the public page instead of your account name."},"metrics":{"type":"object","properties":{"percent":{"type":"boolean","default":false},"balance":{"type":"boolean","default":false},"accounts":{"type":"boolean","default":false},"trades":{"type":"boolean","default":false},"winRate":{"type":"boolean","default":false},"profitFactor":{"type":"boolean","default":false},"bestTrade":{"type":"boolean","default":false}},"additionalProperties":false,"default":{},"description":"Which figures the public page shows."}},"required":["preset"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/affiliate":{"get":{"operationId":"affiliate.get","summary":"Your affiliate account","description":"Referral code, link and earnings. Returns enrolled: false if you are not in the programme.","tags":["affiliate"],"security":[{"bearerAuth":["read"]}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/affiliate/referrals":{"get":{"operationId":"affiliate.referrals","summary":"People who signed up through your link","description":"Every referral attributed to you, newest first, with whether and when they converted into a paying customer. Referrals are other people: their email is masked and their name is not returned, so you can tell two of them apart without being handed their contact details.","tags":["affiliate"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100,"description":"How many referrals to return, newest first."},"description":"How many referrals to return, newest first."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/affiliate/earnings":{"get":{"operationId":"affiliate.earnings","summary":"Your commissions and payouts","description":"Balance by commission status, the individual commissions behind it and the payouts already made to you. Amounts are in the commission's own currency.","tags":["affiliate"],"security":[{"bearerAuth":["read"]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100,"description":"How many commissions and payouts to return, newest first."},"description":"How many commissions and payouts to return, newest first."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/affiliate/code":{"patch":{"operationId":"affiliate.setCode","summary":"Change your referral code","description":"Codes are unique across all affiliates. Old links stop working immediately.","tags":["affiliate"],"security":[{"bearerAuth":["profile:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":3,"maxLength":40,"description":"New referral code."}},"required":["code"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/ai/chats":{"get":{"operationId":"ai.chats.list","summary":"List assistant conversations","description":"","tags":["ai"],"security":[{"bearerAuth":["ai"]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":30,"description":"How many conversations to return, most recent first."},"description":"How many conversations to return, most recent first."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"ai.chats.create","summary":"Start an assistant conversation","description":"Opens an empty chat in the mode you pick: `support` answers questions about the product, `coach-live` reasons over your connected accounts and `coach-backtest` over your simulated ones. The coach modes need a paid plan and draw on a daily allowance. The title is written for you from the first exchange.","tags":["ai"],"security":[{"bearerAuth":["ai"]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["support","coach-live","coach-backtest"],"default":"support","description":"Assistant mode for the whole conversation."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/ai/chats/{chatId}/messages":{"post":{"operationId":"ai.chats.send","summary":"Send a message and get the reply","description":"Runs one full turn — including any data the assistant looks up on your behalf — and returns the finished answer. There is no streaming here: the call takes as long as the answer takes. The message and the reply are both stored in the conversation. Counts against the hourly heavy-operation budget.","tags":["ai"],"security":[{"bearerAuth":["ai"]}],"parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Chat id."},"description":"Chat id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":2000,"description":"What to say to the assistant."},"locale":{"type":"string","description":"Language for the reply. Defaults to English."}},"required":["message"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/ai/chats/{chatId}/actions/{actionId}":{"post":{"operationId":"ai.chats.decide","summary":"Approve or reject an action the assistant proposed","description":"The assistant never changes anything on its own: it proposes an operation and waits. Approving runs it under the same scopes as this call — so a token without the operation's scope cannot approve it — and returns what it did; rejecting drops it. Either way the decision is recorded in the conversation.","tags":["ai"],"security":[{"bearerAuth":["ai"]}],"parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Chat id."},"description":"Chat id."},{"name":"actionId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Id of the proposed action."},"description":"Id of the proposed action."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["approve","reject"],"description":"Whether to run the proposed operation."}},"required":["decision"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/ai/chats/{chatId}":{"patch":{"operationId":"ai.chats.update","summary":"Rename or pin a conversation","description":"","tags":["ai"],"security":[{"bearerAuth":["ai"]}],"parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Chat id."},"description":"Chat id."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80,"description":"Replaces the title written automatically from the first exchange."},"pinned":{"type":"boolean","description":"Pinned conversations stay on top. At most 3."}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"get":{"operationId":"ai.chats.get","summary":"Read one assistant conversation","description":"","tags":["ai"],"security":[{"bearerAuth":["ai"]}],"parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Chat id."},"description":"Chat id."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"ai.chats.delete","summary":"Delete an assistant conversation","description":"","tags":["ai"],"security":[{"bearerAuth":["ai"]}],"parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"Chat id."},"description":"Chat id."}],"responses":{"200":{"description":"Success"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}}}}