# Tickwire > One API for hosted MetaTrader 4 and 5 terminals, with per-account health checks, idempotent orders, an audit log, webhooks and an MCP server for AI agents. Every Tickwire docs page and the whole API reference, as Markdown. Index: https://tickwire.io/llms.txt. --- # Tickwire docs > Read, stream and trade MetaTrader 4 and 5 accounts over one API, with a health check for each account. Source: https://tickwire.io/docs/ Tickwire runs one real MetaTrader terminal per trading account and puts an API in front of it. MT4 and MT5 accounts look the same from the outside. ## Start here - **[Quickstart](https://tickwire.io/docs/quickstart/)**: your first order in under two minutes in the free [sandbox](https://tickwire.io/docs/sandbox/), then the same calls on your broker account. - **[Authentication](https://tickwire.io/docs/authentication/)**: the header forms we accept and how to scope tokens. - **[Health](https://tickwire.io/docs/health/)**: what `healthy`, `stale`, `disconnected` and `down` mean, and how we measure them. ## Three ways to call Tickwire | Surface | Paths | Use it when | |---|---|---| | `/users/current` REST API | `/users/current/accounts/…`, socket.io streaming | Your code already calls this API style or you want its field names | | `/v1` and terminal routes | `/v1/…`, `/mt4/{id}/…`, `/mt5/{id}/…` | You're moving an integration that uses these routes | | Tickwire extras | `/users/current/accounts/{id}/health`, `/audit`, `/ws`, webhooks | You want per-account health, the audit log or plain WebSocket streaming | All three surfaces reach the same terminals, so you can mix them. The native `/v1` lists are [cursor-paginated](https://tickwire.io/docs/pagination/); the other surfaces keep their existing list shapes. ## By use case - [Prop risk tool](https://tickwire.io/docs/guides/prop-risk-tool/): watch equity and flatten on breach. - [Trade copier](https://tickwire.io/docs/guides/copier/): copy orders to many accounts, with idempotency keys so a retry never fills twice. - [Trading journal](https://tickwire.io/docs/guides/journal/): read-only history sync. - [Trading bot](https://tickwire.io/docs/guides/trading-bot/): stream prices and trade. - [Example projects](https://tickwire.io/docs/guides/examples/): quickstarts, webhook receivers, a pre-trade guard and MCP setup to copy. Sandbox only. ## Early access Tickwire is in early access. Pages about features that aren't available yet say so at the top. --- # Quickstart > Your first call in under two minutes, in the free sandbox. Then connect your broker account and run the same calls. Source: https://tickwire.io/docs/quickstart/ Start in the [sandbox](https://tickwire.io/docs/sandbox/): no card, no broker login, no terminal to wait for. When your code works there, connect a broker account and change only the key and the account id. Demo, small funded or live: it's your choice. The examples use `curl`. ```bash export TW=https://api.tickwire.io ``` ## 1. Get a sandbox key and account ```bash curl -s -X POST "$TW/v1/sandbox/signup" -H "content-type: application/json" -d '{"platform": "mt5"}' ``` ```json { "sandbox": true, "apiKey": "twsk_4b1e…", "account": { "id": "acc_7Qx", "server": "Tickwire-Sandbox", "login": "1000", "state": "DEPLOYED", "connectionStatus": "CONNECTED" } } ``` The key is shown once. Set it, then follow steps 2 to 6 below with `acc_7Qx`: ```bash export TW_KEY=twsk_4b1e… ``` Sandbox answers carry `X-Tickwire-Sandbox: true`. Want to see an order that can't be confirmed, a rejection or a disconnect? Create accounts with the [magic logins](https://tickwire.io/docs/sandbox/#magic-logins). ### Or connect a broker account You need a live Tickwire API key and a broker account (login, password and server name, e.g. `YourBroker-Server`): ```bash export TW_KEY=your-live-api-key ``` ```bash curl -s -X POST "$TW/users/current/accounts" \ -H "auth-token: $TW_KEY" \ -H "transaction-id: $(openssl rand -hex 16)" \ -H "content-type: application/json" \ -d '{ "name": "my account", "platform": "mt5", "server": "YourBroker-Server", "login": "12345678", "password": "your-password", "magic": 1000 }' ``` If broker detection is still running you get **202** with a `Retry-After` header. Send the same request again, with the **same** `transaction-id`, after that many seconds. You end with **201** and the account id: ```json { "id": "acc_7Qx", "state": "DEPLOYING" } ``` If the server name is unknown you get `E_SRV_NOT_FOUND` with suggested names. See [broker onboarding](https://tickwire.io/docs/broker-onboarding/). The password is write-only. We never return it or write it to logs. ## 2. Wait for the account to connect ```bash curl -s "$TW/users/current/accounts/acc_7Qx" -H "auth-token: $TW_KEY" ``` Wait for `"connectionStatus": "CONNECTED"` and `"health": {"status": "healthy", …}`. That means the broker link is up, the account was read, and ticks are moving. Usually this takes under a minute; a sandbox account is ready at once. `stale` means connected but quotes frozen (often a closed market). See [Health](https://tickwire.io/docs/health/). ## 3. Read the account ```bash curl -s "$TW/users/current/accounts/acc_7Qx/account-information" -H "auth-token: $TW_KEY" ``` ```json { "platform": "mt5", "broker": "Your Broker Ltd", "currency": "USD", "balance": 10000, "equity": 10000, "margin": 0, "freeMargin": 10000, "leverage": 500, "tradeAllowed": true, "brokerTime": "2026-09-23 14:02:11.480" } ``` `brokerTime` is the broker's local time. It isn't UTC; see [Time zones](https://tickwire.io/docs/time-zones/). ## 4. Place an order ```bash curl -s -X POST "$TW/users/current/accounts/acc_7Qx/trade" \ -H "auth-token: $TW_KEY" \ -H "Idempotency-Key: first-order-1" \ -H "X-Actor: quickstart" -H "X-Reason: trying Tickwire" \ -H "content-type: application/json" \ -d '{"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.01}' ``` ```json { "numericCode": 10009, "stringCode": "TRADE_RETCODE_DONE", "message": "Request completed", "orderId": "46870472", "positionId": "46870472", "outcome": "applied" } ``` Run the same command again: because the `Idempotency-Key` is the same, you get the same answer and no second position. See [Idempotency](https://tickwire.io/docs/idempotency/). Some brokers suffix symbols (`EURUSDm`). `GET …/symbols` lists the exact names. ## 5. Close it ```bash curl -s -X POST "$TW/users/current/accounts/acc_7Qx/trade" \ -H "auth-token: $TW_KEY" \ -H "Idempotency-Key: first-close-1" \ -H "X-Actor: quickstart" -H "X-Reason: done" \ -H "content-type: application/json" \ -d '{"actionType": "POSITION_CLOSE_ID", "positionId": "46870472"}' ``` ## 6. Watch it live ```bash # websocat, or any WebSocket client websocat "wss://api.tickwire.io/users/current/accounts/acc_7Qx/ws?auth-token=$TW_KEY" {"type":"subscribe","marketData":[{"symbol":"EURUSD","subscriptions":[{"type":"quotes"}]}]} ``` You get a full sync, then `prices` and `health` frames. See [Streaming](https://tickwire.io/docs/streaming/). ## Next - Coming from another provider? [Change the base URL and key](https://tickwire.io/docs/switching/) and keep your requests. - Get told about problems: [webhooks](https://tickwire.io/docs/webhooks/). - Start from working code: [example projects](https://tickwire.io/docs/guides/examples/). --- # Sandbox > Free simulated MT4 and MT5 accounts. No card, no broker login, no terminal boot. Your first call in under two minutes. Source: https://tickwire.io/docs/sandbox/ The sandbox gives you MT4 and MT5 accounts that answer the real API but run on a simulated terminal. You don't need a card, a broker login or a subscription, and you don't wait for a terminal to start. Everything you build against the sandbox works unchanged on a live account. - **Free.** Sandbox usage is never billed and never counts as a seat. - **Separate.** Sandbox keys start with `twsk_`. A sandbox key can't see or touch a live account, and a live key can't see or touch a sandbox one. - **Marked.** Every data response from a sandbox account carries the header `X-Tickwire-Sandbox: true`, and sandbox accounts show `"sandbox": true`. - **Limited.** Up to 5 accounts per sandbox, and 10 requests per second per account (bursts of 20). Over the limit you get `429 rate_limited` with `Retry-After`. A sandbox also holds up to 5 active sandbox keys and 20 each of API tokens, read-only keys and agent keys. Anonymous sign-up allows 5 sandboxes an hour and 10 a day from one address. - **Kept while you use it.** A sandbox from anonymous sign-up is deleted, with its keys and accounts, after 7 days without an API call. Sandboxes you get from a live key or the dashboard stay as long as your account does. - **Simulated state.** Balances, positions and orders live in memory. They reset when you redeploy the account, and may reset after a week of inactivity or a sandbox restart. ## Your first call in two minutes ```bash export TW=https://api.tickwire.io # 1. Get a sandbox key and a connected MT5 account (no sign-in needed) curl -s -X POST "$TW/v1/sandbox/signup" -H "content-type: application/json" -d '{"platform": "mt5"}' ``` ```json { "sandbox": true, "tenantId": "9f3c…", "apiKey": "twsk_4b1e…", "account": { "id": "acc_7Qx", "platform": "mt5", "server": "Tickwire-Sandbox", "login": "1000", "state": "DEPLOYED", "connectionStatus": "CONNECTED" } } ``` The key is shown once. Keep it: ```bash export TW_KEY=twsk_4b1e… export ACC=acc_7Qx # 2. Read the account curl -s "$TW/users/current/accounts/$ACC/account-information" -H "auth-token: $TW_KEY" # 3. Buy 0.01 EURUSD curl -s -X POST "$TW/users/current/accounts/$ACC/trade" \ -H "auth-token: $TW_KEY" -H "Idempotency-Key: first-order-1" \ -H "content-type: application/json" \ -d '{"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.01}' # 4. See the position curl -s "$TW/users/current/accounts/$ACC/positions" -H "auth-token: $TW_KEY" ``` The trade answers `"outcome": "applied"` with `numericCode` 10009. Send step 3 again with the same `Idempotency-Key` and you get the same answer and no second position. The sandbox quotes `EURUSD`, `GBPUSD`, `USDJPY` and `XAUUSD`. Prices move a little every second. A key from anonymous sign-up is limited to your sandbox accounts, trading, streaming and reads. It can't create webhooks, pre-trade hooks, agent keys or more keys, and it can't create, change or delete risk-management trackers or guard rules (it can still read trackers, statistics and metrics). For those, sign in and get a sandbox key from your live key; it has full rights inside your sandbox: ```bash curl -s -X POST "$TW/v1/sandbox/keys" -H "X-API-Key: $YOUR_LIVE_KEY" ``` ## Add more sandbox accounts Use the ordinary account API with your `twsk_` key, server `Tickwire-Sandbox`, and a **magic login** from the table below. Any password works. ```bash curl -s -X POST "$TW/users/current/accounts" \ -H "auth-token: $TW_KEY" -H "content-type: application/json" \ -d '{"name": "lost reply", "platform": "mt5", "server": "Tickwire-Sandbox", "login": "1031", "password": "anything"}' ``` The account is deployed at once. Its `connectionStatus` comes from the simulated terminal's own health check, the same rule as a live account: `CONNECTED` only when that check says so. ## Magic logins Like test card numbers, each login makes the sandbox simulate one condition, every time. They work on `mt5` and `mt4`. Any other login behaves like `1000`. | Login | What happens | What you should see | |---|---|---| | `1000` | Normal account | Connects, quotes move, orders fill: `outcome` `applied` | | `1031` | Lost reply ending **applied**: the reply to every order is lost, but the broker executed it | `outcome` `applied`, `numericCode` 10009. The terminal reported no connection, but Tickwire found the fill, so there's nothing to retry | | `1032` | Lost reply ending **unknown**: the reply to new orders is lost and no fill appears | After about 3 s, `outcome` `unknown`, `numericCode` -11. Check positions before you retry. Closes and modifies work normally | | `1019` | Rejection: no money | `outcome` `rejected`, `numericCode` 10019. Nothing happened | | `1006` | Rejection: request rejected | `outcome` `rejected`, `numericCode` 10006 | | `1040` | Disconnect and reconnect | Connected for 60 s, then the broker link drops for 30 s, then it comes back; repeats every 90 s. While it's down, reads answer `503` and trades answer `numericCode` -10 (nothing sent); health says `disconnected`, then `healthy` again | | `1050` | Stale quotes | Connected, but prices never move. After 30 s health says `stale` | | `1060` | OTP required | The account never connects: it ends `DEPLOY_FAILED` with error `ERR_OTP_REQUIRED`. Its health answers `200` with `status` `down` and `reason_code` `ERR_OTP_REQUIRED` (see [Health](https://tickwire.io/docs/health/)) | | `1061` | Login required: wrong login or password | Ends `DEPLOY_FAILED` with error `E_AUTH`. Health is `down` with `reason_code` `E_AUTH` | | `1080` | Slow fills | Every order takes 3 s, then fills | MT4 accounts (`"platform": "mt4"`) behave as MT4 does. Market depth (`…/symbols/{symbol}/current-book`) and tick history (`…/historical-market-data/…/ticks`) answer with the error `not_supported_on_mt4`. Try it with any login. ## Moving to live 1. Create a live key on the dashboard, and connect a broker account (see the [Quickstart](https://tickwire.io/docs/quickstart/)). 2. Swap `twsk_…` for the live key and `Tickwire-Sandbox` for your broker's server. Nothing else changes: same paths, same fields, same outcomes. Sandbox accounts stay in the sandbox; they're never moved to or mixed with live ones. ## Errors you may see | Status | `error` / `code` | Meaning | |---|---|---| | 400 | `sandbox_key_required` | You used server `Tickwire-Sandbox` with a live key | | 400 | `sandbox_server_required` | You used a sandbox key with a real broker server | | 403 | `sandbox_account_limit` | Your sandbox already has 5 accounts; delete one | | 403 | `sandbox_key_limit` | Your sandbox already has 5 active keys (or 20 API tokens, read-only keys or agent keys); revoke one on the dashboard | | 403 | `sandbox_key_restricted` | A sign-up key tried something other than accounts, trading or reads (for example a risk-management write) | | 429 | `rate_limited` | Too many requests, or too many sign-ups from your address. Wait for `Retry-After` | --- # CLI > The tickwire command. Sign in, create a sandbox, list accounts, trade (with a reason) and see the result, forward webhooks to localhost, and tail your request log. Source: https://tickwire.io/docs/cli/ `tickwire` is a command-line tool built on the [Python SDK](https://tickwire.io/docs/sdk-python/). It works the same for MT4 and MT5 accounts. Every command accepts `--json`, which prints machine-readable output: one JSON object, or one per line for `listen` and `logs tail`. ```sh pip install tickwire-cli # Python 3.11+; "tickwire-cli[keyring]" stores keys in the OS keychain ``` **It isn't on PyPI yet.** We're publishing it as `tickwire-cli`, together with the [Python SDK](https://tickwire.io/docs/sdk-python/); until then, `pip install tickwire-cli` won't find it. If you want to use the CLI before then, [contact us](https://tickwire.io/contact/). ## Two minutes in the sandbox ```sh export TICKWIRE_SANDBOX_URL=https://sandbox.example # your sandbox API URL tickwire sandbox create # a sandbox, one simulated MT5 account, a stored key tickwire --sandbox accounts list tickwire --sandbox trade open --side buy --symbol EURUSD --volume 0.01 --reason "first test" ``` `sandbox create` calls `POST /v1/sandbox/signup` and stores the new `twsk_` key in the `sandbox` profile. The key is not printed unless you pass `--show-key`, because the server shows it only once. A lost reply is reported as `unknown` and is not retried, because a retry could create a second sandbox. This key is **restricted**: it can manage accounts, trade and read. To use webhooks (`listen`, `trigger`), sign in, create a sandbox key from your live key (`POST /v1/sandbox/keys`), and run `tickwire login --sandbox`. ## Global options | Option | Meaning | |---|---| | `--json` | JSON output on stdout. Notes and warnings still go to stderr | | `--sandbox` | Use the sandbox. It selects the `sandbox` profile and `TICKWIRE_SANDBOX_URL` | | `--profile NAME` | Use a named credential profile. The default is `default` (`sandbox` with `--sandbox`) | | `--api-url URL` | API base URL. Otherwise the CLI uses `TICKWIRE_API_URL` or `TICKWIRE_SANDBOX_URL`, then the profile's URL. It must be `https://`; plain `http://` is accepted only for `localhost`, `127.0.0.1` and `[::1]` (a local stack), because the key travels with every request | You can put these options before or after the command. Human output is terminal-safe: control characters in data from the server (escape sequences, carriage returns, newlines inside a value, C1 controls, bidi overrides) are printed visibly as `\xNN` or `\uNNNN`, never passed to your terminal. `--json` output is exact JSON. ## `login` and `logout` ```sh tickwire login --api-url https://api.example # hidden prompt echo "$KEY" | tickwire login --sandbox --key-stdin # from a secret store or CI tickwire logout ``` - The key is **never a command-line argument**, because arguments end up in shell history and the process list. The CLI reads it from a hidden prompt, or from stdin when stdin is not a terminal (or with `--key-stdin`). - The key is **never printed**. Output shows a hint such as `twsk_…a1b2`. - Before storing the key, the CLI checks it against the API with `GET /v1/accounts`. A rejected key is not stored. Pass `--no-verify` to skip the check. - `--sandbox` accepts only `twsk_` keys, and a live profile refuses them, so a sandbox key never ends up in a live profile or the other way round. - **Storage:** the OS keychain (service `tickwire-cli`) when the `keyring` package is installed and working. Otherwise the key goes in `credentials.json` with mode `0600`. The file is written to a fresh temporary file (created exclusively, never through a symlink) and renamed into place. A config directory the CLI creates gets mode `0700`; an existing one is never `chmod`-ed. The CLI refuses a credentials file or config directory that is a symlink or belongs to another user, and a credentials file other users can read (it tells you to `chmod 600` it, as `ssh` does). `--no-keyring` forces the file. - The config directory is `$TICKWIRE_CONFIG_DIR`, else `$XDG_CONFIG_HOME/tickwire`, else `~/.config/tickwire`. `config.json` holds profiles (URL, sandbox flag, key hint) and never the key. - `TICKWIRE_API_KEY` in the environment overrides any stored key, so CI jobs need no login. ## `accounts` ```sh tickwire accounts list tickwire accounts get --health # adds health: status, reasons, checked_at ``` ## `trade` ```sh tickwire trade open --side buy --symbol EURUSD --volume 0.01 [--sl 1.05 --tp 1.10] --reason "breakout" tickwire trade close [--volume 0.5] --reason "take profit" ``` Trades use the guarded pipeline (`POST /v1/execution/accounts/{id}/trade`), so the account's [pre-trade hooks](https://tickwire.io/docs/webhooks/) apply. - `--reason` is **mandatory**. It is sent as `X-Reason` and kept in the audit log. - Every trade carries an **`Idempotency-Key`**. The CLI generates one when you don't pass `--idempotency-key`, and always prints it. - The result is one of: | Outcome | Meaning | Exit code | |---|---|---| | `applied` | The terminal confirmed it (`evidence` shows how) | 0 | | `no_change` | Nothing needed doing, e.g. the position was already closed | 0 | | `rejected` | Not executed. The error code says why | 3 | | `held` | A pre-trade hook holds it for approval. Nothing has executed yet | 4 | | `unknown` | It **may** have executed | 5 | **`unknown` is never retried**, by the SDK or by the CLI. You get `unknown` when the reply is lost (timeout, reset, 502/504) or when the server answers with an error and no outcome (5xx). Check the account's positions first. To try again, run the same command with `--idempotency-key `: the server recognises the key and will not execute the trade twice ([idempotency](https://tickwire.io/docs/idempotency/)). The SDK repeats a request with the same key only when it knows the server didn't process it: no connection, or a 408, 429 or 503. Other exit codes: 1 means the API answered with an error, 2 means a usage or login problem, and 130 means you pressed Ctrl-C. ## `listen`: webhooks on localhost ```sh tickwire login --sandbox # an unrestricted sandbox key tickwire --sandbox listen --forward-to http://localhost:3000/webhooks [--events "trade.*,account.*"] ``` On start, `listen` prints a **listener signing secret** (`whsec_…`). Configure your local handler with it and verify deliveries exactly as in production ([webhooks](https://tickwire.io/docs/webhooks/)): the same `X-Tickwire-Signature`, `X-Tickwire-Timestamp` and Standard Webhooks `webhook-*` headers, and the same body shape. This secret is not your API key and not an endpoint's secret. How it works: 1. `POST /v1/webhook-listeners` creates a listener and returns its secret and a cursor (the current head of your event buffer). The cursor is opaque (`:`). 2. The CLI polls `GET /v1/webhook-listeners/{id}/events?after=` every 2 seconds when idle (`--interval`). The **server signs** each event with the listener secret, at most 100 events per poll. 3. The CLI **verifies** both signatures and the timestamp. If an event fails verification, the CLI does not forward it and stops. 4. It POSTs the exact signed bytes and headers to `--forward-to` and prints the status and latency. A failed forward is reported and not retried. What listen mode doesn't do: - **It is not the delivery queue.** Real endpoints get durable deliveries with retries for 72 hours. A listener only sees events published while it is running. Nothing is stored per listener, and events published while nothing was listening are not replayed. To replay an event, use `POST /v1/events/{id}/resend` on a real endpoint. - **Event ids differ.** In listen mode an event's id is `evl__`, not the id that a real endpoint receives for the same event. Each forwarded request carries `X-Tickwire-Listener: `. - **Your own buffer.** Listeners read only your last 1,000 events, so another account's traffic can't push yours out. - **Gaps get a warning.** If the listener falls behind your event buffer, the server sets `truncated` and the CLI prints a warning. After a server restart the server sets `reset`, sends the new buffer from the start, and the CLI prints a warning. Events from before the restart are not replayed. - **Rate limits**, per account and per minute: 10 listener starts, 90 polls and 10 triggers. Over a limit you get `429 rate_limited` with `Retry-After`. - **Listener secrets are derived, not stored**, so a listener survives server restarts. If the secret ever changes, the CLI stops with a signature error instead of forwarding unverified data. Run `listen` again. Anonymous sandbox keys from `sandbox create` get `403 sandbox_key_restricted`, as they do for every webhook route. ## `trigger`: send a test event ```sh tickwire trigger --list tickwire --sandbox trigger trade.outcome [--account ] tickwire trigger webhook.test # the only type allowed on a live key ``` `POST /v1/webhook-events/trigger` publishes one event with the catalog's example data plus `"test": true`. The event goes to your real webhook endpoints and to running `listen` sessions. A sandbox key can trigger any type in the catalog. A live key can trigger only `webhook.test` (`403 webhook_trigger_sandbox_only`), so a fake trade never reaches a production handler. An unknown type gets `400 unknown_event_type`. The answer carries `eventId`, the id your endpoints receive for the event (`webhook-id`), so a monitor can match a delivery to its trigger. It is `null` when no active endpoint is subscribed to the type, and `noDeliveryReason` says why (`endpoint_disabled` with `disabledReasons`, `not_subscribed` or `no_endpoints`). If webhook delivery cannot queue the event you get `503 webhook_unavailable` (running `listen` sessions still got it). Triggers are idempotent (`--idempotency-key`) and audited. ## `logs tail`: your request log ```sh tickwire logs tail # the 20 most recent calls, oldest first tickwire logs tail --status errors --since 1h -n 100 # failed calls of the last hour tickwire logs tail -f --method POST --path /trade # keep following new calls; Ctrl-C stops tickwire logs tail --status 4xx --bodies # with the redacted bodies of failed calls ``` `logs tail` reads [request logs](https://tickwire.io/docs/request-logs/) (`GET /v1/request-logs`): every authenticated call your organisation's keys made in the last 14 days. Each call is one line (time, method, status, latency, path, error code, `[aborted]` when the answer was cut short, and the request id); with `--json`, one JSON object per line, exactly as the API returned it. | Option | Meaning | |---|---| | `-n`, `--limit N` | How many recent calls to print first (default 20, at most 1,000). With `--follow`, `0` prints only calls made from now on | | `-f`, `--follow` | Keep polling (every 2 seconds, `--interval`) and print new calls as Tickwire records them | | `--since`, `--until` | ISO 8601 times (UTC when no zone is given), or relative: `30s`, `15m`, `2h`, `7d`. `--until` does not combine with `--follow` | | `--status` | `404`, `4xx`, `5xx`, `errors` (400 and above) or `aborted` | | `--method`, `--path`, `--error-code`, `--account`, `--key-id`, `--request-id` | The API's filters. `--path` (or `--route`) matches part of the path or of its template | | `--bodies` | Also fetch `GET /v1/request-logs/{id}` for failed calls and print their redacted `requestBody` and `responseBody` | How it works: - The list is newest first and paginated with an opaque cursor. The CLI passes `nextCursor` back unchanged with the same filters, and prints the page oldest first, as `tail` does. - With `--follow` it polls the first page and walks back until it reaches a call it has already printed, so each call is printed once, including one recorded late. If more than 2,000 calls arrive between two polls, it prints the newest and warns that older ones were skipped. - **Bodies come only from the server.** The list never includes excerpts. With `--bodies`, the CLI prints only what the detail view returned, for failed calls (successful calls never keep a body). A credential that may not read bodies (anything but a full-access key with the writer role, not limited to some accounts or applications) gets `excerptsHidden: true` or `403`: the CLI says so once and prints metadata only. - **Rate limits.** On `429` the CLI waits for `Retry-After` in full (or backs off 1, 2, 4… up to 60 seconds when there is none) and tries again. Timeouts and `502`/`503`/`504` are handled the same way. With `--follow` it keeps trying; otherwise it gives up after 3 retries (exit 1). - **Ctrl-C** stops cleanly: no partial line, a short summary on stderr, exit code 130. --- # Python SDK > The tickwire Python package. Typed sync and async clients for MT4 and MT5 accounts, with idempotent trading, safe retries, resumable streams and webhook verification. Source: https://tickwire.io/docs/sdk-python/ `tickwire` is our Python package for the Tickwire API. It has typed clients, sync and async, and works the same for MT4 and MT5 accounts. It needs Python 3.11 or later. **It isn't on PyPI yet.** We're publishing the package as `tickwire`; until it's there, `pip install tickwire` won't find it. If you want to use the SDK before then, [contact us](https://tickwire.io/contact/). Everything it does is a plain HTTP call, so you can also use the [REST API](https://tickwire.io/docs/reference/) directly with any HTTP client. ## Your first calls in the sandbox ```python from tickwire import Tickwire, trade_succeeded # TICKWIRE_SANDBOX_URL and TICKWIRE_API_KEY (your sandbox key) from the environment. with Tickwire(sandbox=True, actor="quickstart") as tw: acc = tw.account(tw.list_accounts()[0]["id"]) # MT4 and MT5 look the same print(acc.health()["status"]) # healthy | stale | disconnected | down print(acc.price("EURUSD")) r = acc.market_order("EURUSD", 0.01, reason="quickstart") # Idempotency-Key generated for you print(trade_succeeded(r), r["numericCode"]) print(acc.audit(limit=5)) # who did what, when, why ``` `sandbox=True` never guesses a host. It reads `sandbox_url=` or `TICKWIRE_SANDBOX_URL`, and raises `ConfigError` if neither is set. For a live account, pass the URL or set `TICKWIRE_API_URL`. See [Sandbox](https://tickwire.io/docs/sandbox/) for how to get a sandbox key. ## Async and streaming `AsyncTickwire` has the same methods (`async with …`, `await …`), plus streams that resume after a reconnect: ```python from tickwire import AsyncTickwire async with AsyncTickwire(sandbox=True) as tw: async with tw.account(account_id).stream() as s: state = await s.wait_synchronized() s.on("positionUpdated", lambda frame, st: print(frame["position"])) ``` The stream re-subscribes from the last sequence number it saw. If it detects a gap, it does a full resync, so your copy of the account is never silently wrong. See [Streaming](https://tickwire.io/docs/streaming/). ## What it covers - **Accounts:** health, account information, positions, orders, deals and history, symbols, prices, server time, one-call snapshots, the audit log, and trading. - **Accounts and webhooks:** accounts and webhooks, including deliveries, resends and secret rotation. - **Sandbox:** sign-up and sandbox keys. - **Agent keys, kill switches and the pre-trade decision hook:** the SDK has clients for them (`AgentClient` and the owner's admin methods), but the agent API isn't available yet. Native `/v1` lists are [cursor-paginated](https://tickwire.io/docs/pagination/). `tw.pages(...)` follows the cursor for you. ## Safety defaults - **Idempotency.** Every mutation sends an `Idempotency-Key` (yours, or a generated one), `X-Actor` and `X-Reason`. Pass `idempotency_key=` so that repeating the same decision is safe across restarts. See [Idempotency](https://tickwire.io/docs/idempotency/). - **Retries only when safe.** Reads retry on transport errors and 408, 429, 502, 503 and 504, with backoff and a per-client retry budget. A mutation retries only when the server confirms it didn't run it, and always with the same key. - **`unknown` is never retried.** If the reply to a mutation is lost, the SDK raises `OutcomeUnknown` with the idempotency key, so you can check what happened instead of sending the order twice. - **Typed errors.** `NotFound`, `Conflict`, `NotSupportedOnMt4`, `RateLimited`, `ConfigError` and others keep the server's [error envelope](https://tickwire.io/docs/errors/) in `.body`. `health()` returns the body of a 503, because "down" is an answer, not an exception. - **Webhooks.** `verify_webhook(secret, headers, body)` checks the HMAC-SHA256 signature and rejects replays outside a 5-minute window. See [Webhooks](https://tickwire.io/docs/webhooks/). - **No secrets in logs.** Keys never appear in `repr()`. ## The CLI The [`tickwire` command](https://tickwire.io/docs/cli/) is built on this SDK. --- # Authentication > The header forms Tickwire accepts, token kinds, and how to narrow a token's reach. Source: https://tickwire.io/docs/authentication/ Every request carries a key or token. We accept each of the forms the APIs we're compatible with use, so existing clients work unchanged: | Form | Example | Used by | |---|---|---| | `X-Tickwire-Agent-Key` | `X-Tickwire-Agent-Key: ` | AI agents (`/v1/agent/…` execution routes) | | `Authorization: Bearer` | `Authorization: Bearer ` | Generic HTTP clients and MCP server tools | | `X-API-Key` header | `X-API-Key: ` | The `/v1` API and terminal routes | | `auth-token` header | `auth-token: ` | The `/users/current/…` REST API | | Query parameter | `?auth-token=` or `?api_key=` | WebSocket and socket.io connections only, for clients that can't set headers (browsers) | Prefer headers. Query parameters end up in logs more easily; we redact them from ours. ## WebSockets: header or query parameter The WebSocket and socket.io upgrade accepts the same headers as REST: `auth-token`, `X-API-Key` or `Authorization: Bearer`. A key in a header stays out of URLs, so any proxy or tool between you and us never logs it. Use a header whenever your client can set one: ```python import websockets async with websockets.connect( "wss://api.tickwire.io/users/current/accounts/acc_7Qx/ws", additional_headers={"auth-token": TW_KEY}, ) as ws: ... ``` ```js // Node.js (the ws package) const ws = new WebSocket("wss://api.tickwire.io/users/current/accounts/acc_7Qx/ws", { headers: { "auth-token": process.env.TW_KEY }, }); ``` Browsers can't set headers on a WebSocket, so in a browser the query parameter is the only way, and it stays supported. There, use a [scoped token](#token-kinds) with a short time-to-live and only the accounts the page needs, never a full API key. We replace the value of `auth-token`, `api_key` and similar parameters with `REDACTED` in every log we write, our servers' access logs included. ## Token kinds Tickwire separates developer credentials based on whether orders are placed directly by code or guided by an AI assistant: ### 1. API keys (`tw_live_` and `tw_ro_`) Created under **API keys** in the dashboard. - **Full keys (`tw_live_`)**: For custom scripts, bot integrations, prop firm workflows, and direct trading. Can trade, manage accounts, and read. - **Read-only keys (`tw_ro_`)**: Can query balances, quotes, positions, and history, but cannot trade or change settings. - **Headers to send**: `Authorization: Bearer ` or `X-API-Key: `. - **Target routes**: `/users/current/…` and `/v1/…`. ### 2. Agent keys (`twag_`) Created under **AI agents > Keys** in the dashboard. - Built specifically for AI assistants (Google Antigravity, Claude, ChatGPT, Cursor, Windsurf). - **Guarded execution**: Each key is linked to an instant kill switch and evaluated by your pre-trade decision hook before orders reach the broker. - **Headers to send**: In MCP clients, send `Authorization: Bearer `. For direct HTTP calls, send `X-Tickwire-Agent-Key: `. - **Target routes**: `/v1/agent/…` routes and the MCP server. Direct terminal routes reject agent keys with `401 invalid_token` to protect you from ungated agent orders. ### 3. Scoped tokens Narrowed from an API key for browser pages or frontends: limited to certain accounts, with a time-to-live and optional IP allowlist. A token with an allowlist is checked against your real public address on every request and WebSocket, whatever `X-Forwarded-For` says. From anywhere else it gets `403` [`ip_not_allowed`](https://tickwire.io/docs/errors/ip_not_allowed/); the answer never shows the allowlist. Every key and token value is shown **once**, in the answer that creates it (or rotates a read-only key). We keep only a SHA-256 digest of each key (full `tw_live_`, read-only `tw_ro_` and sandbox `twsk_` keys, like API tokens and agent keys), so nobody can show it again, us included. Lists and reads show only a short preview such as `tw_live_ab12…`, and asking the dashboard to reveal a key answers `400` [`not_revealable`](https://tickwire.io/docs/errors/not_revealable/). Store the value when you create it; if you lose it, rotate or revoke the key and create a new one. Keys issued before 2026-10-03 start with `fxs_` and keep working. ## Testing your key: Mac, Linux & Windows ### Testing an API key (`tw_live_` or `tw_ro_`) **macOS / Linux (Terminal):** ```bash curl -s -H "Authorization: Bearer " \ https://api.tickwire.io/users/current/accounts ``` **Windows (PowerShell):** ```powershell curl.exe -s -H "Authorization: Bearer " ` https://api.tickwire.io/users/current/accounts ``` ### Testing an Agent key (`twag_`) **macOS / Linux (Terminal):** ```bash curl -s -H "X-Tickwire-Agent-Key: " \ https://api.tickwire.io/v1/agent/accounts ``` **Windows (PowerShell):** ```powershell curl.exe -s -H "X-Tickwire-Agent-Key: " ` https://api.tickwire.io/v1/agent/accounts ``` ## Rotation doesn't restart anything Creating, rotating or revoking a key never restarts a terminal or drops a broker connection. ## Mistakes and what you'll see | Situations | Status | `error` | |---|---|---| | No key | 401 | [`missing_token`](https://tickwire.io/docs/errors/missing_token/) | | Unknown, expired or revoked key | 401 | [`invalid_token`](https://tickwire.io/docs/errors/invalid_token/) | | Agent key sent to direct terminal route | 401 | [`invalid_token`](https://tickwire.io/docs/errors/invalid_token/) (send `X-Tickwire-Agent-Key` to `/v1/agent/…` instead) | | Key not scoped to this account | 403 | [`account_forbidden`](https://tickwire.io/docs/errors/account_forbidden/) | | Read-only API key on a mutation | 403 | [`read_only_token`](https://tickwire.io/docs/errors/read_only_token/) | | Read-only Agent key on trade | 403 | `read_only_key` (uncheck Read-only in dashboard > AI agents > Keys to trade) | | Request from outside the IP allowlist | 403 | [`ip_not_allowed`](https://tickwire.io/docs/errors/ip_not_allowed/) | On the `/users/current/…` routes, `error` holds the class name (`UnauthorizedError` for 401, `ForbiddenError` for 403) and the code above is in `code`. --- # MT4 and MT5 > One API for both platforms, and the few things MT4 can't do. Source: https://tickwire.io/docs/platforms/ Pick the platform when you create an account (`"platform": "mt4"` or `"mt5"`). After that, every endpoint, field and stream frame is the same. ## What's different MT4 is an older platform and lacks some features. Calls for them return `not_supported_on_mt4`: | Capability | MT5 | MT4 | |---|---|---| | Market depth (`current-book`, `marketDepth` stream) | Yes | `not_supported_on_mt4` | | Historical ticks | Yes | `not_supported_on_mt4` | | Stop-limit orders | Yes | `not_supported_on_mt4` | | Close-by | Yes, on hedging accounts | Depends on the broker | | Timeframes | 21, from `1m` to `1mn` | `1m 5m 15m 30m 1h 4h 1d 1w 1mn` | | History | Deals, orders and positions | Closed orders, exposed as deals and history orders | Ask the account up front instead of catching errors: ```bash curl -s https://api.tickwire.io/users/current/accounts/acc_7Qx/capabilities -H "auth-token: $TW_KEY" ``` ```json { "platform": "mt4", "marketDepth": false, "tickHistory": false, "stopLimitOrders": false, "closeBy": true } ``` An unsupported call returns HTTP 400: ```json { "error": "not_supported_on_mt4", "message": "Market depth isn't available on MetaTrader 4." } ``` ## Hedging and netting (MT5) MT5 accounts are either hedging (many positions per symbol) or netting (one). `marginMode` in account information tells you which. On hedging accounts, closes must name a `positionId`; on netting accounts, positions are identified by their MT5 position identifier, which stays stable while the position is scaled in and out. --- # Health > How Tickwire decides whether an account is working. Source: https://tickwire.io/docs/health/ A running terminal isn't necessarily a working one. A terminal can be alive while logged out, stuck on a dialog, or connected to a broker whose price feed has stopped. So Tickwire measures health from **work that succeeded**, using three independent signals: 1. **Broker link:** the connection state the terminal itself reports. 2. **Account reads:** when we last read the account successfully. That shows the broker is answering, not just that a socket is open. 3. **Tick advance:** whether the broker's clock on a reference symbol is moving. ## The ladder | Status | Meaning | What to do | |---|---|---| | `healthy` | Connected, account readable, ticks advancing | Nothing | | `stale` | Connected and readable, but ticks haven't advanced within 30 s | Usually the broker or a closed market. Treat prices as frozen; don't page yourself | | `disconnected` | Terminal up, no broker link | Usually the broker. We reconnect automatically and escalate if it persists | | `down` | We can't read the terminal at all, or the account isn't running | A running account: ours to fix, and you'll get a webhook. An account that isn't running: `reason_code` says why (see [below](#accounts-that-arent-running)) | ## A health snapshot ```bash curl -s https://api.tickwire.io/users/current/accounts/acc_7Qx/health -H "auth-token: $TW_KEY" ``` ```json { "status": "healthy", "connected": true, "read_only": false, "trading_enabled": true, "reasons": [], "last_account_read_age_s": 2.1, "last_tick_age_s": 0.4, "last_action_age_s": 812.0, "broker_time": "2026-09-23 14:02:11.480", "checked_at": "2026-09-23T11:02:13Z" } ``` - `trading_enabled` is true only if an order could be accepted right now: connected, not an investor login, and trading switched on in the terminal. - `reasons` explains any status other than `healthy` in plain words. - The ages let you apply your own, stricter thresholds. - A quote older than four days never counts as "ticks advancing". Some brokers serve a cached quote from years ago right after login. ## Accounts that aren't running An account can exist without a terminal: its deploy failed (for example the broker asked for a one-time password), or you undeployed it. There is nothing to measure, but the answer is still known, so health says so instead of returning `404`: ```bash curl -s https://api.tickwire.io/users/current/accounts/acc_7Qx/health -H "auth-token: $TW_KEY" ``` ```json { "status": "down", "connected": false, "read_only": null, "trading_enabled": false, "reasons": ["account is not running (state DEPLOY_FAILED)", "ERR_OTP_REQUIRED: the broker asks for a one-time password"], "last_account_read_age_s": null, "last_tick_age_s": null, "last_action_age_s": null, "broker_time": null, "checked_at": "2026-09-23T11:02:13Z", "fx_status": "error", "deployed": false, "state": "DEPLOY_FAILED", "reason_code": "ERR_OTP_REQUIRED", "error": "ERR_OTP_REQUIRED: the broker asks for a one-time password" } ``` - The answer is `200`. `state` is the account's lifecycle state, and `reason_code` the code at the start of its error (`ERR_OTP_REQUIRED`, `E_AUTH`, …), or `null` when the error has no code or there is none. `error` is the same text as `health.error` on the account object. - Anything we can't know without a terminal, such as `read_only` and the ages, is `null`. - The terminal routes match: `GET /mt5/{id}/status` (and `/mt4/…`) is `200` with `status: "down"` plus `deployed`, `state`, `reasonCode` and `error`; `/healthz` and `/livez` are `503`. - Agents: `GET /v1/agent/accounts/{id}/health` says `disconnected`, with `state` and `reason_code` in its `evidence`. - An account that is still deploying answers `503` `account_deploying` with `Retry-After`: it may be up in a moment. An account that doesn't exist, or isn't yours, is `404` `account_not_found`. - Other data calls on an account that isn't running are `404` `account_not_deployed`. Fix the cause and redeploy it. ## How it reaches you - **Polling:** `GET …/health`, as above. - **Streaming:** `health` and `brokerConnectionStatus` frames on the [account stream](https://tickwire.io/docs/streaming/). - **Webhooks:** `account.health_changed` on every transition, within 60 seconds. See [Webhooks](https://tickwire.io/docs/webhooks/). - **`/users/current/…` fields:** `connectionStatus` on the account is `CONNECTED` only when health is `healthy` or `stale` **and** the broker link is up; otherwise `DISCONNECTED_FROM_BROKER` or `DISCONNECTED`. - **`/v1` and terminal-route fields:** `status` maps `healthy` and `stale` to `connected`, `disconnected` to `disconnected`, and `down` to `error`. ## Account snapshot `GET /users/current/accounts/{id}/snapshot` (agents: `GET /v1/agent/accounts/{id}/snapshot`) returns everything needed to rebuild your picture of an MT4 or MT5 account in one call: account information, open positions, pending orders, health and the broker's server time. ```json { "account_id": "acc_7Qx", "platform": "mt5", "as_of": "2026-09-23T11:02:13.412Z", "complete": true, "terminal_connected": true, "account_information": { "status": "ok", "read_at": "2026-09-23T11:02:13.380Z", "age_ms": 32, "data": { "balance": 10000, "equity": 10012.5 } }, "positions": { "status": "ok", "read_at": "…", "age_ms": 25, "data": [] }, "orders": { "status": "ok", "read_at": "…", "age_ms": 18, "data": [] }, "health": { "status": "ok", "read_at": "…", "age_ms": 9, "data": { "status": "healthy" } }, "server_time": { "status": "ok", "read_at": "…", "age_ms": 2, "data": { "time": "2026-09-23T11:02:13.410Z", "brokerTime": "2026-09-23 14:02:13.410", "brokerUtcOffsetMinutes": 180 } } } ``` - Each section has its own `status`: `ok` (read from a terminal connected to its broker), `stale` (read, but the terminal was not connected, so values may be out of date) or `unavailable` (the read failed; `data` is `null` and `error` says why). `complete` is `true` only when every section is `ok`. - `read_at` and `age_ms` show how fresh each section is. Sections are read one after another, not atomically. - `data` uses the same shapes as the individual routes. `brokerUtcOffsetMinutes` is explicit and is `null` until measured; broker time is never assumed to be UTC. - The answer is `200` whenever anything could be read, and `503` only when no section could be. ## Missing data shows as unknown If a measurement is missing, the answer is unknown. The status page works the same way: a component without a recent check shows as unknown. --- # Idempotency and trade outcomes > How to retry without placing a second order, and what each order result means. Source: https://tickwire.io/docs/idempotency/ When a request times out, you need to retry without placing a second order, and to know whether the first one went through. ## Idempotency keys Every mutating call accepts an `Idempotency-Key` header: ```http POST /users/current/accounts/acc_7Qx/trade Idempotency-Key: sig-4411-acc_7Qx X-Actor: copier X-Reason: signal 4411 ``` - Same key and same body: you get the stored result. Nothing is sent to the broker again. - Same key and a different body: `409 idempotency_conflict`. You probably reused a key by mistake. - On the `/users/current/…/trade` endpoint, `clientId` in the body works as the key if you don't send the header. - The `/users/current/…` provisioning routes take an optional `Idempotency-Key` (existing clients don't send one, and nothing changes for them). This covers account create, update and delete, `deploy`, `undeploy` and `redeploy`, `credentials`, `increase-reliability` and the `enable-*` routes, plus provisioning profile create, update, delete and file upload. The key belongs to the credential that sent it, as for the secret-minting calls below. A replay of a `DELETE` returns the stored `204`, not a `404`. A `4xx` answer (unknown account, validation error) stores nothing, so you can fix the request and reuse the key. Broker and manager passwords are never stored: the key is bound to a hash of them, so a retry with a different password is a `409`. - Account creation also accepts the `transaction-id` header, with its usual behaviour: the same id and body return the first answer (now also with `Idempotent-Replayed: true`), a different body is `409 ConflictError`, and a retry while the first call is still running gets `202 AcceptedError` with `Retry-After`. `transaction-id` and `Idempotency-Key` share one store, so the same value sent under either header is the same request. You can send both headers if they hold the same value. Two different values are a `400 ValidationError`. - Calls that create or rotate a secret (`POST /v1/agent-keys`, `POST /v1/pretrade-hooks` and its `rotate-secret`, `POST /users/current/tokens`, `POST /users/current/narrow-down-auth-token`, `POST /v1/readonly-keys` and its `rotate`, `POST /v1/sandbox/keys`, and in the dashboard `POST /dashboard/api-keys` and its `rotate`) never show the secret again. A replay has the same id, with the secret field (`key`, `secret`, `token` or `apiKey`) set to `null` and a notice that it was already shown. A replayed rotate rotates nothing: the value from the first answer stays the working one. If you lost it, revoke (or rotate) and create a new one. `narrow-down-auth-token` answers `{token, id}`, where `id` is the token record you revoke with `DELETE /users/current/tokens/{id}`. - For these calls the protection is short-lived: a retry that arrives after one of our restarts or deploys may create a second credential. After retrying one of these calls, list the credentials (for example `GET /v1/agent-keys`) and revoke any duplicate. - The key belongs to the credential that sent it. Another API key, token or user of the same organisation that sends the same `Idempotency-Key` gets its own result, not yours. - If the credential was created but the call then failed, the answer is `500` with `outcome: unknown` and `created_id`, the id of the credential that now exists (never its secret). Revoke it (or rotate it) by that id, then send a new request with a new key. - A duplicate that arrives while the first call is still running gets `409 idempotency_in_flight` with `Retry-After`, and does nothing. Make keys deterministic from your own ids (signal id plus account id, say), so a crashed worker that restarts produces the same key. A key is 1 to 255 printable characters. A longer key, or one with control characters, tabs or bidi marks, is `400 invalid_idempotency_key` (keys are never truncated, so two long keys can't collide). On the `/v1` API and the account-management routes a stored result is kept for 24 hours; after that the key can be used for a new request. Each credential holds at most 10,000 stored results: past that, its least recently used results are dropped first (a call still running is never dropped). A stored result comes back with the response header `Idempotent-Replayed: true`. The first call never carries it, so you can tell a replay from a fresh execution without comparing bodies. The header is on every surface that honours `Idempotency-Key`: the `/users/current/…` and terminal routes, the native `/v1` API, the agent API and guarded execution. ## Outcomes Order responses carry the broker's code (`numericCode`, `stringCode`) and our `outcome`: | `outcome` | Meaning | |---|---| | `applied` | It happened. The broker confirmed it, or we found the result in the terminal. | | `no_change` | Nothing needed doing, e.g. closing a position that's already closed. Counts as success. | | `partial` | Part of the volume was filled. | | `rejected` | The broker refused it. Nothing happened. | | `unknown` | We can't confirm either way. See below. | `is_effective` on the `/v1` and terminal routes tells you whether the call changed anything, so a repeated close is distinguishable from the first one. ## When the answer is "unknown" Sometimes the broker link drops after the request left the terminal. MT5 reports this as 10031 (`TRADE_RETCODE_CONNECTION`) and, depending on the moment, 10011, 10012, 10028 or 10039. MT4's equivalents are 128 (trade timeout) and 146 (trade context busy). The order **may** have executed. Tickwire then checks the terminal's positions, orders and deals for the request. If it finds the result, the outcome is `applied`. If it can confirm nothing happened, `rejected`. If it can't tell yet, `unknown`. When you get `unknown`: 1. Don't blindly retry with a **new** key. That's how double positions happen. 2. Retry with the **same** key after a few seconds. We re-check before doing anything. 3. Or reconcile yourself from `positions` and `history-deals`, matching on your `clientId`. ## The audit log Every mutating call is recorded: time, `X-Actor`, `X-Reason`, the route, the idempotency key and the outcome. On the trading and terminal routes (`/users/current/accounts/{id}/trade`, `/mt4/{id}/…`, `/mt5/{id}/…`), a call without `X-Actor` is recorded with actor `unknown`. The [request log](https://tickwire.io/docs/request-logs/) still shows which key sent it (`keyId`). ```bash curl -s "https://api.tickwire.io/users/current/accounts/acc_7Qx/audit?limit=50" -H "auth-token: $TW_KEY" ``` Account and profile changes (`account.created`, `account.deployed`, `provisioning_profile.updated` and so on) and narrowed tokens (`token.narrowed`) go to your organisation's audit log, which the dashboard shows under **Audit**. Each entry has the actor (`X-Actor`, or `api-key:` of the credential that called when you don't send one), the calling credential's `key_id` (always, even with an `X-Actor`), the reason (`X-Reason`, percent-decoded, at most 500 characters) and the idempotency key. Control characters (including line breaks) and bidi marks are removed from these values. Passwords and token values are never written there. A replay is not logged again. `X-Actor` is a free label, but it can't claim an identity the server assigns: a value starting with `api-key:`, `user:` or `firebase:` that isn't the calling credential's own is `400 invalid_actor`, and nothing is changed. --- # Time zones and broker time > Why broker time isn't UTC, how Tickwire labels it, and how to get day boundaries right. Source: https://tickwire.io/docs/time-zones/ MetaTrader servers keep their own clock, usually UTC+2 in winter and UTC+3 in summer ("New York close" time), but not always. Tick, bar and deal times from the terminal are in that **broker-local** time. Treating them as UTC shifts everything by two or three hours and puts daily limits on the wrong day. ## The rules we follow - Fields named `time` (or ending in `Time` without `broker`) are **UTC**, ISO-8601 with `Z`. - Fields named `brokerTime` are broker-local, formatted `YYYY-MM-DD HH:mm:ss.SSS`, with no zone suffix because they're not UTC. - We never put a `Z` on broker time. ```json { "time": "2026-09-23T11:02:11.480Z", "brokerTime": "2026-09-23 14:02:11.480" } ``` ## Finding a broker's offset ```bash curl -s https://api.tickwire.io/users/current/accounts/acc_7Qx/server-time -H "auth-token: $TW_KEY" ``` ```json { "time": "2026-09-23T11:02:13Z", "brokerTime": "2026-09-23 14:02:13.000", "brokerUtcOffsetSeconds": 10800 } ``` The offset is **measured**: broker tick time minus UTC, rounded to 30 minutes, and only while ticks are fresh. The daylight-saving rule is worked out from the hour at which trading weeks open over several years of hourly bars. Until we've measured it, `brokerUtcOffsetSeconds` is `null`; we don't fill it in with a guess. The [account snapshot](https://tickwire.io/docs/health/#account-snapshot) (`GET /users/current/accounts/{id}/snapshot`) carries the same clock in its `server_time` section, with the offset stated explicitly as `brokerUtcOffsetMinutes` (`null` when not yet measured, never assumed to be 0). If auto-detection gets a broker wrong, set `brokerTimezone` and `brokerDSTSwitchTimezone` on a [provisioning profile](https://tickwire.io/docs/broker-onboarding/). ## Day boundaries for risk rules Prop firms usually reset daily loss limits at the broker's midnight, not UTC midnight. Use `brokerTime` (or UTC plus the measured offset) to decide which trading day a deal belongs to. Our [risk trackers](https://tickwire.io/docs/guides/prop-risk-tool/) do this for you. --- # Build a prop risk tool > Watch equity on many accounts, enforce daily and maximum drawdown, and flatten on breach. Source: https://tickwire.io/docs/guides/prop-risk-tool/ A prop risk tool has one job: never miss a breach. That means knowing when you **can't** see an account, not just when it's losing. ## The shape 1. Connect each trader's account, ideally with the **investor password** if you only monitor, or the master password if you must flatten. 2. Subscribe to each account's stream for equity and positions. 3. Treat any health other than `healthy` as "not watching" and alert on it. 4. On breach, flatten with an idempotent close, then verify. ## 1. Stream equity ```js const ws = new WebSocket(`wss://api.tickwire.io/users/current/accounts/${id}/ws?auth-token=${token}`); ws.onopen = () => ws.send(JSON.stringify({ type: "subscribe" })); ws.onmessage = (m) => { const f = JSON.parse(m.data); if (f.type === "accountInformation" || f.type === "accountInformationUpdated") { check(id, f.accountInformation.equity, f.accountInformation.balance); } if (f.type === "health" && f.status !== "healthy") notWatching(id, f); }; ``` Keep the last `seq` you processed. If the socket drops, reconnect with `{"type":"subscribe","sync":{"lastSeq":}}` and you'll get what you missed. See [Streaming](https://tickwire.io/docs/streaming/). ## 2. Day boundaries in broker time Daily loss limits usually reset at the **broker's** midnight. Take the start-of-day balance at the broker's day change, not at UTC midnight. See [Time zones](https://tickwire.io/docs/time-zones/). ## 3. Know when you're blind Register a webhook for `account.health_changed`. If an account goes `disconnected` or `down`, your tool isn't protecting that trader. Say so in your UI rather than showing the last equity as current. ## 4. Flatten on breach ```bash curl -s -X POST "$TW/users/current/accounts/$ID/trade" \ -H "auth-token: $TW_KEY" \ -H "Idempotency-Key: breach-$ID-2026-09-23" \ -H "X-Actor: risk-engine" -H "X-Reason: daily loss 5% breached" \ -H "content-type: application/json" \ -d '{"actionType": "POSITIONS_CLOSE_SYMBOL", "symbol": "EURUSD"}' ``` Across many accounts at once, the batch endpoint `POST /v1/orders/close` takes selectors (all positions, by symbol, by magic) for up to 20 accounts in one idempotent call. Then verify: read `positions` until it's empty. If any close came back `unknown`, retry with the **same** key; see [Idempotency](https://tickwire.io/docs/idempotency/). ## 5. Or let Tickwire enforce it Our risk engine can run the rule for you: drawdown and profit trackers per day, week, month and lifetime, with absolute or relative thresholds and broker-time day boundaries. The guard runs **next to the terminal**, so it keeps enforcing even if our central services or yours are unreachable. Breaches arrive as webhooks. This part is not available yet. --- # Build a trade copier > Copy trades from one account to many, with idempotency keys so a retry never fills twice, and handle the ones that can't be confirmed. Source: https://tickwire.io/docs/guides/copier/ Copiers fail in two ways: copying a trade twice, or silently not copying it. Here's how to avoid both. > Copy only into accounts whose owners have authorised it. Copying into someone else's account is > banned by our [acceptable use policy](https://tickwire.io/legal/acceptable-use/) and by most prop firms. ## Listen to the source Subscribe to the source account's stream and act on position changes: ```js if (f.type === "positionUpdated" && isNew(f.position)) fanOut(f.position); if (f.type === "positionRemoved") closeCopies(f.positionId); ``` ## Fan out with deterministic keys Derive the idempotency key from the source position and the follower. A crashed and restarted worker then produces the same key and can't double-copy. ```python import requests def copy_open(follower, src): return requests.post( f"{TW}/users/current/accounts/{follower}/trade", headers={ "auth-token": KEY, "Idempotency-Key": f"open-{src['id']}-{follower}", "X-Actor": "copier", "X-Reason": f"copy of {src['id']}", }, json={ "actionType": "ORDER_TYPE_BUY" if src["type"] == "POSITION_TYPE_BUY" else "ORDER_TYPE_SELL", "symbol": map_symbol(follower, src["symbol"]), "volume": size_for(follower, src), "clientId": f"cp_{src['id']}", }, timeout=30, ).json() ``` `clientId` is stored with the order, so you can find each copy later by the source id. ## Symbols differ per broker `EURUSD` on one broker is `EURUSDm` or `EURUSD.r` on another. Build a map per follower from `GET …/symbols`, and check `symbols/{symbol}/specification` for `minVolume` and `volumeStep` before sizing. Cent accounts need very different volumes. ## Many followers in one call `POST /v1/orders` sends up to 20 legs across accounts in one idempotent request and returns a status per leg. ## Handle "unknown" If a leg comes back `unknown`, don't send a new order. Retry with the same key, or look for the `clientId` in the follower's `positions`. See [Idempotency](https://tickwire.io/docs/idempotency/). ## Skip followers you can't reach Check health before copying. If a follower is `disconnected`, record the missed copy and decide deliberately (catch up at market, or skip) when it comes back, rather than letting requests time out. --- # Build a trading journal > Sync closed trades read-only with investor passwords, incrementally and without gaps. Source: https://tickwire.io/docs/guides/journal/ A journal needs complete, correct history and should never be able to trade. ## Use investor passwords Connect accounts with the **investor** (read-only) password. The terminal then can't trade at all: account information shows `tradeAllowed: false`, and health shows `read_only: true` and `trading_enabled: false`. Your users can hand you access without handing you their account. ## First sync Page through deals by time. Start is inclusive, end exclusive, and `limit` is at most 1000: ```bash curl -s "$TW/users/current/accounts/$ID/history-deals/time/2026-01-01T00:00:00Z/2026-09-23T00:00:00Z?offset=0&limit=1000" \ -H "auth-token: $TW_KEY" ``` Keep increasing `offset` by the number of results until you get fewer than `limit`. Deals include deposits, withdrawals and credit (`DEAL_TYPE_BALANCE`, `DEAL_TYPE_CREDIT`), so you can separate trading performance from money movements. On MT4, closed orders are presented as deals with the same fields. ## Stay in sync Either poll from your last deal's `time` (overlap by a minute and de-duplicate on deal `id`), or subscribe to the account stream with `sync.startingHistoryTime` set to that time and consume `deals` and `dealAdded` frames. ## Get the time right Group trades into days by the broker's trading day, using `brokerTime`, not by UTC date. See [Time zones](https://tickwire.io/docs/time-zones/). ## Statistics If you'd rather not compute them, our statistics API (not available yet) returns period stats, drawdown, and equity and balance curves. --- # Build a trading bot > Stream prices, place orders, and handle disconnects and ambiguous fills correctly. Source: https://tickwire.io/docs/guides/trading-bot/ ## Stream what you need ```json { "type": "subscribe", "marketData": [ { "symbol": "EURUSD", "subscriptions": [ { "type": "quotes", "intervalInMilliseconds": 250 }, { "type": "candles", "timeframe": "1m" } ] } ] } ``` You'll get `prices` and `candles` frames. Each `prices` frame also carries the account's `equity`, `margin` and `freeMargin`, read from the terminal. See [Streaming](https://tickwire.io/docs/streaming/). ## Don't trade on stale prices Check the `health` frames. If the account is `stale`, prices have stopped moving; if it's `disconnected`, orders will fail. Pause the strategy rather than trading on a frozen quote. ## Place orders without duplicates Give every order an idempotency key derived from your strategy's own decision id: ```json { "actionType": "ORDER_TYPE_BUY_LIMIT", "symbol": "EURUSD", "volume": 0.1, "openPrice": 1.0712, "stopLoss": 20, "stopLossUnits": "RELATIVE_PIPS", "takeProfit": 40, "takeProfitUnits": "RELATIVE_PIPS", "expiration": { "type": "ORDER_TIME_SPECIFIED", "time": "2026-09-23T18:00:00Z" }, "clientId": "bot1_d8812" } ``` Stops and targets can be absolute prices or relative (price, points, pips, account currency, or percent of balance). ## Read the response properly `POST /trade` returns HTTP 200 even when the broker rejects. Success codes are 10008 (placed), 10009 (done), 10010 (partial) and 10025 (no changes); anything else is a failure. Then check our `outcome`. If it's `unknown`, the broker link dropped mid-order: retry with the same key, never a new one. See [Idempotency](https://tickwire.io/docs/idempotency/). ## After a reconnect Resume the stream with `lastSeq` so you don't miss fills. After a broker reconnect, wait for a fresh tick before sending new orders. --- # Example projects > Starter templates to copy. Quickstarts in Python and TypeScript, webhook receivers, a pre-trade guard and an AI assistant over MCP. Sandbox only, MIT licensed. Source: https://tickwire.io/docs/guides/examples/ We've written small example projects you can copy. Each one has its own README, an MIT license, and tests that run offline against mocks. They aren't published yet; until they are, [contact us](https://tickwire.io/contact/) if you'd like one. The runnable parts target the [sandbox](https://tickwire.io/docs/sandbox/) only. The quickstarts refuse any key that isn't a sandbox key (`twsk_…`), and nothing has a live host built in. | Directory | What it shows | |---|---| | `examples/python-quickstart` | Create a sandbox account, read it, and place one idempotent order with a reason. It handles `applied`, `rejected`, `held` and `unknown`, and never retries `unknown` | | `examples/typescript-quickstart` | The same with the TypeScript SDK | | `examples/webhook-receiver-python` | A FastAPI receiver: verify [Standard Webhooks](https://tickwire.io/docs/webhooks/) signatures, reject stale timestamps, de-duplicate by event id | | `examples/webhook-receiver-node` | The same with Express | | `examples/pretrade-guard` | A minimal service on the pre-trade decision hook. It verifies Tickwire's signature, answers a signed `allow`, `deny` or `hold`, and releases holds | | `examples/ai-agent-mcp` | Connect an AI assistant to the Tickwire MCP server with a read-only or scoped agent key | > **Tickwire ships no trading rules.** The guard's rule (deny orders above a size, hold mid-size > ones for a person) is only an example of the moving parts. The rules you enforce are yours. ## Try each outcome The quickstarts take a [magic login](https://tickwire.io/docs/sandbox/#magic-logins), so you can see every outcome without a broker: ```bash python quickstart.py --reason "normal fill" --login 1000 # applied python quickstart.py --reason "reply lost, filled" --login 1031 # applied python quickstart.py --reason "reply lost, no fill" --login 1032 # unknown: check before acting python quickstart.py --reason "no money" --login 1019 # rejected ``` `unknown` means the order **may** have executed. The examples print the open positions and the idempotency key, and stop. Re-running with the same key returns the recorded answer and never fills twice. A retry with a new key could open a second position. See [Idempotency](https://tickwire.io/docs/idempotency/). ## Before you ship one - The webhook receivers keep seen event ids in memory. In production, put a unique key on the event id in your database. - The guard keeps no state and has no login. A real guard product needs both. - The SDKs aren't on PyPI or npm yet. See the [Python SDK](https://tickwire.io/docs/sdk-python/) page. AI apps don't need a package: they connect to Tickwire's hosted MCP address (see [AI agents](https://tickwire.io/ai-agents/#connect)). --- # Streaming > The per-account WebSocket protocol. Full sync, incremental updates, market data, sequence numbers and resume. Source: https://tickwire.io/docs/streaming/ There are two ways to stream: - **A socket.io protocol** for existing clients that already speak it, alongside the `/users/current/…` REST API. See [Switching from another provider](https://tickwire.io/docs/switching/). - **Tickwire's plain WebSocket protocol** (this page): JSON frames, one socket per account, easy to use from any language without an SDK. ## Connect ``` wss://api.tickwire.io/users/current/accounts/{accountId}/ws?auth-token= ``` Or, better, leave the key out of the URL and send it as the `auth-token` (or `X-API-Key`, or `Authorization: Bearer`) header on the upgrade, if your client can set headers. Browsers can't, so they use the query parameter; give a browser a short-lived [scoped token](https://tickwire.io/docs/authentication/#token-kinds), not a full key. See [WebSockets: header or query parameter](https://tickwire.io/docs/authentication/#websockets-header-or-query-parameter). ## Subscribe ```json { "type": "subscribe", "sync": { "startingHistoryTime": "2026-09-01T00:00:00Z", "lastSeq": null }, "marketData": [ { "symbol": "EURUSD", "subscriptions": [ { "type": "quotes", "intervalInMilliseconds": 500 }, { "type": "candles", "timeframe": "1m" }, { "type": "ticks" }, { "type": "marketDepth" } ] } ] } ``` - `sync.startingHistoryTime`: send history (deals and history orders) from this time. `null` skips history. - `sync.lastSeq`: resume after a disconnect (below). - `marketData`: optional. `ticks` and `marketDepth` are MT5 only. Send `{"type": "unsubscribe", "marketData": [...]}` to drop market data, and `{"type": "ping"}` whenever you like; you'll get `pong`. ## Frames Every server frame has `type`, `seq` (increasing by one per frame) and `time` (UTC). **Full synchronization**, in this order: | Frame | Carries | |---|---| | `synchronizationStarted` | — | | `accountInformation` | `accountInformation` | | `positions` | the full list (replace yours) | | `orders` | the full list of pending orders (replace yours) | | `historyOrders` | a batch; may repeat | | `deals` | a batch; may repeat | | `positionsSynchronized`, `ordersSynchronized`, `historyOrdersSynchronized`, `dealsSynchronized` | — | | `synchronized` | Your state is complete | **Incremental updates** after that: `accountInformationUpdated`, `positionUpdated`, `positionRemoved`, `orderUpdated`, `orderCompleted`, `historyOrderAdded`, `dealAdded`. **Market data:** `prices` (with the account's `equity`, `margin`, `freeMargin` and `marginLevel`), `candles`, `ticks` and `book`. **Status:** `health` (our [health snapshot](https://tickwire.io/docs/health/)) whenever it changes, and `brokerConnectionStatus` with `connected: true|false`. **Warnings:** `warning`, for example when you read too slowly (below). ```json { "type": "positionUpdated", "seq": 1842, "time": "2026-09-23T11:02:14.120Z", "position": { "id": "46870472", "symbol": "EURUSD", "type": "POSITION_TYPE_BUY", "volume": 0.01, "openPrice": 1.07182, "profit": 0.42, "brokerTime": "2026-09-23 14:02:14.120" } } ``` ## Resume after a disconnect Remember the last `seq` you processed. Reconnect and subscribe with `"lastSeq": `: - If we still hold the frames after it, we replay them and carry on. No gap, no full sync. - If not, we run a full synchronization. Replace your state when `synchronized` arrives. ## Slow consumers If you don't read fast enough, we don't buffer forever. We drop frames and send: ```json { "type": "warning", "seq": 2210, "code": "slow_consumer", "firstMissingSeq": 2011 } ``` Reconnect with `lastSeq: 2010` to get the missing frames back, or accept a fresh sync. ## Heartbeats We send a frame at least every 15 seconds, a `health` frame if nothing else is happening. If you hear nothing for 60 seconds, reconnect. --- # Webhooks > Signed event delivery, retries for 72 hours, the delivery log, resend, secret rotation and the event catalog. Source: https://tickwire.io/docs/webhooks/ Register an HTTPS endpoint and we'll POST events to it. You don't need to poll to find out that an account went down. Every delivery is stored: you can see each attempt, why it failed, and resend it for 30 days. ## Register ```bash curl -s -X POST https://api.tickwire.io/v1/webhooks \ -H "X-API-Key: $TW_KEY" -H "content-type: application/json" \ -d '{"url": "https://example.com/hooks/tickwire"}' ``` ```json { "id": "wh_91c", "url": "https://example.com/hooks/tickwire", "secret": "whsec_…", "active": true, "created_at": "2026-09-23T11:00:00+00:00" } ``` Store the `secret`. You can also supply your own. Endpoint management needs a full API key: read-only keys are refused, because responses contain the secret. ### Which URLs are allowed - `https://` only. - The host must resolve only to public internet addresses. We refuse `localhost`, `*.localhost`, `*.internal` and `*.local`, and any host that is or resolves to a loopback, private (RFC 1918, IPv6 ULA), link-local (including cloud metadata `169.254.169.254`), carrier-grade NAT, multicast or reserved address. If any one of its addresses is non-public, the URL is refused. - No username or password in the URL. A refused URL gets `400 invalid_url` with the same message whatever the reason. We check again on **every delivery attempt** and send to the address we checked, so a DNS change to a private address is refused too. Redirects are never followed: a `3xx` is a failed delivery. To test with a receiver on your own machine, expose it over HTTPS with a tunnel, then send a `webhook.test` event from the dashboard. ## What a delivery looks like ```http POST /hooks/tickwire Content-Type: application/json X-Tickwire-Event: account.health_changed X-Tickwire-Event-Id: 5f0c7a0e9b1d4c2e8f3a6b7c8d9e0f1a X-Tickwire-Delivery-Id: dlv_4be01f2a9c7d5e3b1a0f8c6d X-Tickwire-Attempt: 1 X-Tickwire-Timestamp: 1790161333 X-Tickwire-Signature: sha256=3b9f… X-Tickwire-Signatures: sha256=3b9f… webhook-id: 5f0c7a0e9b1d4c2e8f3a6b7c8d9e0f1a webhook-timestamp: 1790161333 webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4= {"id":"5f0c7a0e9b1d4c2e8f3a6b7c8d9e0f1a","type":"account.health_changed","created_at":"2026-09-23T11:02:13+00:00","data":{…}} ``` | Header | Meaning | |---|---| | `X-Tickwire-Event` | The event type | | `X-Tickwire-Event-Id`, `webhook-id` | The event id. Stays the same on every retry and every resend: de-duplicate on it | | `X-Tickwire-Delivery-Id` | This delivery (a resend is a new delivery of the same event) | | `X-Tickwire-Attempt` | 1 for the first try, then 2, 3, … | | `X-Tickwire-Timestamp`, `webhook-timestamp` | Unix seconds when this attempt was signed (fresh on every retry) | | `X-Tickwire-Signature` | `sha256=` under your **current** secret | | `X-Tickwire-Signatures` | `sha256=` for **every active** secret, comma-separated (two during a rotation) | | `webhook-signature` | [Standard Webhooks](https://www.standardwebhooks.com/) signatures, `v1,`, space-separated, one per active secret | We strip broker passwords, API keys, tokens and secrets from every event before it is stored or sent. ## Verify the signature You can verify either header set. Both use HMAC-SHA256 with your secret. ### Tickwire headers The signature covers the timestamp, a dot, and the **raw** request body. Verify before parsing, and reject old timestamps to block replays. Checking every entry of `X-Tickwire-Signatures` lets you rotate secrets without downtime. ```python import hashlib, hmac, time def verify(secret: str, headers: dict, raw_body: bytes, tolerance_s: int = 300) -> bool: ts = headers["X-Tickwire-Timestamp"] if abs(time.time() - int(ts)) > tolerance_s: return False expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest() given = headers.get("X-Tickwire-Signatures") or headers["X-Tickwire-Signature"] return any(hmac.compare_digest(expected, s.strip().removeprefix("sha256=")) for s in given.split(",")) ``` ```js import crypto from "node:crypto"; export function verify(secret, headers, rawBody, toleranceS = 300) { const ts = headers["x-tickwire-timestamp"]; if (Math.abs(Date.now() / 1000 - Number(ts)) > toleranceS) return false; const expected = crypto.createHmac("sha256", secret).update(`${ts}.`).update(rawBody).digest("hex"); const given = String(headers["x-tickwire-signatures"] || headers["x-tickwire-signature"]); return given.split(",").some((s) => { const sig = s.trim().replace(/^sha256=/, ""); return sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig)); }); } ``` Verifiers that only read `X-Tickwire-Signature` keep working. That header always carries the current secret's signature. ### Standard Webhooks The `webhook-*` headers follow the [Standard Webhooks](https://www.standardwebhooks.com/) spec, so the official libraries verify Tickwire deliveries unchanged. Pass them your secret as it is: ```python from standardwebhooks.webhooks import Webhook payload = Webhook(secret).verify(raw_body, headers) # raises on a bad signature or old timestamp ``` ```js import { Webhook } from "standardwebhooks"; const payload = new Webhook(secret).verify(rawBody, headers); ``` This works for the secrets Tickwire generates (`whsec_…`). If you chose your own secret, use the `standardSecret` value that `POST /v1/webhooks/{id}/reveal-secret` and `rotate-secret` return (`whsec_` plus the base64 of your secret). ## Delivery and retries - Return any `2xx` within 5 seconds. Do slow work after you've responded. Each attempt has a hard limit of 10 seconds in total (connecting, sending, and reading your status line, headers and up to 2 KiB of body). An attempt that takes longer is `failed` with `timeout` and is retried. - At most 2 deliveries per organisation are in flight at once, so one slow endpoint delays only its own organisation's deliveries. - A delivery counts as **delivered only on a `2xx`**. A `3xx` (we don't follow redirects), `4xx`, `5xx`, timeout or connection error is **failed**, and we retry it. - Retries use exponential backoff with ±20 % jitter: about 5 s, 30 s, 2 min, 10 min and 1 h after the first try, then every 3 to 6 hours, until 72 hours after the event. The last try is at the 72-hour mark. - Retries are stored in our database, so they survive our deploys and restarts. - Deliveries can arrive more than once or out of order. De-duplicate on `X-Tickwire-Event-Id` (or `webhook-id`), and use `created_at` (and the health snapshot inside `data`) to ignore older news. ### Endpoints that keep failing If every delivery to an endpoint has failed for **72 hours** without a single `2xx`, we disable the endpoint: - its unfinished deliveries stop (you can resend them after you fix it); - your other endpoints receive a `webhook.endpoint_disabled` event; - your organisation's owners and admins get an email. Fix the endpoint, then re-enable it: ```bash curl -s -X POST https://api.tickwire.io/v1/webhooks/wh_91c/enable \ -H "X-API-Key: $TW_KEY" -H "X-Reason: fixed TLS certificate" ``` Any `2xx` resets the 72-hour clock. ## Choose which events an endpoint gets By default an endpoint receives every event (`"*"`). Narrow it with `enabledEvents`: exact types, family wildcards such as `trade.*`, or `*`. ```bash curl -s -X PATCH https://api.tickwire.io/v1/webhooks/wh_91c \ -H "X-API-Key: $TW_KEY" -H "content-type: application/json" \ -d '{"enabledEvents": ["account.health_changed", "trade.*"]}' ``` An unknown type returns `400 invalid_request`. `GET /v1/webhooks/{id}/settings` shows the filter, status, `failingSince`, `lastSuccessAt` and the rotation state. ## Events `GET /v1/webhook-event-types` lists every type with a description and an example payload. No key is needed. | Event | When | |---|---| | `account.created` | An account was added | | `account.health_changed` | Health moved between `healthy`, `stale`, `disconnected` and `down`, or the `connectionStatus` on `/users/current/…` changed. Delivered within 60 s | | `account.state_changed` | Deployment state changed (`DEPLOYING`, `DEPLOYED`, …) | | `account.engine_state_changed` | The terminal engine on the host changed state | | `account.live` | The terminal logged in and is serving for the first time | | `subscription.updated` | Your subscription changed | | `risk.tracker_exceeded` | A risk tracker crossed its threshold | | `trade.outcome` | Outcome of an order sent through the agent API: filled, rejected, or `unknown` when the terminal couldn't confirm it | | `trade.denied`, `trade.held`, `trade.hold_expired`, `trade.hold_released` | Pre-trade hook decisions | | `pretrade.hook_failed_open`, `pretrade.hook_unavailable` | Your pre-trade hook failed | | `agent.kill_switch_changed` | An agent kill switch was engaged or released | | `webhook.endpoint_disabled` | One of your endpoints was disabled: after 72 h of failures (`failing_72h`) or because its URL is not allowed (`url_not_allowed`) | | `webhook.test` | A test event you sent from the dashboard | | `account.connected`, `account.disconnected` | The terminal's broker link came up or went down, as the account's health reports it | | `account.login_failed` | The terminal tried to log in and the broker refused it. The payload never contains credentials | | `account.margin_call` | The terminal-reported margin level fell to or below the broker's margin-call level (percent mode only; once per crossing) | | `account.stop_out` | The terminal reports a deal closed by stop-out (MT5 deal reason `SO`; on MT4, the broker's `so:` comment) | | `position.opened`, `position.modified`, `position.closed` | A position appeared, had its SL, TP or volume changed, or left the position list | | `order.filled`, `order.cancelled`, `order.rejected` | A pending order filled or was cancelled/expired (from the terminal's order history), or an order Tickwire sent was rejected | | `trade.outcome_unknown` | An order Tickwire sent could not be confirmed either way. Reconcile with the same idempotency key; never resend with a new one | | `dedicated_ip.active`, `dedicated_ip.released` | A dedicated IP became active (route confirmed), or was released for good (it is never reassigned) | ### When account and trade events are sent Tickwire sends these only when the terminal shows the change: - Position and order events come from comparing two successful reads of the terminal, about every 2 seconds. Reads taken while the terminal is not connected to its broker, or that fail, are skipped, so a reconnect never looks like every position closing and reopening. The first good read after a restart is the baseline and sends nothing. - `position.closed` is sent at once when the terminal's history has the closing deal (`"evidence": "closing_deal"`, with `closing_deal` filled in). A position that disappears without a closing deal is held back: if it is back on the next read, nothing is sent; if two consecutive good reads lack it and there is still no deal, `position.closed` is sent with `"evidence": "unknown"` and `"closing_deal": null`. Treat that as "gone, cause unknown" and check the history before acting on it. - A pending order that disappears is reported only from the terminal's order history. With no history record after two reads, nothing is sent. - `order.filled` for a market order comes from the broker's confirmed deal; for a pending order, from the order history or from the order's ticket becoming a position. - `account.margin_call` and `account.stop_out` are sent only when the terminal reports them; we don't calculate them ourselves. - `account.connected` is sent only when the terminal itself reports the broker link up. All of them work the same on MT4 and MT5 accounts. Each type is in `GET /v1/webhook-event-types` with an example payload. ### How trade events reach you Position, order, margin-call and stop-out events start in your account's terminal, a few seconds after the change. If our event service can't be reached, the terminal keeps up to 1,000 events per account and retries them, oldest first, every few seconds (backing off to once a minute). Trading never waits for this. Delivery is **at least once**. Every event keeps one id across retries, and we usually recognise a retry of an event we already have and don't send it again. That check covers only recent events and doesn't survive a restart of our service, so the same event can still reach you twice. It then has the same `X-Tickwire-Event-Id` (and `webhook-id`): de-duplicate on it. Some events can still be lost: - if more than 1,000 pile up during an outage, the oldest are dropped first; - events that were still queued when the terminal restarted are gone; - if our event service refuses the terminal's credentials (for example after we reset them), each event is retried for 15 minutes and then dropped. Redeploying the account fixes it. A webhook tells you something changed. After an outage, re-read positions, orders and history to catch up. Sandbox accounts don't send position, order, margin-call or stop-out events. To test your handler, use `POST /v1/webhook-events/trigger` with a sandbox key. ## Delivery log Every delivery and every attempt is kept for 30 days. ```bash curl -s "https://api.tickwire.io/v1/webhooks/wh_91c/deliveries?status=failed&limit=20" \ -H "X-API-Key: $TW_KEY" ``` ```json { "data": [{ "id": "dlv_4be01f2a9c7d5e3b1a0f8c6d", "webhookId": "wh_91c", "eventId": "5f0c7a0e9b1d4c2e8f3a6b7c8d9e0f1a", "eventType": "account.health_changed", "url": "https://example.com/hooks/tickwire", "status": "failed", "willRetry": true, "attempts": 3, "nextAttemptAt": "2026-09-23T11:14:40Z", "lastStatusCode": 502, "lastLatencyMs": 181, "lastError": "http 502", "createdAt": "2026-09-23T11:02:13Z", "deliveredAt": null, "resendOf": null, "resendableUntil": "2026-10-23T11:02:13Z" }], "hasMore": false, "nextCursor": null } ``` | Query | Meaning | |---|---| | `status` | `pending`, `sending`, `delivered`, `failed`, or `retrying` (failed, with a retry scheduled) | | `eventType`, `eventId` | Filter by event | | `since`, `until` | ISO-8601 times, on `createdAt` | | `limit`, `cursor` | Page size (1–200, default 50) and the `nextCursor` of the previous page. Newest first | `lastError` is `http `, `timeout`, `connection_error: …`, `url_not_allowed` (the URL failed the rules above at send time; retried, since DNS may change back), or, for deliveries we stopped without sending, `endpoint_disabled` or `endpoint_deleted`. An endpoint whose URL can never pass the rules (for example one registered before they applied) gets no deliveries. Its settings show `status: disabled` and `disabledReason: url_not_allowed`, and your other endpoints receive `webhook.endpoint_disabled`. Change the URL with `PATCH /v1/webhooks/{id}`, then enable it. `GET /v1/webhooks/{id}/deliveries/{deliveryId}` adds `attemptLog` (each attempt's time, outcome, status code, latency, error and the first 2 KiB of your response), `lastResponseBody`, and the exact `payload` we signed. ## Resend ```bash curl -s -X POST https://api.tickwire.io/v1/webhooks/wh_91c/deliveries/dlv_4be0…/resend \ -H "X-API-Key: $TW_KEY" -H "Idempotency-Key: $(uuidgen)" -H "X-Reason: replay after outage" ``` This queues the same event (same event id, fresh signature) as a new delivery and returns it with `202`. `POST /v1/events/{eventId}/resend` does the same for every endpoint that received the event (add `?webhookId=` for one). Resend works for 30 days after the event (`410 resend_window_expired` after that) and only while the endpoint is enabled (`409 conflict` otherwise). ## Rotate the secret ```bash curl -s -X POST https://api.tickwire.io/v1/webhooks/wh_91c/rotate-secret \ -H "X-API-Key: $TW_KEY" -H "Idempotency-Key: rotate-2026-09" \ -H "content-type: application/json" -d '{"overlapHours": 24}' ``` The response holds the new `secret` and `standardSecret`, once. For `overlapHours` (0–24, default 24) the old secret stays valid: every delivery carries a signature for each secret in `X-Tickwire-Signatures` and `webhook-signature`, while `X-Tickwire-Signature` switches to the new secret at once. To rotate without dropping a delivery: 1. Rotate. 2. Deploy the new secret to your receiver, verifying against `X-Tickwire-Signatures` or `webhook-signature`. 3. The old secret stops signing when the overlap ends. Send `{"secret": "…"}` (at least 16 characters) to choose the new secret yourself. `POST /v1/webhooks/{id}/reveal-secret` shows the current secret, and the previous one while its overlap lasts. ## Changes and audit `PATCH /v1/webhooks/{id}`, `enable`, `disable`, `rotate-secret`, `reveal-secret` and both resend calls accept `Idempotency-Key` (a replay returns the first response), `X-Actor` and `X-Reason` (percent-encode non-ASCII). Each one is written to your organisation's audit log as a `webhook.*` action. Audit entries never contain secrets. ## Dashboard API The dashboard uses the same operations with a dashboard session instead of an API key. Reads need the `viewer` role and changes need `admin`. The JSON shapes are identical. | Method and path | Use | |---|---| | `GET /dashboard/webhooks` | Endpoints, with a masked secret | | `GET /dashboard/webhooks/catalog` | Event types with example payloads, for the filter picker | | `GET /dashboard/webhooks/{id}/settings` | Status, `disabledReason`, `failingSince`, `lastSuccessAt`, `enabledEvents`, rotation state | | `PATCH /dashboard/webhooks/{id}` | `{enabledEvents?, url?, description?}` | | `POST /dashboard/webhooks/{id}/enable`, `/disable` | Re-enable (for example after an automatic disable), or pause | | `POST /dashboard/webhooks/{id}/rotate-secret` | `{overlapHours?, secret?}`. Show the returned `secret` once | | `GET /dashboard/webhooks/{id}/deliveries` | The delivery table (same filters and cursor as above) | | `GET /dashboard/webhooks/{id}/deliveries/{deliveryId}` | The detail drawer: attempts, response body, payload | | `POST /dashboard/webhooks/{id}/deliveries/{deliveryId}/resend` | The Resend button (`202`) | | `POST /dashboard/webhooks/{id}/test` | Send a `webhook.test` event | Suggested UI: show `status` and `failingSince` on each endpoint, a banner with an Enable button when `disabledReason` is `failing_72h`, and in the delivery table the status, `lastStatusCode`, `lastLatencyMs`, `attempts` and `nextAttemptAt`. Show a Resend button while `resendableUntil` is in the future. --- # Status feed > The public status feed behind the status page, the RSS, Atom and JSON incident feeds, email updates, and how to read them. Source: https://tickwire.io/docs/status-feed/ The [status page](https://tickwire.io/status/) reads one public JSON document from the Tickwire status service. The service runs apart from the API, so it keeps answering when the platform doesn't. You can read the same feed to show Tickwire's status in your own dashboard, or follow incidents in a feed reader. ``` GET https://status.tickwire.io/api/v1/status.json ``` The [status page](https://tickwire.io/status/) shows the feed's current address. Every endpoint on this page is public, needs no key and allows cross-origin reads. **What's available now:** the JSON feed, RSS, Atom and JSON Feed. **Not yet:** email updates. They switch on when an email provider is configured. Until then, subscribing answers [`email_notifications_unavailable`](https://tickwire.io/docs/errors/email_notifications_unavailable/) and the feed says `"subscribe": {"email": false}`. ## What it measures Each component's status comes from real probes run every 30–60 seconds from outside the platform: | Component | Probe | |---|---| | API gateway | the API's front door answers its health check | | Control plane | account and key management answers through the API | | Stream hub | WebSocket streaming answers through the API | | Webhook delivery | every 5 minutes a test event is triggered for a canary organisation, and its correctly signed webhook must arrive within 2 minutes; if the test event cannot be triggered, the component shows unknown, not an outage | | Dashboard | the dashboard page loads | | Website and docs | the website's home page loads | | MT5 trading, MT4 trading | a canary broker account's health, read through the API, is `healthy` and can trade | | Sandbox | a sandbox account's health, read with a sandbox key | A component with no probe set up yet is listed separately as **Not monitored yet** (the feed's `not_monitored` list). We have no evidence either way for it, so it is never shown green or red and it does not count towards the overall status. A probed component with no recent result shows **unknown**, and **no data** in its daily bars. Services we don't run yet are not listed. ## Endpoints | Path | What | |---|---| | `GET /api/v1/status.json[?history_days=N]` | the full feed (N from 0 to 400; default 90) | | `GET /api/v1/summary.json` | the feed without daily history | | `GET /api/v1/components/{id}` | one component | | `GET /api/v1/incidents[?days=14]` | incidents and maintenance, newest first | | `GET /api/v1/incidents/{id}` | one incident, with its postmortem once published | | `GET /api/v1/postmortems` | published postmortems, newest first | | `GET /api/v1/feed.rss` | incidents and maintenance as RSS 2.0 | | `GET /api/v1/feed.atom` | the same as Atom 1.0 | | `GET /api/v1/feed.json` | the same as [JSON Feed 1.1](https://jsonfeed.org/version/1.1) | | `POST /api/v1/subscriptions` | email updates (when available; see below) | The JSON endpoints are cacheable for 15 seconds, the incident feeds for 60. ## Shape (`tickwire.status.v1`) ```json { "schema": "tickwire.status.v1", "generated_at": "2026-09-27T12:00:30Z", "page": { "name": "Tickwire", "url": "https://status.tickwire.io" }, "status": { "indicator": "none", "description": "All Systems Operational" }, "components": [ { "id": "gateway", "name": "API gateway", "group": "Platform", "description": "The public REST and WebSocket entry point.", "region": null, "account_class": null, "status": "operational", "measured_status": "operational", "updated_at": "2026-09-27T12:00:21Z", "probes": [ { "id": "gateway-healthz", "name": "Gateway liveness", "kind": "http", "state": "up", "fresh": true, "checked_at": "2026-09-27T12:00:21Z", "latency_ms": 41.2, "detail": "HTTP 200", "region": null, "account_class": null } ], "uptime": { "24h": 100.0, "7d": 99.98, "30d": null, "90d": null }, "history": [ { "date": "2026-09-26", "uptime_pct": null, "status": "no_data", "samples": { "up": 0, "degraded": 0, "down": 0, "paused": 0 }, "avg_latency_ms": null }, { "date": "2026-09-27", "uptime_pct": 100.0, "status": "operational", "samples": { "up": 2400, "degraded": 0, "down": 0, "paused": 0 }, "avg_latency_ms": 44.0 } ] } ], "not_monitored": [ { "id": "webhooks", "name": "Webhook delivery", "group": "Platform", "description": "Signed webhook events reaching a canary endpoint." } ], "groups": [ { "name": "Platform", "status": "operational", "components": ["gateway"] } ], "regions": [], "account_classes": [], "incidents": { "active": [], "recent": [] }, "maintenances": { "active": [], "upcoming": [] }, "postmortems": [], "subscribe": { "email": false, "rss": "https://status.tickwire.io/api/v1/feed.rss", "atom": "https://status.tickwire.io/api/v1/feed.atom", "json": "https://status.tickwire.io/api/v1/feed.json" }, "power": { "configured": true, "paused": false, "state": "running", "since": null, "checked_at": "2026-09-23T12:00:00Z", "description": null } } ``` | Field | Values | |---|---| | component `status` | `operational`, `degraded_performance`, `partial_outage`, `major_outage`, `under_maintenance`, `unknown` | | component `measured_status` | what the probes alone say; `status` can be worse when we declare an incident, and is better only during a planned pause (see `power`) | | component `in_maintenance` | `true` while a maintenance window covers the component. During maintenance a degraded or partial outage shows as `under_maintenance`; a `major_outage` or `unknown` is always shown as it is, with this flag as the note | | `updated_at` | the newest fresh probe result; `null` when there is none | | `not_monitored` | components with no probe set up yet (`id`, `name`, `group`, `description`). They are not in `components`, `groups` or the overall `status`. Show them as "Not monitored yet", never as up or down. Older feeds lack this field | | day `status` | the component statuses, or `no_data` for a day without a single measurement | | `uptime` | percentages over 24 h, 7, 30 and 90 days; `null` means no data, never 100 | | incident `status` | `investigating`, `identified`, `monitoring`, `resolved`; maintenance: `scheduled`, `in_progress`, `completed` | | incident `impact` | `none`, `minor`, `major`, `critical`, `maintenance` | | incident `automatic` | `true` when our probes opened it | | incident `postmortem` | `null` until a postmortem is published; then when it was published. The text is in `GET /api/v1/incidents/{id}` | | `power.paused` | `true` while the platform is paused on purpose before launch. It wakes on the first request, in about 2 minutes. While paused, components that are asleep show `under_maintenance` and the headline reads "Paused (sleeping to save cost; wakes on first use)". `power.since` is when the pause began | `history` is oldest first and covers 90 days by default. Uptime counts `degraded` as available. A check that finds something down while the platform is paused on purpose counts under `samples.paused` and is left out of every uptime figure: a planned sleep is not downtime. The full JSON Schema is published at [/schemas/status-feed.schema.json](https://tickwire.io/schemas/status-feed.schema.json). ## Truth rules The status page applies these, and we recommend you do the same: 1. If `generated_at` is more than **5 minutes** old, treat everything as `unknown`. 2. A component that says `operational` or `degraded_performance` but whose `updated_at` is more than **5 minutes** old, or missing, is `unknown`. 3. A day with `uptime_pct: null` is "no data", never green. 4. An unrecognised status value is `unknown`. 5. The overall status is the worst component status, and `unknown` ranks worse than `operational`. Only `components` count; `not_monitored` entries never do. With no monitored component at all, the overall status is `unknown`. 6. If the feed can't be fetched, or isn't a `tickwire.status.v1` document, say the feed is unreachable. Don't show the last state you saw as current. ## Incident feeds `feed.rss`, `feed.atom` and `feed.json` carry one entry per incident or maintenance, newest activity first (up to 50). An entry's updated time is its latest update, so your reader shows it again when it changes. Its text lists every update and, once published, links the postmortem. An empty feed means we haven't posted an incident. ## Email updates When email is available (`subscribe.email` is `true`): ```bash curl -X POST https://status.tickwire.io/api/v1/subscriptions \ -H 'content-type: application/json' -d '{"email":"you@example.com"}' ``` - The answer is always `202` with the same body, whether or not the address is already subscribed. - We send a confirmation link. Nothing else is sent until you confirm it. The link expires in 48 hours. - Every incident email has an unsubscribe link. - Limits: 5 requests per hour from one IP address (IPv6: per /64) ([`rate_limited`](https://tickwire.io/docs/errors/rate_limited/)). One address gets at most one confirmation email every 10 minutes and 3 a day, whoever asks. Requests beyond that still get the same `202`, and no email is sent. When email isn't available the endpoint answers `503` [`email_notifications_unavailable`](https://tickwire.io/docs/errors/email_notifications_unavailable/), and its message lists the feed URLs. ## Postmortems After a significant incident we publish a postmortem on the incident's page (`/status/incident/?id=N` on this site). Published postmortems appear in the feed's `postmortems` list and in the incident feeds. None have been published yet. --- # Errors > The error envelope, the codes you'll see, and which ones are safe to retry. Source: https://tickwire.io/docs/errors/ ## The envelope Every error has the same shape: ```json { "error": "not_supported_on_mt4", "message": "Market depth isn't available on MetaTrader 4.", "requestId": "4f6c1d2e9a8b4c7d8e9f0a1b2c3d4e5f", "docUrl": "https://tickwire.io/docs/errors/not_supported_on_mt4" } ``` - `error` is the machine-readable code. `docUrl` opens a short page about it, and [All error codes](#all-error-codes) below lists every code by area. - `requestId` identifies the request. It's also in the `X-Request-ID` header of **every** response, successful or not. Quote it when you contact support: it finds the request in our logs and in the account's audit trail. You can send your own `X-Request-ID` (1 to 128 characters from `A-Z a-z 0-9 . _ : -`). We keep it end to end, from the moment we receive it to the account's terminal. Anything else is replaced with an id we generate. On the `/users/current/…` routes, `error` holds the error name that existing clients for that API style already read (such as `NotFoundError`). Our code is in `code`, and `requestId` and `docUrl` are added: ```json { "id": 1, "error": "NotFoundError", "code": "account_not_found", "message": "Account acc_7Qx not found", "requestId": "4f6c1d2e9a8b4c7d8e9f0a1b2c3d4e5f", "docUrl": "https://tickwire.io/docs/errors/account_not_found" } ``` The `/v1` routes and the terminal routes (`/{mt4|mt5}/{id}/…`) keep their `{error, message, command_id}` shape and add the same two fields. ## HTTP status codes | Status | `error` examples | Retry? | |---|---|---| | 400 | `ValidationError`, `not_supported_on_mt4` | No. Fix the request | | 401 | `unauthorized` | No. Check the key | | 403 | `read_only_key`, `ForbiddenError` | No | | 404 | `not_found`, `symbol_not_found` | No | | 409 | `idempotency_conflict` | No. You reused a key with a different body | | 429 | `TooManyRequestsError` | Yes, after `Retry-After`. See [Rate limits](https://tickwire.io/docs/rate-limits/) | | 502 | `backend_error` (the terminal returned an error) | Reads yes; mutations only with the same idempotency key | | 503 | `not_connected` (no broker link right now) | Yes, with backoff. Check [health](https://tickwire.io/docs/health/) | | 202 | `AcceptedError` (account creation still running) | Yes: same request, same `transaction-id` | ## Provisioning errors Account creation can fail with a `details` code: | Code | Meaning | What to do | |---|---|---| | `E_SRV_NOT_FOUND` | We don't know that server name | Use a suggested name from `details.serversByBrokers`, or upload a server file | | `E_AUTH` | Login, password or server is wrong, or the account is disabled | Check the credentials. We don't charge for these | | `E_SERVER_TIMEZONE` | Couldn't detect the broker's time settings | Create a [provisioning profile](https://tickwire.io/docs/broker-onboarding/) | | `ERR_OTP_REQUIRED` | The broker wants a one-time password | Disable OTP for API access at the broker | | `E_PASSWORD_CHANGE_REQUIRED` | The broker demands a password change | Change it in a terminal, then update the account | ## Trade results `POST /trade` returns **HTTP 200** even when the broker rejects the order, so existing clients keep working. Read `numericCode` and `stringCode`: | Codes | Meaning | |---|---| | 10008, 10009, 10010, 10025 | Success: placed, done, partially done, no changes needed | | 10004 requote, 10006 rejected, 10013–10016 invalid request/volume/price/stops, 10018 market closed, 10019 no money | Refused. Nothing happened | | 10031 connection, and 10011, 10012, 10028, 10039 | **May have executed.** Check `outcome`; see [Idempotency](https://tickwire.io/docs/idempotency/) | | MT4: 128 trade timeout, 146 trade context busy | Same care as 10031 | MT4 accounts return MT5-style codes too, so you only handle one set; the original MT4 code is kept in the message. ## Streaming errors On the WebSocket, errors arrive as frames: ```json { "type": "error", "seq": 88, "error": "invalid_subscription", "message": "timeframe is required for candles" } ``` ## All error codes Each entry gives the HTTP status and whether a retry can help. **Retry: yes** means nothing happened (or it was a read), so repeat the request, after `Retry-After` when there is one. **Retry: no** means the same request gets the same answer, so change something first. **Retry: same key only** means the first attempt may have run, so repeat it only with the same `Idempotency-Key` (or `clientId`). Trading errors also say whether anything reached the broker. Each code also has its own short page at `/docs/errors//`, which is where `docUrl` points. ### Requests and validation Problems with the request itself. Any endpoint can return these. #### `accepted` The same request is still being processed. *HTTP 202 · Retry: same key only* **Likely cause:** A create request with the same transaction-id is still running. **What to do:** Repeat the same request after Retry-After seconds. #### `api_version_unsupported` The API version to pin is older than the oldest supported version. *HTTP 400 · Retry: no* **Likely cause:** The version is past its sunset, or predates every published version. **What to do:** Pin one of metadata.supportedVersions. The pin was not changed. #### `bad_path` The request path is malformed. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely causes:** - The path does not start with '/'. - It has empty, '.' or '..' segments. **What to do:** Fix the URL. #### `bad_request` The request is malformed. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** An invalid header, parameter or body value. **What to do:** Fix the request; the message says what is wrong. #### `body_too_large` The request body exceeds the limit for this endpoint. *HTTP 413 · Retry: no* **Likely cause:** A hold release body over the size limit. **What to do:** Send a smaller body. #### `conflict` The request conflicts with the current state. *HTTP 409 · Retry: no* **Likely cause:** The resource changed or already exists. **What to do:** Re-read the resource, then decide. #### `duplicate` This already exists. *HTTP 409 · Retry: no* **Likely causes:** - The trading account is already linked. - A token id is already in use. **What to do:** Use the existing resource. #### `http_error` An HTTP error with no more specific code. *HTTP 404, 405 · Retry: no* **Likely causes:** - Status page API: the path or method does not exist (a typo in the URL, or the wrong HTTP method). - MCP tool result: the Tickwire API answered with an HTTP error whose body had no code of its own; `message` gives the HTTP status. **What to do:** Check the path and the method. From an MCP tool, read `message` and retry only if the status says it is temporary (429 or 5xx). #### `invalid_api_version` The Tickwire-Version header, or the apiVersion to pin, names no published API version. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely causes:** - The value is not a date in YYYY-MM-DD form. - The date is not one of the published versions (the message and metadata.supportedVersions list them). **What to do:** Send a published version from the versioning page, or omit the header to use your organisation's pinned version. Nothing was sent or changed. #### `invalid_cursor` The pagination cursor is not one this list issued. *HTTP 400 · Retry: no* **Likely causes:** - The cursor was edited, truncated, or taken from a different list endpoint. - The filters changed between pages (a cursor is bound to the list and filters it came from). **What to do:** Start again without cursor, or pass the next_cursor value from the previous page unchanged with the same filters. #### `invalid_parameter` A query or path parameter is invalid; `details` names it. *HTTP 400 · Retry: no* **Likely cause:** A value out of range or of the wrong type. **What to do:** Fix the parameter. #### `invalid_request` The request body is invalid. *HTTP 400 · Retry: no* **Likely cause:** Not a JSON object, or a field fails validation. **What to do:** Fix the body; the message names the field. #### `method_not_allowed` This HTTP method is not supported on this path. *HTTP 405 · Retry: no · Nothing reached the broker* **Likely cause:** For example POST on a read-only route. **What to do:** Check the API reference. #### `missing_header` A required header is missing. *HTTP 400 · Retry: no* **Likely causes:** - X-Actor, X-Reason or Idempotency-Key is missing on a mutating call. - X-Actor, X-Reason or Idempotency-Key is missing when changing the API version pin. **What to do:** Send the headers named in the message. #### `not_found` No such endpoint or resource. *HTTP 404 · Retry: no* **Likely cause:** A wrong path or id. **What to do:** Check the URL and ids. #### `not_implemented` This is not implemented here. *HTTP 501 · Retry: no* **Likely cause:** A feature this backend or platform does not provide. **What to do:** Check the platform notes. #### `payload_too_large` The request body is too large. *HTTP 413 · Retry: no · Nothing reached the broker* **Likely cause:** A body over our size limit. **What to do:** Send less data per request. #### `rate_limited` Too many requests. *HTTP 429 · Retry: yes · Nothing reached the broker* **Likely causes:** - The per-key, per-account, per-account trade or per-IP budget is used up (metadata.bucket names it). - A heavy call (history, batch, stream connect) costs more than one unit. - Too many sandbox sign-ups from one address in an hour or a day, or from everyone in an hour (POST /v1/sandbox/signup). **What to do:** Wait for Retry-After, then retry. A refused trade carries sent: false: it was not sent, so it is safe to resend. See the rate-limits page. #### `request_body_timeout` The request body did not arrive in time; nothing was forwarded. *HTTP 408 · Retry: yes · Nothing reached the broker* **Likely cause:** The client sent the body too slowly (inbound provider webhooks allow 10 seconds by default). **What to do:** Send the whole body promptly, then retry. #### `unsupported_media_type` The request body has an unsupported content type. *HTTP 415 · Retry: no · Nothing reached the broker* **Likely cause:** Not application/json. **What to do:** Send JSON with Content-Type: application/json. #### `validation_error` The request failed validation. *HTTP 400, 422 · Retry: no · Nothing reached the broker* **Likely cause:** A missing field, a wrong type or an out-of-range value. **What to do:** Fix the fields named in `details` or the message. #### `window_too_large` The time window is too large for one call. *HTTP 400 · Retry: no* **Likely cause:** More than 31 days requested. **What to do:** Page by time. ### Keys, tokens and permissions The key or token is missing, wrong, or not allowed to do this. See [Authentication](https://tickwire.io/docs/authentication/). #### `account_forbidden` This token is scoped to other accounts. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely cause:** An account-scoped token was used for an account outside its scope. **What to do:** Use a token that covers this account. #### `agent_key_not_found` No agent key with this id exists in your organisation. *HTTP 404 · Retry: no* **Likely cause:** Wrong id, or the key was deleted. **What to do:** List agent keys and use an existing id. #### `api_key_expired` The API token that sent this order has expired. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely cause:** The token passed its expiry while the order was pending. **What to do:** Create a new token. Nothing was sent. #### `api_key_revoked` The API key or token that sent this order was revoked or deleted. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely cause:** The key was revoked, possibly while the order was held. **What to do:** Use a current key. Nothing was sent. #### `forbidden` Your credential may not do this. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely causes:** - A read-only key on a mutating route. - Your role lacks the permission. **What to do:** Use a credential with the needed access. #### `invalid_actor` X-Actor names a server-assigned identity that is not the calling credential's own. Nothing was changed. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** The value starts with api-key:, user: or firebase: but is not api-key: (or, for a signed-in user, your own firebase: id). **What to do:** Send a free-text label (for example copier-7 or ops:jane), your own api-key:, or no X-Actor. The audit log always records the calling credential's key_id separately. #### `invalid_agent_key` The agent key is missing, invalid or revoked. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely cause:** No X-Tickwire-Agent-Key header, or a revoked key. **What to do:** Send a valid agent key (twag_...). #### `invalid_token` The token is invalid, expired or revoked. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely cause:** A typo, or the token was revoked or expired. **What to do:** Use a current token. Repeated bad tokens from one IP are rate limited. #### `ip_not_allowed` The token is valid, but it has an IP allowlist and this request came from an address outside it. The message never shows the allowlist. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely causes:** - The call came from a server or network that is not on the token's allowlist. - Your public IP changed (a new office line, VPN, NAT or cloud egress address). - The allowlist was narrowed; open WebSockets using the token are closed (code 1008) at the next re-check. **What to do:** Call from an address on the allowlist, or create a token whose allowlist includes this address. Retrying from the same address will not help. #### `method_access` This token may not call this method. *HTTP 403 · Retry: no* **Likely causes:** - An account-access token on an account-management method. - A token without the needed application or role. **What to do:** Use an owner credential or a token with the role. #### `missing_agent_key` The MCP endpoint needs a Tickwire agent key, and none was sent. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely causes:** - No `Authorization: Bearer …` header. - The bearer value is not an agent key (agent keys start with `twag_`). **What to do:** Create an agent key in the dashboard and send it as `Authorization: Bearer twag_…`. #### `missing_credentials` The MCP endpoint was called without a sign-in or an agent key. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely causes:** - The AI app has not signed in with Tickwire yet. - No `Authorization: Bearer …` header (or `X-Tickwire-Agent-Key`) was sent. **What to do:** Sign in with Tickwire from the AI app (it follows the `WWW-Authenticate` header in this answer), or send an agent key as `Authorization: Bearer twag_…`. #### `missing_token` No token was sent. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely cause:** No auth-token, X-API-Key, Authorization: Bearer or ?auth-token= (WebSockets). **What to do:** Send your token. #### `not_revealable` Key values are shown only once, at creation (or rotation), and stored hashed. *HTTP 400 · Retry: no* **Likely cause:** An attempt to reveal an existing full, read-only or sandbox key: only a digest is stored. **What to do:** Create a new key if you lost it, or rotate a read-only key to get a new value. #### `read_only_key` This key is read-only; it can't trade. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely cause:** A read-only API key or agent key sent an order. **What to do:** Use a full key. #### `read_only_token` This token is read-only. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely cause:** A read-only token on a mutating route. **What to do:** Use a token with write access. #### `too_many_connections` Too many concurrent WebSockets for this token. *HTTP 429 · Retry: yes* **Likely cause:** More connections than the per-token limit. **What to do:** Close unused connections or multiplex subscriptions over one. #### `unauthorized` Missing or invalid credentials. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely cause:** No key, a wrong key, or a revoked key. **What to do:** Send a valid key. ### Accounts and terminals The trading account or its terminal can't serve the request right now. See [Health](https://tickwire.io/docs/health/). #### `account_deploying` The account's terminal is starting. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** The account was just deployed or redeployed. **What to do:** Retry after Retry-After. The request was not sent. #### `account_not_deployed` The account exists but has no running terminal. *HTTP 404 · Retry: no · Nothing reached the broker* **Likely cause:** The account is undeployed, parked, or its deployment failed. **What to do:** Deploy the account, then retry. Its health routes still answer (200, status down, with the state and reason code), so read GET /users/current/accounts/{id}/health to see why it is not running. #### `account_not_found` No trading account with this id belongs to you. *HTTP 404 · Retry: no · Nothing reached the broker* **Likely causes:** - A typo in the account id. - The account belongs to another tenant (we answer 404, not 403, so ids are not disclosed). - The account was deleted. **What to do:** List your accounts and use one of their ids. #### `account_unreachable` The account's terminal could not be reached. *HTTP 502, 503 · Retry: yes · Nothing reached the broker* **Likely causes:** - The terminal is down or restarting. - The account is not deployed. **What to do:** Retry after Retry-After. We only return this when nothing was sent. #### `backend_error` The terminal returned an error for this operation; the MetaTrader code is in `code` or `mt5Code`. *HTTP 500, 502 · Retry: same key only · May have executed* **Likely causes:** - The terminal refused or failed the call. - The connection to the terminal failed mid-call. **What to do:** Reads: retry. Trades: do not resend blindly; repeat only with the same Idempotency-Key, which answers with the real outcome. #### `broker_offset_unknown` The broker's UTC offset is not known yet, so UTC times can't be given. *HTTP 503 · Retry: yes* **Likely cause:** No live ticks since the terminal started (weekend, closed market). **What to do:** Retry shortly, or omit timeBasis=utc to get broker time. #### `broker_time_unknown` The broker's server time is not known yet. *HTTP 503 · Retry: yes* **Likely cause:** No live ticks since the terminal started. **What to do:** Retry after Retry-After. #### `not_connected` The terminal has no broker connection right now. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely causes:** - The terminal is starting or reconnecting. - The broker server is unreachable or rejected the login. **What to do:** Retry with backoff and check the account's health. A trade answered with this was not sent. #### `terminal_timeout` The terminal did not answer a read in time. *HTTP 504 · Retry: yes* **Likely cause:** The terminal is busy or stuck. **What to do:** Retry the read. #### `unknown_account` An account id in the request is not yours. *HTTP 400 · Retry: no* **Likely cause:** A wrong id in account_ids. **What to do:** Use ids from your account list. #### `unknown_host` No Tickwire service is served at this hostname. *HTTP 404 · Retry: no · Nothing reached the broker* **Likely cause:** A wrong base URL. **What to do:** Use the hostnames from the docs. #### `unknown_region` This region is not served. *HTTP 404 · Retry: no · Nothing reached the broker* **Likely cause:** A wrong region in a regional API hostname. **What to do:** Use a served region. ### Orders and idempotency Order checks and `Idempotency-Key` handling. See [Idempotency](https://tickwire.io/docs/idempotency/). #### `idempotency_conflict` This Idempotency-Key was already used with a different request body. *HTTP 409 · Retry: no · Nothing reached the broker* **Likely cause:** A key was reused for a new request. **What to do:** Use a new key for a new request; the earlier one stands. #### `idempotency_in_flight` A request with this Idempotency-Key is still running. This request was not sent (`sent: false`); the earlier one may still execute. *HTTP 409 · Retry: same key only · May have executed* **Likely cause:** A retry arrived before the first attempt finished, for example after a gateway timeout (504) or a client-side timeout. **What to do:** Wait Retry-After seconds, then repeat with the same key: once the first attempt finishes you get its stored result. Never switch to a new key while the outcome is open, and check positions and orders (or the trade status by key) first. #### `idempotency_key_required` Every trade needs an Idempotency-Key. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** The header is missing or too long. **What to do:** Send a unique Idempotency-Key. #### `idempotency_key_reused` This Idempotency-Key was used for a different order, account or batch; this request was not sent. *HTTP 409, 422 · Retry: no · Nothing reached the broker* **Likely cause:** A key was reused for a new request. **What to do:** Use a new key; the earlier request stands. #### `idempotency_unavailable` Idempotency can't be guaranteed right now, so nothing was sent. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely causes:** - The idempotency store is unavailable. - The idempotency store is full of requests that are still running. **What to do:** Retry after Retry-After, or drop the header to trade without idempotency. #### `invalid_batch` The batch request is invalid; nothing was sent. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** A malformed leg or a missing field. **What to do:** Fix the batch; the message names the field. #### `invalid_idempotency_key` The Idempotency-Key (or `transaction-id` header) is longer than 255 characters or holds non-printable characters. Nothing was changed. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** A key built from long ids, or one carrying control characters, tabs or bidi marks. **What to do:** Send 1 to 255 printable characters. Keys are never truncated, so two long keys can't collide. #### `invalid_order` The order is invalid; nothing was sent. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** A missing or malformed order field. **What to do:** Fix the order; the message names the field. #### `order_not_found` No pending order with this id. *HTTP 404 · Retry: no* **Likely cause:** It filled, was cancelled, or the id is wrong. **What to do:** Check history for it. #### `position_not_found` No open position with this id. *HTTP 404 · Retry: no* **Likely cause:** It was closed, or the id is wrong. **What to do:** Check history for it. #### `reason_required` Every trade needs a reason (X-Reason). *HTTP 400 · Retry: no · Nothing reached the broker* **Likely causes:** - The X-Reason header is missing. - An MCP trading tool was called without a `reason`. **What to do:** Say why in X-Reason (or the MCP tool's `reason`). #### `reason_too_long` The reason is too long. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** X-Reason over the limit. **What to do:** Shorten it. #### `request_log_not_found` There is no request log entry with this id in your organisation. *HTTP 404 · Retry: no* **Likely causes:** - The id is mistyped, or belongs to another organisation. - The entry is older than 14 days, or was removed to keep the organisation within its request-log limits. **What to do:** List recent calls with GET /v1/request-logs (filter by requestId) and use an id from there. #### `request_not_found` No trade was recorded under this Idempotency-Key. *HTTP 404 · Retry: no* **Likely cause:** Nothing was sent with it, or it was refused before sending. **What to do:** It is safe to send the order with this key. #### `timeout` No answer in time: a batch leg's status, or a pre-trade hook's `error` in webhook events. For a batch leg the order may have executed. *Not an HTTP error · Retry: same key only · May have executed* **Likely causes:** - The terminal or broker did not reply in time. - Your pre-trade hook did not answer in time. **What to do:** Batch legs: never resend blindly; repeat the batch with the same Idempotency-Key, or check positions and history. Hooks: make the hook answer faster. #### `unreachable_account` Some accounts in the batch have no terminal; nothing was sent. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** Accounts undeployed or their terminals down. **What to do:** Deploy them or drop them from the batch. ### Pre-trade hooks, holds and kill switches Your own pre-trade hook, orders it holds, and the kill switch. #### `approval_belongs_to_the_hook` Only the pre-trade hook that placed a hold can approve it. *HTTP 403 · Retry: no* **Likely cause:** An owner or another hook tried to approve the hold. **What to do:** Approve from the holding hook, or reject as the owner. #### `hold_expired` A held order expired before a decision; it was not and will not be executed. *HTTP 409 · Retry: no · Nothing reached the broker* **Likely cause:** The pre-trade hook did not approve in time. **What to do:** Send a new order with a new Idempotency-Key if still wanted. #### `hold_not_found` No such hold. *HTTP 404 · Retry: no* **Likely cause:** Wrong hold id. **What to do:** Check the id. #### `hold_rejected` A held order was rejected by the pre-trade hook or the owner; nothing was sent. *HTTP 409 · Retry: no · Nothing reached the broker* **Likely cause:** The hook or owner rejected the hold. **What to do:** Read the message for why. #### `hook_denied` The account owner's pre-trade hook denied this order; nothing was sent. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely cause:** The order broke a rule the hook enforces. **What to do:** Read `hook_message`. #### `hook_exists` This account or agent key already has a pre-trade hook. *HTTP 409 · Retry: no* **Likely cause:** A second hook was created. **What to do:** Update or delete the existing hook. #### `hook_not_found` No such pre-trade hook. *HTTP 404 · Retry: no* **Likely cause:** Wrong id. **What to do:** Check the id. #### `hook_not_holding` This hook did not place this hold. *HTTP 403 · Retry: no* **Likely cause:** A different hook tried to release the hold. **What to do:** Release from the hook that holds it. #### `hook_unavailable` The pre-trade hook didn't give a valid answer. The hook fails closed, so the order wasn't sent. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** The hook URL is down, slow or answered invalidly. **What to do:** Fix the hook, then send the order again. #### `invalid_hook` The pre-trade hook definition is invalid. *HTTP 400 · Retry: no* **Likely cause:** A hook on an agent key must apply to agents only. **What to do:** Fix the hook body. #### `invalid_hook_url` The pre-trade hook URL is not allowed. *HTTP 400 · Retry: no* **Likely cause:** Not https, or it points to a private address. **What to do:** Use a public https URL. #### `invalid_signature` A hold release was not signed with the holding hook's secret. *HTTP 401 · Retry: no* **Likely cause:** Wrong secret, missing headers, or a stale timestamp. **What to do:** Sign with X-Tickwire-Hook-Id, X-Tickwire-Timestamp and X-Tickwire-Signature. #### `kill_switch_engaged` The kill switch for this account or agent key is engaged; nothing was sent. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely cause:** The owner engaged the kill switch (`scope`, `kill_reason`). **What to do:** The owner must release the kill switch. #### `pretrade_unavailable` The pre-trade check (pre-trade hooks) could not be completed, so the order was not sent. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** Our API or the pre-trade hook service is unreachable or slow. **What to do:** Retry after Retry-After with the same Idempotency-Key. #### `TICKWIRE_HELD` A pre-trade hook is holding this order; nothing has been sent yet (`stringCode` of a streaming `TradeError`). *WebSocket error frame · Retry: no · Nothing reached the broker* **Likely cause:** Your pre-trade hook answered with a hold instead of allow or deny. **What to do:** Do not resend. Wait for the hook to release or reject the hold before `metadata.expiresAt`; `metadata.holdId` identifies it. #### `unknown_actor` The original caller of a held order can't be verified; nothing was sent. *HTTP 401 · Retry: no · Nothing reached the broker* **Likely cause:** The credential that sent it no longer exists. **What to do:** Send the order again with a current credential. ### Market data and platform support Prices, candles and depth, and things one MetaTrader version can't do. #### `candle_unavailable` No candle is available for this symbol and timeframe. *HTTP 404 · Retry: yes* **Likely cause:** The symbol has no history in the terminal for that timeframe yet. **What to do:** Retry later or use another timeframe. #### `depth_unavailable` The terminal has no market depth for this symbol. *HTTP 404 · Retry: no* **Likely cause:** The broker does not publish depth for the symbol. **What to do:** Use quotes instead. #### `not_supported_on_mt4` MetaTrader 4 doesn't support this. *HTTP 400, 501 · Retry: no · Nothing reached the broker* **Likely cause:** Market depth, tick history, stop-limit orders, OrderCheck and other MT5-only features. **What to do:** Use an MT5 account for this feature. Nothing was sent. #### `not_supported_on_mt5` MetaTrader 5 can't do this. *HTTP 400, 501 · Retry: no · Nothing reached the broker* **Likely cause:** An MT4-only feature asked of an MT5 account. **What to do:** Use the MT5 equivalent. Nothing was sent. #### `symbol_not_found` The terminal doesn't know this symbol. *HTTP 404 · Retry: no · Nothing reached the broker* **Likely cause:** A typo, or the broker names it differently (suffixes such as .m or -ECN). **What to do:** List symbols and use the broker's exact name. #### `too_many_requests` All concurrent market-data request slots for this account are in use. *HTTP 429 · Retry: yes* **Likely cause:** Too many parallel history or market-data calls. **What to do:** Wait for Retry-After, or send fewer calls at once. ### Streaming Most of these arrive as WebSocket error frames (`type: error`), not HTTP statuses. See [Streaming](https://tickwire.io/docs/streaming/). #### `invalid` The subscription frame on the terminal WebSocket (`/{mt4|mt5}/{id}/ws`) is invalid. *WebSocket error frame · Retry: no* **Likely causes:** - Unknown topic. - A prices or bars topic without a symbol. **What to do:** Fix the subscription frame. #### `invalid_message` A WebSocket frame is not a valid message (sent as an error frame, not an HTTP status). *WebSocket error frame · Retry: no* **Likely cause:** Not JSON, not an object, an unknown type, or a bad field. **What to do:** Fix the frame; the message names the field. #### `invalid_subscription` A market-data subscription is invalid (sent as an error frame). *WebSocket error frame · Retry: no* **Likely cause:** Unknown market data type, or a bad interval or timeframe. **What to do:** Fix the subscription. #### `market_depth_unavailable` The terminal gave no market depth for the symbol (stream error frame). *WebSocket error frame · Retry: no* **Likely cause:** The broker does not publish depth for it. **What to do:** Unsubscribe from marketDepth for this symbol. #### `not_subscribed` Unsubscribe without a subscription (stream error frame). *WebSocket error frame · Retry: no* **Likely cause:** An unsubscribe before subscribe. **What to do:** Subscribe first. #### `not_supported` This terminal backend does not provide the requested stream (stream error frame). *WebSocket error frame · Retry: no* **Likely cause:** Market depth on a backend without it. **What to do:** Unsubscribe from it. #### `NotAuthenticatedError` Error name in a streaming error: the account's terminal is not connected, or the account is not subscribed on this connection. *WebSocket error frame · Retry: yes* **Likely causes:** - The terminal is starting, reconnecting or stopped. - A request for an account this connection has not subscribed to. **What to do:** Subscribe to the account first. If it is subscribed, wait for the terminal to connect (see [Health](https://tickwire.io/docs/health/)) and retry. #### `TimeoutError` Error name in a streaming error: the terminal did not answer in time. *WebSocket error frame · Retry: same key only* **Likely causes:** - The terminal or the broker is slow. - A wait for synchronization ran past its timeout. **What to do:** Repeat reads. Repeat a trade only with the same `requestId`, which returns the real outcome. #### `too_many_sessions` Too many stream sessions for this account (error frame, then the socket closes). *WebSocket error frame · Retry: yes* **Likely cause:** More sessions than allowed per account. **What to do:** Reuse one session. #### `TradeError` Error name in a streaming error: the trade was refused or is being held. `stringCode` says which, and `metadata.sent` says whether anything reached the broker. *WebSocket error frame · Retry: no* **Likely causes:** - A pre-trade hook is holding the order (`stringCode: TICKWIRE_HELD`). - The order failed a check or the broker refused it. **What to do:** Read `stringCode`, `message` and `metadata`, fix the order if needed, and send a new one only if `metadata.sent` is false. #### `upstream_refused` The upstream refused the WebSocket. *HTTP 400, 401, 403, 404, 409, 429, 502 · Retry: no* **Likely cause:** The upstream answered the upgrade with an error status. **What to do:** Check the path and the subscription. ### Webhooks Webhook endpoints, test events and deliveries. Some are values in a delivery record rather than HTTP errors. See [Webhooks](https://tickwire.io/docs/webhooks/). #### `endpoint_deleted` A webhook delivery was abandoned because its endpoint was deleted (the delivery's `error`, not an HTTP status). *Not an HTTP error · Retry: no* **Likely cause:** The webhook endpoint was deleted while deliveries were still queued. **What to do:** Nothing to do. Create a new endpoint to receive future events. #### `endpoint_disabled` A webhook delivery was abandoned because its endpoint is disabled (the delivery's `error`, not an HTTP status). *Not an HTTP error · Retry: no* **Likely causes:** - You disabled the endpoint. - We disabled it after it kept failing (for example 72 hours of failures). **What to do:** Fix the endpoint, re-enable it, then resend the events you missed while they are inside the resend window. #### `event_expired` A webhook delivery was abandoned because the event is past its retention (the delivery's `error`, not an HTTP status). *Not an HTTP error · Retry: no* **Likely cause:** The endpoint stayed down longer than events are kept. **What to do:** Reconcile from the API (positions, orders, history) instead of waiting for the event. #### `invalid_url` The webhook URL is not allowed. The message is the same whatever rule refused it. *HTTP 400 · Retry: no* **Likely causes:** - Not https://. - The host is localhost, *.localhost, *.internal or *.local, or the URL carries a username or password. - The host is, or resolves to, a non-public address (loopback, private, link-local, carrier-grade NAT, multicast, reserved), or cannot be resolved. - Re-enabling an endpoint whose URL breaks these rules. **What to do:** Use an https URL whose host resolves only to public internet addresses. #### `resend_window_expired` The webhook event is too old to resend. *HTTP 410 · Retry: no* **Likely cause:** A resend was asked for an event outside the resend window. **What to do:** Reconcile from the API instead of resending. #### `unknown_event_type` The webhook event type is not in the event catalog. *HTTP 400 · Retry: no* **Likely causes:** - Triggering a test event (POST /v1/webhook-events/trigger) with a type that does not exist. - Filtering a webhook listener's events with a type or family that does not exist. **What to do:** Use a type from GET /v1/webhook-event-types, or a family wildcard such as trade.*. #### `url_not_allowed` A webhook delivery was not sent because the endpoint's URL failed our egress rules at send time (the delivery's `lastError`, and an endpoint's `disabledReason`; not an HTTP status). *Not an HTTP error · Retry: no* **Likely causes:** - The host now resolves to a non-public address (for example after a DNS change). - The URL was registered before the rules applied and is not https://, or names an internal host or address; such endpoints are disabled. **What to do:** Point the endpoint at an https URL that resolves only to public addresses, re-enable it, then resend missed events inside the resend window. #### `webhook_trigger_sandbox_only` On a live key only webhook.test can be triggered; other test events are sandbox-only. *HTTP 403 · Retry: no* **Likely cause:** POST /v1/webhook-events/trigger with a live key and an event type other than webhook.test. **What to do:** Use a sandbox key (POST /v1/sandbox/keys) to trigger other event types, so a test trade never reaches a production handler. #### `webhook_unavailable` The test event was published, but the webhook pipeline could not store or queue it, so your endpoints will not receive it. *HTTP 503 · Retry: yes* **Likely cause:** POST /v1/webhook-events/trigger while webhook storage or the delivery queue is failing. **What to do:** Retry later with a new Idempotency-Key. Running tickwire listen sessions still received the event. If it persists, check the status page and contact support with the requestId. ### Outages and timeouts Something inside Tickwire, or between Tickwire and the terminal, failed or was slow. The [status page](https://tickwire.io/status/) shows known incidents. #### `agent_gateway_misconfigured` The agent API is not available right now. *HTTP 503 · Retry: no · Nothing reached the broker* **Likely cause:** A required server setting is missing. **What to do:** Contact support with the requestId. #### `authorization_server_unreachable` The MCP endpoint could not reach the Tickwire sign-in service to check the access token. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** A network problem, or the sign-in service is restarting. **What to do:** Retry after a few seconds. The [status page](https://tickwire.io/status/) shows known incidents. #### `authorization_unavailable` The Tickwire sign-in service could not check the access token right now. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** The sign-in service answered with an unexpected error. **What to do:** Retry after a few seconds. If it keeps happening, sign in again from the AI app. #### `bad_gateway` An upstream service gave an invalid answer. *HTTP 502 · Retry: same key only · May have executed* **Likely cause:** A service between our API and the terminal failed. **What to do:** Reads: retry. Mutations: repeat only with the same Idempotency-Key. #### `bad_response` The Tickwire API answered the MCP tool without a JSON body. *MCP tool result · Retry: same key only* **Likely cause:** Something in front of the API answered instead of it, for example during a restart. **What to do:** Repeat reads. For a trade, call `get_trade_status` with the same `idempotency_key` before sending it again. #### `controlplane_unavailable` We could not check your token or route the request. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** An internal service is restarting or overloaded. **What to do:** Retry after Retry-After. Nothing was sent. #### `docs_unavailable` The MCP docs search could not fetch the Tickwire docs. *MCP tool result · Retry: yes* **Likely cause:** The docs site was unreachable or slow. **What to do:** Try the search again later, or read the docs at [/docs/](https://tickwire.io/docs/). #### `execution_unavailable` A trade sent over streaming could not reach the execution service, so it was not sent (`stringCode` of a streaming `InternalError`). *WebSocket error frame · Retry: yes · Nothing reached the broker* **Likely cause:** A short outage inside Tickwire. **What to do:** Retry with the same `requestId`. #### `gateway_timeout` An upstream did not answer in time. *HTTP 504 · Retry: same key only · May have executed* **Likely cause:** The terminal or a service is slow or stuck. **What to do:** Reads: retry. Mutations: the outcome is unknown; repeat only with the same Idempotency-Key. #### `internal_error` An unexpected failure inside Tickwire. *HTTP 500 · Retry: same key only · May have executed* **Likely cause:** A bug or an unexpected state. **What to do:** Reads: retry. Mutations: repeat only with the same Idempotency-Key. If the answer has created_id, a credential (key, token or hook secret) was created before the failure: revoke or rotate it by that id. Report the requestId if it persists. #### `outcome_unknown` A trade sent over streaming got no answer from the execution service; it may have executed (`stringCode` of a streaming `InternalError`). *WebSocket error frame · Retry: same key only · May have executed* **Likely cause:** The execution service or the terminal did not answer in time. **What to do:** Retry with the same `requestId` to learn the real outcome. Never send a new trade blindly. #### `service_unavailable` The service is not available right now. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** Not available yet, or restarting. **What to do:** Retry later. Nothing was sent. #### `temporarily_unavailable` The service could not answer just now; nothing was changed. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely causes:** - A read could not reach the database, even after one retry on a fresh connection (listings such as connected apps and dedicated IPs). - OAuth (Sign in with Tickwire): client registration is at capacity. **What to do:** Retry after Retry-After seconds (when sent), or later. #### `tickwire_no_reply` The MCP tool sent the request but got no reply. If it was a trade, it may have executed. *MCP tool result · Retry: same key only · May have executed* **Likely cause:** The connection dropped or timed out after the request was sent. **What to do:** For a trade, call `get_trade_status` with the same `idempotency_key` before doing anything else. Reads can be repeated. #### `tickwire_unreachable` The MCP tool could not reach the Tickwire API, so nothing was sent. *MCP tool result · Retry: yes · Nothing reached the broker* **Likely causes:** - A network problem between the MCP server and the API. - A wrong API address in a locally run MCP server's settings. **What to do:** Retry the tool. If it keeps happening, check the [status page](https://tickwire.io/status/), and for a local MCP server check the API address it uses. #### `unavailable` A dependent feature isn't running right now. *HTTP 503 · Retry: yes* **Likely cause:** Webhook delivery is not running. **What to do:** Try again later. #### `upstream_misconfigured` The account's terminal refused our API. *HTTP 502 · Retry: no · Nothing reached the broker* **Likely cause:** An internal credential mismatch. **What to do:** Contact support with the requestId. #### `upstream_timeout` The upstream did not answer in time. For a mutating request the outcome is unknown (`metadata.outcome: unknown`): it may have executed. *HTTP 504 · Retry: same key only · May have executed* **Likely cause:** The terminal or broker is slow. **What to do:** Never resend a trade blindly: repeat it with the same Idempotency-Key (or clientId) to learn the real outcome. Reads can be retried. #### `upstream_unavailable` A Tickwire service is unreachable; the request was not sent. *HTTP 502 · Retry: yes · Nothing reached the broker* **Likely cause:** The service is restarting. **What to do:** Retry after Retry-After. #### `waking_up` Tickwire was paused to save cost while nobody was using it, and your request started it again. Starting takes about 2 minutes. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely cause:** The first request after a quiet period (only before launch: the automatic sleep is off once trading customers are live). **What to do:** Retry after Retry-After (30 seconds). In a browser the page reloads itself. ### Billing, slots and dedicated IPs Payments, discount codes, account slots and dedicated IPs. #### `already_subscribed` The organisation already has a subscription. *HTTP 409 · Retry: no* **Likely cause:** A second checkout was started. **What to do:** Use Manage billing to change the plan. #### `bad_discount_code` The discount code is unknown or can't be used here. *HTTP 400 · Retry: no* **Likely cause:** A typo, an expired code, or a code for another product. **What to do:** Check the code. #### `bad_signature` A billing webhook's signature did not verify. *HTTP 400 · Retry: no* **Likely causes:** - Wrong webhook secret. - The body was changed in transit. **What to do:** Check the webhook secret configured at the payment provider. #### `checkout_unavailable` Payments are not available right now. *HTTP 503 · Retry: yes* **Likely cause:** The payment provider is not configured or not reachable. **What to do:** Try again later. #### `dedicated_ip_refused` The dedicated-IP change can't be made. *HTTP 409 · Retry: no* **Likely causes:** - The requested count is above what the plan allows. - An IP is still in use by an account. **What to do:** Read the message; change the count or free the IP. #### `discount_too_large` The discount code gives more off than allowed. *HTTP 400 · Retry: no* **Likely cause:** The code takes more off than we accept for this order. **What to do:** Use another code. #### `insufficient_balance` The wallet balance does not cover this purchase. *HTTP 402 · Retry: no* **Likely cause:** Not enough prepaid balance; `shortfall_eur_cents` says how much is missing. **What to do:** Top up, then repeat. #### `ip_allocation_refused` The dedicated-IP operation can't be done in the IP's current state. *HTTP 409 · Retry: no* **Likely cause:** For example, confirming cancellation before release. **What to do:** Follow the order in the message. #### `ip_previously_owned` This IP has had an owner before; a dedicated IP is never reassigned. *HTTP 409 · Retry: no* **Likely cause:** An attempt to allocate a previously held IP. **What to do:** Allocate a fresh IP. #### `no_subscription` There is no subscription to manage yet. *HTTP 409 · Retry: no* **Likely causes:** - Manage billing was opened before any subscription. - Cancel or resume was asked for without a subscription to cancel. **What to do:** Start a subscription first. #### `payment_provider_error` The payment provider failed the call. *HTTP 502 · Retry: yes* **Likely cause:** The provider is down or refused; `provider_code` has its code. **What to do:** Try again later. #### `server_limit_reached` The maximum number of private servers is reached. *HTTP 409 · Retry: no* **Likely cause:** A plan limit. **What to do:** Delete a server or raise the limit. #### `slots_full` Every purchased slot is taken. *HTTP 409 · Retry: no* **Likely cause:** Linking an account without a free slot. **What to do:** Buy a slot or unlink an account. ### Sandbox Limits on sandbox keys and accounts. See [Sandbox](https://tickwire.io/docs/sandbox/). #### `sandbox_account_limit` Your sandbox already holds its maximum number of accounts (5 by default). *HTTP 403 · Retry: no · Nothing reached the broker* **Likely cause:** Creating a sixth account with a sandbox (twsk_) key. **What to do:** Delete a sandbox account you no longer need, then create the new one. #### `sandbox_key_limit` Your sandbox already holds its maximum number of active credentials of this kind (5 sandbox keys; 20 each of API tokens, read-only keys and agent keys by default). *HTTP 403 · Retry: no · Nothing reached the broker* **Likely causes:** - Creating another sandbox key (dashboard quickstart or POST /v1/sandbox/keys) while the sandbox holds the maximum. - Creating another API token, read-only key or agent key with a sandbox key or token while the sandbox holds the maximum of that kind. **What to do:** Revoke a sandbox credential of that kind you no longer need on the dashboard, then create the new one. #### `sandbox_key_required` Server Tickwire-Sandbox is only for sandbox keys; sandbox and live never mix. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** Creating an account on server Tickwire-Sandbox with a live key. **What to do:** Get a twsk_ key with POST /v1/sandbox/keys (or /v1/sandbox/signup) and use it. #### `sandbox_key_restricted` This sandbox key came from anonymous sign-up: it may manage its sandbox accounts, trade, stream and read, nothing else. *HTTP 403 · Retry: no · Nothing reached the broker* **Likely causes:** - Creating a webhook, pre-trade hook, agent key, API key or token, or another sandbox key with a key from POST /v1/sandbox/signup. - Creating, changing or deleting a risk-management tracker or guard rule (or resetting trading statistics) with such a key. Reading trackers, statistics and metrics stays allowed. - A sandbox key whose restrictions we could not confirm, on a risk-management write (it fails closed). **What to do:** Sign in, then create a sandbox key with POST /v1/sandbox/keys using your live key; it has full rights inside your sandbox. #### `sandbox_server_required` A sandbox key can only create simulated accounts. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** Creating an account on a real broker server with a sandbox (twsk_) key. **What to do:** Use server Tickwire-Sandbox and a magic login, or use a live key for a broker account. ### Sign-in and organisations Dashboard sign-in, invites and organisation members. #### `already_member` The person is already a member of the organisation. *HTTP 409 · Retry: no* **Likely cause:** An invite was sent to an existing member. **What to do:** Nothing to do. #### `email_taken` An account with this email already exists. *HTTP 409 · Retry: no* **Likely cause:** Sign-up with a registered email. **What to do:** Sign in instead. #### `invalid_credentials` Email or password is wrong. *HTTP 401 · Retry: no* **Likely cause:** Wrong password. **What to do:** Check the credentials, or use a magic link. #### `invalid_email` The email address is not valid. *HTTP 400 · Retry: no* **Likely cause:** A typo. **What to do:** Enter a valid email address. #### `invalid_link` The sign-in or invite link is invalid or expired. *HTTP 401 · Retry: no* **Likely cause:** The link was used already or is too old. **What to do:** Request a new link. #### `last_owner` An organisation needs at least one owner. *HTTP 409 · Retry: no* **Likely cause:** Removing or demoting the last owner. **What to do:** Promote another member first. #### `no_org` No organisation is selected. *HTTP 400 · Retry: no* **Likely cause:** A dashboard session without an active organisation. **What to do:** Select or create an organisation. #### `sign_in_required` This invite link only works once you are signed in with the invited email address. *HTTP 403 · Retry: no* **Likely cause:** An invite link shared by hand was opened while signed out. **What to do:** Sign in or sign up with the invited address, then open the link again. #### `too_many_attempts` Too many failed sign-ins or link requests. *HTTP 429 · Retry: yes* **Likely cause:** Repeated wrong passwords, or too many magic links in an hour. **What to do:** Wait, or use a magic link. #### `weak_password` The password is too weak. *HTTP 400 · Retry: no* **Likely cause:** Too short or too common. **What to do:** Choose a longer, less common password. ### Sign in with Tickwire (OAuth) The OAuth flow that lets an AI app connect to a Tickwire account. #### `access_denied` The user pressed Cancel on the consent page (sent to the app's redirect URI). *HTTP 302 · Retry: no* **Likely cause:** The user declined to connect the app. **What to do:** Nothing was shared. Ask the user whether they want to connect, then start again. #### `connected_app_not_found` No such connected app in this organisation. *HTTP 404 · Retry: no* **Likely cause:** Wrong id, or the app belongs to another organisation. **What to do:** List connected apps with GET /v1/connected-apps. #### `consent_token_invalid` The approval did not come from the consent page this session opened (CSRF protection). *HTTP 403 · Retry: no* **Likely causes:** - The page was reloaded (a new token was issued) or the request was forged. - Another session or organisation tried to answer the request. **What to do:** Reload the consent page and answer again. #### `interaction_required` The user has to approve the app on the consent page (shown on the sign-in error page). *HTTP 400 · Retry: no* **Likely cause:** The app sent prompt=none. **What to do:** Start the sign-in without prompt=none. #### `invalid_client` The client could not be identified or authenticated. *HTTP 400, 401 · Retry: no* **Likely causes:** - Unknown client_id: register the app first (DCR) or use a valid client metadata document URL. - Wrong or missing client secret for a confidential client, or a secret sent by a public client. - The client metadata document could not be loaded or is invalid. - The app sent a token exchange request with credentials we do not accept. **What to do:** Check the client registration and its credentials; re-register if needed. #### `invalid_client_metadata` The dynamic client registration request is not acceptable. *HTTP 400 · Retry: no* **Likely causes:** - The body is not a JSON object. - Unsupported grant_types, response_types or token_endpoint_auth_method. **What to do:** Register with response_types ["code"], grant_types authorization_code (+ refresh_token), and auth method none, client_secret_post or client_secret_basic. #### `invalid_grant` The authorization code, refresh token or access token is not valid for this request. *HTTP 400 · Retry: no* **Likely causes:** - The code or refresh token was already used, expired or revoked. - A rotated-out refresh token was reused, so the whole token chain was revoked. - PKCE verification failed, or redirect_uri differs from the authorization request. - The connection was disconnected, expired, or its agent key was revoked. - The access token was issued for another resource (MCP server URL). **What to do:** Start the sign-in again from the app (a new authorization request). Never retry with the same refresh token. #### `invalid_redirect_uri` A registered redirect URI is not allowed. *HTTP 400 · Retry: no* **Likely causes:** - Not https, not loopback http, and not a reverse-domain app scheme. - It has a fragment, user info, backslashes or spaces, or is longer than 2000 characters. - More than 10 redirect URIs. **What to do:** Use exact https redirect URIs (or http on 127.0.0.1, [::1] or localhost). #### `invalid_scope` The requested scope is wider than what was granted. *HTTP 400 · Retry: no* **Likely cause:** A refresh request asked for a scope the user did not grant (for example tickwire.trade on a read-only connection). **What to do:** Refresh without scope, or ask the user to connect again with the wider access. #### `invalid_target` The resource parameter is not the Tickwire MCP server. *HTTP 400 · Retry: no* **Likely causes:** - resource names another server, or several resources were requested. - At the token endpoint, resource differs from the one the grant was issued for. **What to do:** Send resource set to the Tickwire MCP server URL: the same address you gave the app, shown on the AI agents page. #### `oauth_not_configured` Sign-in for AI apps is not enabled on this deployment. *HTTP 404 · Retry: no* **Likely cause:** Sign in with Tickwire is switched off or not fully set up on this server. **What to do:** Use an agent key instead, or contact support. #### `request_belongs_to_someone_else` This sign-in request was opened by another signed-in user first. *HTTP 403 · Retry: no* **Likely cause:** The sign-in link was opened by someone else (or in another organisation) before you. **What to do:** Start connecting again from the app. #### `request_expired` The sign-in request is older than 10 minutes. *HTTP 410 · Retry: no* **Likely cause:** The consent page was left open too long. **What to do:** Start connecting again from the app. #### `request_not_supported` Request objects (request, request_uri) are not supported (shown on the sign-in error page). *HTTP 400 · Retry: no* **Likely cause:** The authorization request carried a request or request_uri parameter. **What to do:** Send the authorization parameters in the query string. #### `request_used` The sign-in request was already answered. *HTTP 409 · Retry: no* **Likely cause:** Allow or Cancel was pressed twice, or in two tabs. **What to do:** Start connecting again from the app if it did not connect. #### `unsupported_grant_type` The token endpoint only supports authorization_code and refresh_token. *HTTP 400 · Retry: no* **Likely cause:** grant_type is password, client_credentials, implicit or another type. **What to do:** Use the authorization code flow with PKCE. #### `unsupported_response_type` Only response_type=code is supported (shown on the sign-in error page). *HTTP 400 · Retry: no* **Likely cause:** The app used the implicit flow or another response type. **What to do:** Use response_type=code with PKCE (S256). ### Compatibility error names On the `/users/current/…` routes, `error` holds one of these names so existing clients keep working, and our own code is in `code`. The terminal routes (`/{mt4|mt5}/{id}/…`) use the three names that start with `MRPC`. #### `AcceptedError` Error name for a request that is still being processed (`/users/current/…` routes only). *HTTP 202 · Retry: same key only* **Likely cause:** Account creation for the same transaction-id is still running. **What to do:** Repeat the same request, with the same transaction-id, after Retry-After seconds. #### `ApiError` Error name on the `/users/current/…` routes for a client error that has no more specific name. *HTTP 400, 405, 413, 415, 422 · Retry: no* **Likely cause:** See the Tickwire code in the `code` field. **What to do:** Read `code` and open its page; fix the request. #### `ConflictError` Error name for a conflict (409) on the `/users/current/…` routes. *HTTP 409 · Retry: no* **Likely causes:** - The resource already exists. - An Idempotency-Key or clientId was reused for a different request. **What to do:** Read the Tickwire code in `code` (or `tickwireError`) for the exact reason. #### `ForbiddenError` Error name for a forbidden request (403) on the `/users/current/…` routes. *HTTP 403 · Retry: no* **Likely cause:** The token may not do this (read-only, account-scoped, or missing a role). **What to do:** Use a token with the needed access. The Tickwire code is in `code`. #### `InternalError` Error name for a server-side failure on the `/users/current/…` routes. *HTTP 500, 502, 503, 504 · Retry: same key only · May have executed* **Likely causes:** - The terminal returned an error. - A Tickwire service failed. **What to do:** Read the Tickwire code in `code` or `tickwireError`. Reads can be retried; repeat a trade only with the same clientId or Idempotency-Key. #### `MRPC` Terminal route error (`/{mt4|mt5}/{id}/…`): the terminal processed the request but the operation failed. *HTTP 500 · Retry: same key only · May have executed* **Likely causes:** - Unknown symbol (`reason: symbol_not_found`). - The terminal returned an error (`reason: backend_error`, MT code in `code`). **What to do:** Check `reason`. Fix the symbol, or retry a read. Repeat a trading call only with the same Idempotency-Key. #### `MRPC_NOT_CONNECTED` Terminal route error (`/{mt4|mt5}/{id}/…`): the terminal has no broker connection right now. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely causes:** - The terminal is starting or reconnecting. - The broker server is down or rejected the login. **What to do:** Retry with backoff and check the account's health endpoint. #### `MRPC_VALIDATION` Terminal route error (`/{mt4|mt5}/{id}/…`): a parameter is missing or invalid. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely causes:** - A required query or body field is missing. - A value has the wrong type or range. **What to do:** Fix the request; the message names the parameter. #### `NotConnectedError` Error name on the `/users/current/…` routes: the terminal is not connected to the broker. *HTTP 503 · Retry: yes · Nothing reached the broker* **Likely causes:** - The terminal is starting or reconnecting. - The broker server is unreachable. **What to do:** Retry after Retry-After; check account health. #### `NotFoundError` Error name for a missing resource on the `/users/current/…` routes. *HTTP 404 · Retry: no* **Likely cause:** See the Tickwire code in `code` or `tickwireError`. **What to do:** Check the id or symbol in the path. #### `NotSynchronizedError` Error name on the `/users/current/…` routes: the terminal is not synchronized enough to answer (for example the broker time is not known yet). *HTTP 503 · Retry: yes* **Likely cause:** No live ticks have arrived since the terminal started. **What to do:** Retry after Retry-After. #### `PaymentRequiredError` Error name for a request that needs payment (402) on the `/users/current/…` routes. *HTTP 402 · Retry: no* **Likely cause:** The wallet balance does not cover the purchase. **What to do:** Top up, then repeat. #### `TooManyRequestsError` Error name for a rate limit on the `/users/current/…` routes; `metadata.recommendedRetryTime` says when to retry. *HTTP 429 · Retry: yes* **Likely causes:** - Too many requests for this token, account or IP. - All concurrent market-data request slots are in use. **What to do:** Wait for Retry-After (or recommendedRetryTime), then retry. #### `UnauthorizedError` Error name for a missing or invalid token on the `/users/current/…` routes. *HTTP 401 · Retry: no* **Likely causes:** - No auth-token header. - The token is invalid, expired or revoked. **What to do:** Send a valid token. #### `ValidationError` Error name for an invalid request on the `/users/current/…` routes; `details` lists the parameters. *HTTP 400 · Retry: no · Nothing reached the broker* **Likely cause:** A field is missing or has the wrong type or value. **What to do:** Fix the fields named in `details`. ### Status page API Errors from the status page's API, including its admin API. #### `admin_disabled` The admin API is switched off. *HTTP 403 · Retry: no* **Likely cause:** The status service's admin API is not enabled. **What to do:** Not for customers: only Tickwire staff use this API. #### `canary_not_found` No webhook-delivery canary has this id. *HTTP 404 · Retry: no* **Likely causes:** - The canary endpoint URL has a typo. - The canary probe is not configured (its secret is unset). **What to do:** Point the canary webhook at /api/v1/canary/webhooks/ of a configured webhook_receipt probe. #### `component_not_found` No component with this id. *HTTP 404 · Retry: no* **Likely cause:** A typo in the component id. **What to do:** Read /api/v1/status.json for the list of component ids. #### `email_notifications_unavailable` Email updates are not available yet. *HTTP 503 · Retry: no* **Likely cause:** Email updates aren't switched on yet. **What to do:** Follow the RSS, Atom or JSON feed instead; the message has their URLs. #### `incident_closed` The incident or maintenance is already resolved or completed. *HTTP 409 · Retry: no* **Likely cause:** An update was posted to a closed incident. **What to do:** Open a new incident; a closed one takes no more updates. #### `incident_not_closed` A postmortem can only be written once the incident is resolved. *HTTP 409 · Retry: no* **Likely cause:** The incident is still open. **What to do:** Resolve the incident first, then write the postmortem. #### `incident_not_found` No incident with this id. *HTTP 404 · Retry: no* **Likely cause:** A typo in the incident id. **What to do:** List incidents with /api/v1/incidents. #### `invalid_incident_status` That status doesn't belong to this kind of event. *HTTP 422 · Retry: no* **Likely cause:** An incident given a maintenance status (scheduled, in_progress, completed), or the reverse. **What to do:** Incidents use investigating, identified, monitoring, resolved; maintenance uses scheduled, in_progress, completed. #### `invalid_maintenance` The maintenance window is invalid. *HTTP 422 · Retry: no* **Likely causes:** - scheduled_for is missing. - scheduled_until is not after scheduled_for. **What to do:** Send a start time, and an end time after it. #### `postmortem_not_found` This incident has no postmortem. *HTTP 404 · Retry: no* **Likely cause:** None was written, or it was deleted. **What to do:** Write one with PUT /api/v1/incidents/{id}/postmortem. #### `unknown_component` An incident names a component that doesn't exist. *HTTP 422 · Retry: no* **Likely cause:** A typo in a component id. **What to do:** Use ids from /api/v1/status.json. --- # Rate limits > The real limits, what each call costs, the headers you get, and how to back off without making things worse. Source: https://tickwire.io/docs/rate-limits/ Tickwire uses a few plain token buckets, not a credit system. Each request costs a small, fixed number of **units** (its weight), and each bucket refills continuously. Limits apply per API key and per trading account, so one noisy integration can't starve your others, and trades have their own budget, so polling can never block an order. ## The limits | Bucket | Burst (units) | Refill (units per second) | Applies to | |---|---|---|---| | Per key | 100 | 50 | Every authenticated request, by API key or token | | Per account | 40 | 20 | Requests that name a trading account (all keys together) | | Per account, trades | 20 | 10 | Trades on one account (all keys together) | | Per IP, anonymous | 20 | 5 | Requests without a key (sign-up, public lists) | | Per IP, failed auth | 20 | 0.5 | Requests with an invalid key | | Per IP, MCP server | 200 | 50 | The hosted MCP server (it also limits per key) | A request passes only if **every** bucket it uses has room, and then all of them are charged. A refused request charges nothing. Streaming: | Limit | Value | |---|---| | Concurrent WebSockets per key | 50 | | Request body | 16 MiB | | WebSocket message | 16 MiB | ## What each call costs | Class | Weight | Buckets | Calls | |---|---|---|---| | Standard | 1 | key + account | Reads and account changes: positions, orders, symbols, prices, account info | | History | 5 | key + account | History and bulk reads: `history-orders`, `history-deals`, `historical-market-data`, `historical-trades`, terminal `OrderHistory`, `PositionHistory`, `PriceHistory` | | Trade | 1 | key + account trades | `POST /users/current/…/trade`, terminal `OrderSend`, `OrderModify`, `OrderClose`, `CloseAll`, `POST /v1/execution/accounts/{id}/trade` | | Batch orders | 10 | key | `POST /v1/orders`, `POST /v1/orders/close` (each leg is also checked by the account) | | Stream connect | 5 | key + account | Opening a WebSocket. Frames on an open socket are free | So with one key you can, at a steady rate, make 50 reads a second, or 10 history calls a second, or trade 10 times a second on each account, and bursts of twice that. ## Trades are never dropped silently A trade refused by a rate limit is answered `429` with `"sent": false` and `"outcome": "not_sent"`. It never reached the terminal and was not queued. You can resend it after `Retry-After`; use the same `Idempotency-Key` anyway, as for every trade. ## Headers Every response carries the tightest bucket's state, in the IETF [RateLimit header fields](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/) form, plus the same numbers under the older `X-` names: | Header | Meaning | |---|---| | `RateLimit-Limit` | The bucket's burst, in units | | `RateLimit-Remaining` | Units left right now | | `RateLimit-Reset` | Seconds until the bucket is full again | | `RateLimit-Policy` | `;w=;name=""`, e.g. `100;w=2;name="key"` | | `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` | The same values | A `429` also carries `Retry-After` (seconds until this request would pass) and the standard error envelope with code [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/). `metadata` says which bucket refused it (`bucket`: `key`, `account`, `account-trades`, `ip`…), the request's `weight`, and `recommendedRetryTime`, as on the `/users/current/…` API. ```json { "error": "rate_limited", "message": "too many requests; retry after the time in Retry-After", "sent": false, "outcome": "not_sent", "metadata": { "recommendedRetryTime": "2026-09-25T11:02:20.000Z", "exceededConfig": "perAccountTrades", "resourceId": "account:acc_7Qx", "limit": 20, "bucket": "account-trades", "weight": 1 }, "requestId": "4f1c…", "docUrl": "https://tickwire.io/docs/errors/rate_limited" } ``` On the `/users/current/…` routes `error` is `TooManyRequestsError` and our code is in `code`, so existing clients that read `error` handle it as they do today. Too many open WebSockets is `429` [`too_many_connections`](https://tickwire.io/docs/errors/too_many_connections/). ## Backing off well - Wait at least `Retry-After`. Then back off exponentially with **jitter**, capped at 30 seconds or so. Without jitter, every client retries at the same instant and trips the limit again. - Never auto-retry a trade on `429` with a **new** idempotency key. - Stream instead of polling. One WebSocket replaces hundreds of `GET /positions` calls, and its frames don't count against request limits. ## What doesn't count Webhook deliveries, WebSocket frames we send you, and the health checks `/_gateway/healthz` and `/_gateway/readyz`. Need more? Higher limits are available on request, per key; the headers always show the limits that apply to you. --- # Broker onboarding > Connect an account on any MT4 or MT5 broker, and what to do when we can't find the server. Source: https://tickwire.io/docs/broker-onboarding/ You don't need a broker-specific integration. Any MT4 or MT5 broker works with the details below. ## What you provide - `platform`: `mt4` or `mt5` - `server`: the server name as shown in the terminal's login dialog, e.g. `YourBroker-Server` - `login` and `password` (master to trade, investor to read only) ## MT5 The terminal finds brokers by server name through MetaQuotes' directory. That covers almost every broker. ## MT4 MT4 has no central directory. We look up the broker's **public server address** from the server name. If we can't resolve the name, give us the address from your broker's site. ## When the server isn't found You get `E_SRV_NOT_FOUND` with suggestions: ```json { "error": "ValidationError", "message": "Server not found: YourBroker-Srv. Suggested server names: YourBroker-Server", "details": { "code": "E_SRV_NOT_FOUND", "serversByBrokers": { "Your Broker Ltd": ["YourBroker-Server"] } } } ``` If none fits, create a **provisioning profile** and upload the server file from a terminal where login works: `servers.dat` from MT5's `Config` folder, or the broker's `.srv` file from MT4's `config` folder. ```bash curl -s -X POST "$TW/users/current/provisioning-profiles" -H "auth-token: $TW_KEY" \ -H "content-type: application/json" \ -d '{"name": "My broker", "version": 5, "brokerTimezone": "EET", "brokerDSTSwitchTimezone": "EET"}' curl -s -X PUT "$TW/users/current/provisioning-profiles/$PROFILE/servers.dat" \ -H "auth-token: $TW_KEY" -F "file=@servers.dat" ``` Then create the account with `provisioningProfileId`. ## Quirks we handle - **Symbol suffixes.** `EURUSD` might be `EURUSDm` or `EURUSD.r`. `GET …/symbols` returns the exact names; use those. - **Filling modes.** MT5 brokers accept different fill policies. We choose from the symbol's allowed modes, or you can give a priority list in `fillingModes`. - **Same name, two platforms.** Some brokers use one server name for MT4 and MT5. The `platform` you set decides. - **Cent and micro accounts.** Minimum volumes differ; read `minVolume` and `volumeStep` from the symbol specification. - **Server time.** Measured per server, never assumed. See [Time zones](https://tickwire.io/docs/time-zones/). --- # Request logs > Every API call your keys made in the last 14 days, with redacted bodies for errors, in the dashboard and the API. Source: https://tickwire.io/docs/request-logs/ Tickwire records every authenticated call to its API, so you can see what your integration actually sent and what it got back, without adding logging of your own. Open **Logs** in the dashboard, read them with `GET /v1/request-logs`, or follow them in your terminal with [`tickwire logs tail -f`](https://tickwire.io/docs/cli/#logs-tail-your-request-log). ## What each entry holds | Field | Meaning | |---|---| | `id` | The entry id (`req_…`). | | `requestId` | The `X-Request-ID` of the call; quote it to support. | | `createdAt` | When the call arrived (UTC). | | `method`, `path`, `route` | The call. `path` never includes the query string; `route` is its template, e.g. `/users/current/accounts/{accountId}/positions`. | | `status`, `errorCode` | The HTTP status and, for errors, the [error code](https://tickwire.io/docs/errors/). | | `latencyMs` | Time until the whole answer was sent. | | `outcome` | `completed`, or `aborted` when the answer was cut short: the upstream broke off, or your client disconnected before reading it all. | | `keyId`, `accountId` | The API key (its id, never its value) and the trading account. | | `apiVersion`, `rateLimitBucket` | The version that served the call, and the rate-limit bucket it drew on. | | `clientIp`, `userAgent` | Where the call came from. | WebSocket sessions are logged too (`kind: "websocket"`), when they end. ## Bodies: errors only, redacted For calls that failed (status 400 or above), the entry also keeps short excerpts of the request and response bodies (`requestBody`, `responseBody`, at most 2 KiB each). Successful calls never keep a body. - Only JSON objects and form bodies (`application/x-www-form-urlencoded`) are kept. XML, multipart uploads, JSON arrays and plain text are never stored. - Every value under a name that may hold a secret is replaced by `[REDACTED]`: passwords, PINs, one-time codes, keys, secrets, tokens, authorization headers, cookies, sessions and signatures, at any depth. Free text is scrubbed of `name=value` pairs and of anything that looks like a credential (API keys, bearer tokens, JWTs), including URL-encoded and escaped forms. - When a body cannot be redacted with certainty, no excerpt is kept at all. - Bodies with a lot of text (roughly more than 16,000 characters of keys and strings) get no excerpt, and under heavy error load some entries may be kept without one. The rest of the entry is always recorded. **Who can see bodies.** In the dashboard, owners and admins. Members and viewers see the entry without its bodies. Through the API, a full-access key with the writer role; other credentials get the entry with `excerptsHidden: true`. ## Retention and limits Entries are kept for **14 days**, within limits set by your plan; when a limit is reached, the oldest entries go first. | Organisation | Entries | Storage | |---|---|---| | Sandbox | 2,000 | 2 MiB | | No paid subscription (trial, unpaid, cancelled) | 10,000 | 16 MiB | | Paid subscription | 100,000 | 128 MiB | Sizes are counted in UTF-8 bytes. If the service's total request-log storage nears its limit (90 %), new entries keep their metadata but no body excerpts until space is freed. If it is full, entries are removed first from the organisations furthest over a fair share of the total, sandbox organisations first, then those without a paid subscription; a paid organisation's entries are only removed once every lower tier is at or below its share, and never below that share. Calls to `/v1/request-logs` itself are not logged. ## API ```http GET /v1/request-logs?status=errors&limit=50 ``` Filters: `status` (`404`, `4xx`, `5xx`, `errors` or `aborted`), `method`, `route` (part of the path or template), `errorCode`, `keyId`, `accountId`, `requestId`, `since` and `until` (ISO 8601). Answers `{data, nextCursor, hasMore}`, newest first; pass `cursor=` for the next page. ```http GET /v1/request-logs/summary?hours=24 GET /v1/request-logs/{id} ``` The summary gives totals, the error rate and the most frequent error codes and routes. An unknown id answers [`request_log_not_found`](https://tickwire.io/docs/errors/request_log_not_found/). --- # Switching from another provider > Move an existing MT4/MT5 API integration to Tickwire by changing the base URL and the key, and what differs. Source: https://tickwire.io/docs/switching/ Tickwire serves two API styles that existing clients already call: - **The `/users/current/accounts/…` REST API.** Same paths, query parameters, field names and trade return codes. Authenticate with the `auth-token` header. - **The `/v1` API and the terminal routes `/{mt4|mt5}/{id}/…`.** Same routes, field names, WebSocket topics and batch order endpoints. Authenticate with `X-API-Key` or `Authorization: Bearer`. If your code calls one of these over plain HTTP, switching means a new base URL and a Tickwire key. Other providers' official SDKs are their software under their licences, which can restrict use with other services, so we don't support pointing them at Tickwire. Call the REST endpoints directly, or use the Tickwire SDKs. The examples use `curl`; set these first: ```bash export TW=https://api.tickwire.io export TW_KEY=your-api-key ``` ## 1. Change the base URL and the key Keep your HTTP client and send the same requests to Tickwire's host with your Tickwire key. On the `/users/current/…` routes, the key goes in the same `auth-token` header: ```bash curl -s "$TW/users/current/accounts/acc_7Qx/account-information" -H "auth-token: $TW_KEY" ``` On the `/v1` and terminal routes, both `X-API-Key` and `Authorization: Bearer` work, and WebSockets take `?api_key=`: ```diff - BASE = "https:///v1" + BASE = "https://api.tickwire.io/v1" - KEY = "" + KEY = "" ``` Every endpoint is listed in the [API reference](https://tickwire.io/docs/reference/). ## 2. Re-create your accounts Broker credentials can't be exported from another provider, so link each account again. On the `/users/current/…` API, create it with the same `name`, `server`, `login`, `password`, `magic` and `platform`. Your `tags` and `metadata` carry over as they are. Account creation takes the `transaction-id` header and answers `202` with `Retry-After` while broker detection runs, so existing provisioning code keeps its polling logic. ```bash curl -s -X POST "$TW/users/current/accounts" \ -H "auth-token: $TW_KEY" \ -H "transaction-id: $(openssl rand -hex 16)" \ -H "content-type: application/json" \ -d '{"name": "my account", "platform": "mt5", "server": "YourBroker-Server", "login": "12345678", "password": "your-password", "magic": 1000}' ``` On the `/v1` API, `POST /v1/accounts` takes the same body (`platform`, `server`, `login`, `password`, `nickname`, …). Each account's `rest_url` and `ws_url` point at Tickwire; keep using them as you do now. They are `https://api.tickwire.io/{mt4|mt5}/{id}` and `wss://api.tickwire.io/{mt4|mt5}/{id}/ws`, whatever region the account runs in. The account's dedicated IP, if it has one, is where its broker traffic comes from; it is not an API address. ## 3. Run it A typical flow on the `/users/current/…` API: wait for the account to connect, read it, then trade. ```bash # Health, with evidence (Tickwire extra) curl -s "$TW/users/current/accounts/acc_7Qx/health" -H "auth-token: $TW_KEY" # Open positions curl -s "$TW/users/current/accounts/acc_7Qx/positions" -H "auth-token: $TW_KEY" # A market order; clientId works as before, and Idempotency-Key makes retries safe curl -s -X POST "$TW/users/current/accounts/acc_7Qx/trade" \ -H "auth-token: $TW_KEY" \ -H "Idempotency-Key: rf_1" \ -H "X-Actor: migration-test" -H "X-Reason: first order after switching" \ -H "content-type: application/json" \ -d '{"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.01, "clientId": "rf_1"}' ``` For streaming, use the WebSocket on each account's `ws_url`, or Tickwire's [plain WebSocket protocol](https://tickwire.io/docs/streaming/): JSON frames, one socket per account, from any language. ## What's the same | Area | Endpoints | |---|---| | `/users/current` REST API | Paths, query parameters and field names on `/users/current/accounts/{id}/…`; trade `actionType`s, relative SL/TP units, expiration types and return codes; `clientId` handling; the `error`, `numericCode` and `stringCode` error fields; `transaction-id` and 202 polling on account creation | | `/v1` API | `/v1/accounts`, `/v1/private-servers` (buy, resize, cancel, add/remove accounts, regions), `/v1/readonly-keys`, `/v1/subscription`, `/v1/wallet` | | Batch trading | `POST /v1/orders` (up to 20 legs), `POST /v1/orders/close` with `symbol`, `symbol_match`, `kind`, `side`, `magic`, `tickets`, partial volume and `require_reachable`; per-leg statuses; `Idempotency-Key` | | Terminal | `/{mt4\|mt5}/{id}/AccountSummary`, `AccountInfo`, `OpenedOrders`, `OrderHistory`, `PositionHistory`, `PriceHistory`, `SymbolInfo`, `symbols`, `getQuote`, `ServerTimezone`, `OrderSend`, `OrderModify`, `OrderClose`, `OrderCalcMargin`, `OrderCalcProfit`, `status`, `healthz`, `livez` | | WebSocket | `/{mt4\|mt5}/{id}/ws` with the prices, bars, account, positions, trades and terminal topics; snapshot on subscribe; `warning` for slow consumers | | Order results | `success`, `outcome` (`applied`, `no_change`, `partial`, `rejected`) and `is_effective` | ## What's different - **Health is evidence-based.** An account is `CONNECTED` (or `connected`) only when our health monitor has seen the broker link, a successful account read and moving ticks. You may see accounts go disconnected that your current provider showed as fine. See [Health](https://tickwire.io/docs/health/). - **Extra response fields.** Trade responses add `outcome`; unknown outcomes are checked against the terminal. See [Idempotency](https://tickwire.io/docs/idempotency/). Clients that ignore unknown fields are unaffected. - **A new outcome value.** Order results can be `unknown` when a broker connection drops mid-order and the result can't be confirmed. Handle it like a timeout: retry with the same `Idempotency-Key`. - **Timestamps.** UTC fields are real UTC. Broker-local times are in separate, labelled fields, not marked with a `Z`. If your code corrected broker times by hand, remove that correction. See [Time zones](https://tickwire.io/docs/time-zones/). - **TLS.** Dedicated IPs have valid certificates. Remove any `verify=False`. - **Key changes don't restart terminals.** Creating, rotating or re-scoping read-only keys doesn't take accounts offline. - **Read-only keys are shown once.** Tickwire returns a read-only key's value only when you create or rotate it, and stores a hash: lists and reads answer `key: null` with a short `key_preview`. Store the key when you create it. If your code fetched keys from `GET /v1/readonly-keys` to use them, rotate the key instead and keep the new value. - **Webhooks, `/health` and `/audit`.** Register a webhook instead of polling for status. - **Pricing.** One monthly plan per account in USD. See [Pricing](https://tickwire.io/pricing/). ## What isn't supported - Copy-trading services, an MT Manager API, hosted configuration links and demo-account generation. Calls to them fail with a clear error. - `reliability: "high"` runs one instance per account today; cross-region replicas aren't offered. - Expert-advisor upload. ## Checklist 1. Create a Tickwire key and point a staging copy of your app at Tickwire. Replay your usual calls. 2. Link one account and run your test suite against it. 3. Remove `verify=False` and any broker-time corrections. Store read-only keys when you create them. 4. Handle `outcome: "unknown"`. 5. Register a [webhook](https://tickwire.io/docs/webhooks/) for `account.health_changed`. 6. Move accounts one at a time or in small batches. Remove an account from your old provider only after the Tickwire copy is healthy. Never run two terminals on one prop-firm account at the same time. --- # Pagination > Cursor pagination on the native /v1 lists, and which lists keep their upstream shapes. Source: https://tickwire.io/docs/pagination/ The native `/v1` lists return one page at a time and hand you a cursor for the next one. ## Request and response | Query | Meaning | |---|---| | `limit` | Page size, 1 to 500. Default 100. | | `cursor` | The `next_cursor` from the previous page, passed back unchanged. Omit it for the first page. | Every page carries the list's items plus: | Field | Meaning | |---|---| | `has_more` | `true` when another page follows. | | `next_cursor` | The cursor for the next page, or `null` on the last page. | ```bash curl -s "https://api.tickwire.io/v1/pretrade-holds?status=pending&limit=2" -H "X-API-Key: $TW_KEY" ``` ```json { "data": [{ "hold_id": "hld_2", "status": "pending" }, { "hold_id": "hld_1", "status": "pending" }], "has_more": true, "next_cursor": "eyJ2IjoxLCJmIjoi…" } ``` Call again with `cursor=eyJ2IjoxLCJmIjoi…` and the **same filters** until `has_more` is `false`. ## Guarantees - **Keyset, not offset.** A page never repeats or skips an item because rows were added or removed between calls. Each list has a fixed order, documented on its route. - **Cursors are opaque and bound to their list and filters.** A cursor that was edited, comes from another list, or is sent with different filters is rejected with [`400 invalid_cursor`](https://tickwire.io/docs/errors/invalid_cursor/). Start again without a cursor. - A cursor reveals nothing about other tenants; every query is still scoped to your key. ## Which lists are paginated | List | Items field | Order | |---|---|---| | `GET /v1/agent-keys` | `data` | Oldest first | | `GET /v1/pretrade-hooks` | `data` | Oldest first | | `GET /v1/pretrade-holds` | `data` | Newest first | | `GET /v1/agent-kill-switches` | `accounts` | By account id | | `GET /v1/agent-audit`, `GET /v1/agent/audit` | `entries` | Newest first (`before` still works) | | `GET /v1/connected-apps` | `apps` | Oldest first | | `GET /v1/agent/accounts` | `accounts` | By account id | The compatible routes (`/users/current/…`, and `/v1/accounts`, `/v1/webhooks` and `/mt4|mt5/{id}/…`) keep their existing shapes and are not paginated this way. `GET /v1/webhooks/{id}/deliveries` keeps its existing `hasMore` and `nextCursor` fields. ## In the SDKs Python: `for page in tw.pages(tw.list_holds, status="pending"): …` (also `async for` on `AsyncTickwire`). TypeScript: `for await (const page of pages((cursor) => tw.listHolds({ cursor }))) …`. --- # Changelog > Changes to the API and docs, newest first. Source: https://tickwire.io/docs/changelog/ We version the API and announce breaking changes at least six months before they take effect. API versions and deprecations are listed in the [API changelog](https://tickwire.io/docs/changelog-api/); the rules are in [Versioning and deprecation](https://tickwire.io/docs/versioning/). ## 2026-09-23 - Docs site published: quickstart, concepts, guides, streaming protocol v2, webhooks, errors, rate limits, broker onboarding, time zones, migration guides, status feed. - API reference generated from the OpenAPI contract. - Pricing page with a calculator. --- # Versioning and deprecation > Dated API versions, what we count as a breaking change, and how long you get before anything goes away. Source: https://tickwire.io/docs/versioning/ Code you write against Tickwire today keeps working. Breaking changes to the native API ship only under a new dated version that you opt into, and nothing is removed without at least **six months** of notice, in headers and in the [API changelog](https://tickwire.io/docs/changelog-api/). ## Which surfaces are versioned | Surface | Paths | Versioning | |---|---|---| | Native API | `/v1/…` on `api.` | Dated versions, `Tickwire-Version` header | | `/users/current` REST API | `/users/current/…`, the regional API hostnames | **Frozen** to its existing shapes | | Terminal routes | `/mt4/{id}/…`, `/mt5/{id}/…` | **Frozen** to their existing shapes | The compatible surfaces exist so that code written for these API styles runs unchanged. Their request and response shapes are fixed and are never changed by a Tickwire version. We may add fields there when the API style does; we never rename, remove or retype one. `Tickwire-Version` is ignored on those routes and not echoed. ## Dated versions Versions are dates: `YYYY-MM-DD`. The current and only version is **`2026-09-25`**. - Send `Tickwire-Version: 2026-09-25` on a `/v1` request to choose a version for that call. - Without the header, the call uses your organisation's **pinned** version (see below). - Every `/v1` response echoes the version that served it in `Tickwire-Version`, errors included. - A malformed or unknown version is refused with `400` [`invalid_api_version`](https://tickwire.io/docs/errors/invalid_api_version/), listing the supported versions in `metadata.supportedVersions`. Nothing is forwarded. Sending the header explicitly is the safest choice: your code then never changes behaviour when the pin does. ## Your organisation's pin Every organisation is pinned to one version. A `/v1` call without `Tickwire-Version` is served in that version, so a new version never changes how your existing code behaves until you move the pin. - A new organisation is pinned to the latest version on the day it is created. - Organisations created before pins existed are pinned to `2026-09-25`. - The header always wins: a call that sends `Tickwire-Version` gets that version, whatever the pin. Read the pin with any API key or API token: ```bash curl https://api.tickwire.io/v1/api-version -H "X-API-Key: $TICKWIRE_KEY" ``` ```json {"apiVersion": "2026-09-25", "latestVersion": "2026-09-25", "supportedVersions": ["2026-09-25"]} ``` ### Upgrading the pin Test your code against the new version first by sending `Tickwire-Version: ` on its calls. When it passes, move the pin, either in the dashboard (**Settings → API version**, owners and admins) or with the API: ```bash curl -X POST https://api.tickwire.io/v1/api-version \ -H "X-API-Key: $TICKWIRE_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "X-Actor: deploy-bot" \ -H "X-Reason: upgrade after the integration tests passed" \ -H "Content-Type: application/json" \ -d '{"apiVersion": "2026-09-25"}' ``` ```json {"apiVersion": "2026-09-25", "previousApiVersion": "2026-09-25", "changed": false, "latestVersion": "2026-09-25", "supportedVersions": ["2026-09-25"]} ``` - It needs a **full** API key, or a full-access API token with the writer role. Keys are issued by owners and admins; in the dashboard only owners and admins see the upgrade button. - `Idempotency-Key`, `X-Actor` and `X-Reason` are required (`400` [`missing_header`](https://tickwire.io/docs/errors/missing_header/) otherwise; percent-encode a non-ASCII value). Repeating the key returns the first answer; the same key with a different body is `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/). - Every change is written to your organisation's audit log as `api_version.pinned`, with the old and new version, the actor and the reason. - An unknown or malformed version is `400` [`invalid_api_version`](https://tickwire.io/docs/errors/invalid_api_version/). A version older than the oldest supported one is `400` [`api_version_unsupported`](https://tickwire.io/docs/errors/api_version_unsupported/). The pin is unchanged in both cases. - You can move the pin back to an older version while it is still supported. - The new pin applies to calls without the header **within 30 seconds**. ## What counts as breaking Breaking (only in a new dated version): - removing or renaming an endpoint, a field, a query parameter or an enum value; - changing a field's type, format, units or meaning (for example broker time to UTC); - making an optional request field required, or adding a new required field; - changing a success status code, an error code, or when an error is returned; - changing default values, sort order or pagination behaviour; - tightening validation so that a request accepted before is now refused. Not breaking (can ship at any time, in every version): - new endpoints, new optional request fields and parameters; - new response fields (ignore fields you don't know); - new enum values in fields documented as open-ended, new error codes for new failure modes, new webhook event types (ignore types you don't know); - changes to the text of `message`, to `docUrl` targets, to the order of JSON keys, or to the length and format of opaque ids; - raising a rate limit, or adding response headers. Security fixes are the one exception: if a behaviour is unsafe, we may change it without a new version, and we'll say so in the changelog the same day. ## Deprecation When an endpoint, a field or a whole version is scheduled to go away: 1. It is announced in the [API changelog](https://tickwire.io/docs/changelog-api/) with the date it stops working. 2. From that day, every response from it carries: | Header | Standard | Example | |---|---|---| | `Deprecation` | RFC 9745 | `Deprecation: @1790812800` (when it was deprecated, Unix seconds) | | `Sunset` | RFC 8594 | `Sunset: Sat, 01 May 2027 00:00:00 GMT` (when it stops working) | | `Link` | RFC 8288 | `Link: ; rel="deprecation"` | 3. The sunset is **at least six months** after the deprecation is announced. A version stays supported for at least six months after the next version is published, and in practice until usage has moved. 4. We contact organisations we still see calling a deprecated route before its sunset. Watch for `Deprecation` in your logs or tests: it is the earliest warning you'll get. ## Changelog [API changelog](https://tickwire.io/docs/changelog-api/) lists every version and every deprecation, newest first. The general [changelog](https://tickwire.io/docs/changelog/) covers the docs and the product. --- # API changelog > Every API version, breaking change and deprecation, newest first. Source: https://tickwire.io/docs/changelog-api/ Breaking changes to the native `/v1` API ship only under a new dated version, and anything deprecated keeps working for at least six months. The [versioning policy](https://tickwire.io/docs/versioning/) explains the rules. The compatible surfaces (`/users/current/…` and the terminal routes) are frozen to their existing shapes and are not listed here unless we fix a divergence from those shapes. ## Unreleased (no version change) - **New API key prefixes.** New full keys start with `tw_live_` and new read-only keys with `tw_ro_`. Keys issued before 2026-10-03 keep working unchanged, with the same rights. If your code checks a key's prefix, accept both. No shape changes. - **`Idempotency-Key` on calls that create a secret.** `POST /v1/agent-keys`, `POST /v1/pretrade-hooks`, `POST /v1/pretrade-hooks/{id}/rotate-secret`, `POST /users/current/tokens`, `POST /v1/readonly-keys`, `POST /v1/readonly-keys/{id}/rotate` and `POST /v1/sandbox/keys` now honour it (a replayed rotate rotates nothing): a retry with the same key answers the first result with `Idempotent-Replayed: true`, the secret field set to `null` and a notice (`key_notice`, `secret_notice`, `tokenNotice`, `apiKeyNotice`) that it was already shown. Before, every retry created a second live credential. The key is scoped to the calling credential, and the protection is short-lived: a retry after one of our restarts or deploys may still create a second credential, so list and revoke duplicates. A call that fails after the credential exists answers `500`, `outcome: unknown` and `created_id`. See [Idempotency](https://tickwire.io/docs/idempotency/). - **Full and sandbox keys are stored hashed.** Full (`tw_live_`) and sandbox `twsk_` keys are now stored as a SHA-256 digest with a short preview, like read-only keys, API tokens and agent keys. Their values were already shown only once (`POST /dashboard/api-keys`, `POST /v1/sandbox/signup`, `POST /v1/sandbox/keys`, the dashboard's sandbox quickstart); now nothing on our side keeps them. Lists answer only `key_preview` (`tw_live_ab12…`, `twsk_ab12…`), and the dashboard's reveal answers `400` [`not_revealable`](https://tickwire.io/docs/errors/not_revealable/) for every key. Existing keys keep working, with every header and query form, over REST and WebSocket. No shape changes. - **Breaking (pre-launch): read-only keys are shown once.** Read-only (`tw_ro_`) keys are now stored as a SHA-256 digest, like agent keys and API tokens. The value is in `key` only in the answer to `POST /v1/readonly-keys` and `POST /v1/readonly-keys/{id}/rotate` (with `key_notice`); every other read (`GET /v1/readonly-keys`, `GET` and `PATCH /v1/readonly-keys/{id}`) answers `key: null` and a `key_preview` (`tw_ro_ab12…`). Existing keys keep working. The dashboard can no longer reveal a read-only key; rotate it to get a new value. - **Request logs.** `GET /v1/request-logs`, `GET /v1/request-logs/summary` and `GET /v1/request-logs/{id}`: every authenticated call of the last 14 days, with redacted body excerpts for errors. See [Request logs](https://tickwire.io/docs/request-logs/). New error code [`request_log_not_found`](https://tickwire.io/docs/errors/request_log_not_found/). Additive; no version change. - **Health of an account that isn't running.** `GET /users/current/accounts/{id}/health` and `GET /mt4|mt5/{id}/status` used to answer `404` `account_not_deployed` for an account whose deploy failed or that was undeployed. They now answer `200` with `status: "down"`, `deployed: false`, the lifecycle `state` and the reason code from the account's error (for example `ERR_OTP_REQUIRED` for sandbox login `1060`); `/healthz` and `/livez` answer `503`. Agent health (`GET /v1/agent/accounts/{id}/health`) says `disconnected` with that reason instead of `unknown`. Unknown accounts and other tenants' accounts are still `404`. See [Health](https://tickwire.io/docs/health/#accounts-that-arent-running). - **Fewer one-off `500`s on listings.** `GET /v1/connected-apps` and `GET /v1/dedicated-ips` (and their dashboard versions) could answer `500 internal_error` about once in a hundred calls when a database connection had been dropped while idle. Connections are now checked before use, the read is retried once on a fresh connection, and if the database still can't be reached the answer is `503` [`temporarily_unavailable`](https://tickwire.io/docs/errors/temporarily_unavailable/) with `Retry-After`. Nothing was changed by such a call; retry it. ## 2026-09-27: pagination, account snapshot, trade and account events Additions and one pre-launch shape change to version `2026-09-25`. No new version was cut: the API has no customers yet, so the change is made in place before launch rather than behind a new version. - **Breaking (pre-launch): three lists changed from a bare JSON array to a page.** `GET /v1/agent-keys`, `GET /v1/pretrade-hooks` and `GET /v1/pretrade-holds` now answer `{"data": [...], "has_more": false, "next_cursor": null}` instead of `[...]`. Read the items from `data`. The SDKs changed with them (`list_agent_keys` / `listAgentKeys`, `list_pretrade_hooks` / `listPretradeHooks`, `list_holds` / `listHolds` return the page). - **Cursor pagination on native `/v1` lists:** `limit` (1 to 500, default 100) and `cursor` in; `has_more` and `next_cursor` out. Also on `GET /v1/agent-kill-switches`, `GET /v1/agent-audit`, `GET /v1/agent/audit`, `GET /v1/connected-apps` and `GET /v1/agent/accounts`, where the existing items field is unchanged and the two fields are added. The lists on the compatible routes are unchanged. See [Pagination](https://tickwire.io/docs/pagination/). - **New error code:** [`invalid_cursor`](https://tickwire.io/docs/errors/invalid_cursor/). - **Account snapshot:** `GET /users/current/accounts/{id}/snapshot` and `GET /v1/agent/accounts/{id}/snapshot`: account information, positions, orders, health and server time in one read, with per-section freshness and an explicit broker UTC offset. MT4 and MT5. See [Health](https://tickwire.io/docs/health/#account-snapshot). - **New webhook events**, each sent only on evidence from the terminal: `position.opened`, `position.modified`, `position.closed`, `order.filled`, `order.cancelled`, `order.rejected`, `trade.outcome_unknown`, `account.connected`, `account.disconnected`, `account.login_failed`, `account.margin_call`, `account.stop_out`, `dedicated_ip.active`, `dedicated_ip.released`. `position.closed` carries `evidence`: `closing_deal` (sent at once, with the deal) or `unknown` (the position was missing from two consecutive reads and no closing deal was found). See [Webhooks](https://tickwire.io/docs/webhooks/#events). - **New response header:** `Idempotent-Replayed: true` on every answer served from the idempotency store; first executions never carry it. See [Idempotency](https://tickwire.io/docs/idempotency/). Deprecations: none. ## 2026-09-25: first version - **Version `2026-09-25` published.** This is the baseline for the native `/v1` API. Send `Tickwire-Version: 2026-09-25` to pin it per request; every `/v1` response echoes the version that served it. - **Rate limits published and enforced** with per-endpoint weights: standard calls and trades cost 1 unit, history 5, batch orders 10, a WebSocket connect 5. Trades have their own per-account budget. See [Rate limits](https://tickwire.io/docs/rate-limits/). - **New response headers:** `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy` (IETF draft) on every response, next to the existing `X-RateLimit-*`. - **Organisation pin.** Each organisation is pinned to a version (new organisations to the latest, existing ones to `2026-09-25`), used by `/v1` calls without `Tickwire-Version`. Read it with `GET /v1/api-version` and move it with `POST /v1/api-version` or in the dashboard settings; see [Versioning](https://tickwire.io/docs/versioning/#your-organisations-pin). - **New error codes:** [`invalid_api_version`](https://tickwire.io/docs/errors/invalid_api_version/) and [`api_version_unsupported`](https://tickwire.io/docs/errors/api_version_unsupported/). - A `429` on a trade or batch order now says `"sent": false`, `"outcome": "not_sent"`. Deprecations: none. --- # accepted > The same request is still being processed. Source: https://tickwire.io/docs/errors/accepted/ HTTP 202. **Likely cause:** A create request with the same transaction-id is still running. **What to do:** Repeat the same request after Retry-After seconds. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # AcceptedError > Error name for a request that is still being processed (`/users/current/…` routes only). Source: https://tickwire.io/docs/errors/acceptederror/ HTTP 202. **Likely cause:** Account creation for the same transaction-id is still running. **What to do:** Repeat the same request, with the same transaction-id, after Retry-After seconds. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # access_denied > OAuth (Sign in with Tickwire): the user pressed Cancel on the consent page (sent to the app's redirect URI). Source: https://tickwire.io/docs/errors/access_denied/ HTTP 302. **Likely cause:** The user declined to connect the app. **What to do:** Nothing was shared. Ask the user whether they want to connect, then start again. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # account_conflict > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/account_conflict/ `account_conflict` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # account_deploying > The account's terminal is starting. Source: https://tickwire.io/docs/errors/account_deploying/ HTTP 503. Nothing reached the broker. **Likely cause:** The account was just deployed or redeployed. **What to do:** Retry after Retry-After. The request was not sent. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # account_forbidden > This token is scoped to other accounts. Source: https://tickwire.io/docs/errors/account_forbidden/ HTTP 403. Nothing reached the broker. **Likely cause:** An account-scoped token was used for an account outside its scope. **What to do:** Use a token that covers this account. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # account_not_deployed > The account exists but has no running terminal. Source: https://tickwire.io/docs/errors/account_not_deployed/ HTTP 404. Nothing reached the broker. **Likely cause:** The account is undeployed, parked, or its deployment failed. **What to do:** Deploy the account, then retry. Its health routes still answer (200, status down, with the state and reason code), so read GET /users/current/accounts/{id}/health to see why it is not running. **Retry:** No. The same request gets the same answer; change something first. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # account_not_found > No trading account with this id belongs to you. Source: https://tickwire.io/docs/errors/account_not_found/ HTTP 404. Nothing reached the broker. **Likely causes:** - A typo in the account id. - The account belongs to another tenant (we answer 404, not 403, so ids are not disclosed). - The account was deleted. **What to do:** List your accounts and use one of their ids. **Retry:** No. The same request gets the same answer; change something first. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # account_unreachable > The account's terminal could not be reached. Source: https://tickwire.io/docs/errors/account_unreachable/ HTTP 502, 503. Nothing reached the broker. **Likely causes:** - The terminal is down or restarting. - The account is not deployed. **What to do:** Retry after Retry-After. We only return this when nothing was sent. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # admin_disabled > Status page: the admin API is switched off. Source: https://tickwire.io/docs/errors/admin_disabled/ HTTP 403. **Likely cause:** The status service's admin API is not enabled. **What to do:** Not for customers: only Tickwire staff use this API. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # agent_gateway_misconfigured > The agent API is not available right now. Source: https://tickwire.io/docs/errors/agent_gateway_misconfigured/ HTTP 503. Nothing reached the broker. **Likely cause:** A required server setting is missing. **What to do:** Contact support with the requestId. **Retry:** No. The same request gets the same answer; change something first. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # agent_key_not_found > No agent key with this id exists in your organisation. Source: https://tickwire.io/docs/errors/agent_key_not_found/ HTTP 404. **Likely cause:** Wrong id, or the key was deleted. **What to do:** List agent keys and use an existing id. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # already_member > The person is already a member of the organisation. Source: https://tickwire.io/docs/errors/already_member/ HTTP 409. **Likely cause:** An invite was sent to an existing member. **What to do:** Nothing to do. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # already_subscribed > The organisation already has a subscription. Source: https://tickwire.io/docs/errors/already_subscribed/ HTTP 409. **Likely cause:** A second checkout was started. **What to do:** Use Manage billing to change the plan. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # api_key_expired > The API token that sent this order has expired. Source: https://tickwire.io/docs/errors/api_key_expired/ HTTP 401. Nothing reached the broker. **Likely cause:** The token passed its expiry while the order was pending. **What to do:** Create a new token. Nothing was sent. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # api_key_revoked > The API key or token that sent this order was revoked or deleted. Source: https://tickwire.io/docs/errors/api_key_revoked/ HTTP 401. Nothing reached the broker. **Likely cause:** The key was revoked, possibly while the order was held. **What to do:** Use a current key. Nothing was sent. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # api_version_unsupported > The API version to pin is older than the oldest supported version. Source: https://tickwire.io/docs/errors/api_version_unsupported/ HTTP 400. **Likely cause:** The version is past its sunset, or predates every published version. **What to do:** Pin one of metadata.supportedVersions. The pin was not changed. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ApiError > Error name on the `/users/current/…` routes for a client error that has no more specific name. Source: https://tickwire.io/docs/errors/apierror/ HTTP 400, 405, 413, 415, 422. **Likely cause:** See the Tickwire code in the `code` field. **What to do:** Read `code` and open its page; fix the request. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # approval_belongs_to_the_hook > Only the pre-trade hook that placed a hold can approve it. Source: https://tickwire.io/docs/errors/approval_belongs_to_the_hook/ HTTP 403. **Likely cause:** An owner or another hook tried to approve the hold. **What to do:** Approve from the holding hook, or reject as the owner. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # authorization_server_unreachable > The MCP endpoint could not reach the Tickwire sign-in service to check the access token. Source: https://tickwire.io/docs/errors/authorization_server_unreachable/ HTTP 503. Nothing reached the broker. **Likely cause:** A network problem, or the sign-in service is restarting. **What to do:** Retry after a few seconds. The [status page](https://tickwire.io/status/) shows known incidents. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # authorization_unavailable > The Tickwire sign-in service could not check the access token right now. Source: https://tickwire.io/docs/errors/authorization_unavailable/ HTTP 503. Nothing reached the broker. **Likely cause:** The sign-in service answered with an unexpected error. **What to do:** Retry after a few seconds. If it keeps happening, sign in again from the AI app. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # backend_error > The terminal returned an error for this operation; the MetaTrader code is in `code` or `mt5Code`. Source: https://tickwire.io/docs/errors/backend_error/ HTTP 500, 502. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely causes:** - The terminal refused or failed the call. - The connection to the terminal failed mid-call. **What to do:** Reads: retry. Trades: do not resend blindly; repeat only with the same Idempotency-Key, which answers with the real outcome. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # bad_discount_code > The discount code is unknown or can't be used here. Source: https://tickwire.io/docs/errors/bad_discount_code/ HTTP 400. **Likely cause:** A typo, an expired code, or a code for another product. **What to do:** Check the code. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # bad_gateway > An upstream service gave an invalid answer. Source: https://tickwire.io/docs/errors/bad_gateway/ HTTP 502. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely cause:** A service between our API and the terminal failed. **What to do:** Reads: retry. Mutations: repeat only with the same Idempotency-Key. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # bad_path > The request path is malformed. Source: https://tickwire.io/docs/errors/bad_path/ HTTP 400. Nothing reached the broker. **Likely causes:** - The path does not start with '/'. - It has empty, '.' or '..' segments. **What to do:** Fix the URL. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # bad_request > The request is malformed. Source: https://tickwire.io/docs/errors/bad_request/ HTTP 400. Nothing reached the broker. **Likely cause:** An invalid header, parameter or body value. **What to do:** Fix the request; the message says what is wrong. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # bad_response > The Tickwire API answered the MCP tool without a JSON body. Source: https://tickwire.io/docs/errors/bad_response/ MCP tool result. **Likely cause:** Something in front of the API answered instead of it, for example during a restart. **What to do:** Repeat reads. For a trade, call `get_trade_status` with the same `idempotency_key` before sending it again. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # bad_signature > A billing webhook's signature did not verify. Source: https://tickwire.io/docs/errors/bad_signature/ HTTP 400. **Likely causes:** - Wrong webhook secret. - The body was changed in transit. **What to do:** Check the webhook secret configured at the payment provider. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # body_too_large > The request body exceeds the limit for this endpoint. Source: https://tickwire.io/docs/errors/body_too_large/ HTTP 413. **Likely cause:** A hold release body over the size limit. **What to do:** Send a smaller body. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # broker_offset_unknown > The broker's UTC offset is not known yet, so UTC times can't be given. Source: https://tickwire.io/docs/errors/broker_offset_unknown/ HTTP 503. **Likely cause:** No live ticks since the terminal started (weekend, closed market). **What to do:** Retry shortly, or omit timeBasis=utc to get broker time. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # broker_time_unknown > The broker's server time is not known yet. Source: https://tickwire.io/docs/errors/broker_time_unknown/ HTTP 503. **Likely cause:** No live ticks since the terminal started. **What to do:** Retry after Retry-After. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # busy > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/busy/ `busy` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # canary_not_found > Status page: no webhook-delivery canary has this id. Source: https://tickwire.io/docs/errors/canary_not_found/ HTTP 404. **Likely causes:** - The canary endpoint URL has a typo. - The canary probe is not configured (its secret is unset). **What to do:** Point the canary webhook at /api/v1/canary/webhooks/ of a configured webhook_receipt probe. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # candle_unavailable > No candle is available for this symbol and timeframe. Source: https://tickwire.io/docs/errors/candle_unavailable/ HTTP 404. **Likely cause:** The symbol has no history in the terminal for that timeframe yet. **What to do:** Retry later or use another timeframe. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Market data and platform support](https://tickwire.io/docs/errors/#market-data-and-platform-support) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # checkout_unavailable > Payments are not available right now. Source: https://tickwire.io/docs/errors/checkout_unavailable/ HTTP 503. **Likely cause:** The payment provider is not configured or not reachable. **What to do:** Try again later. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # component_not_found > Status page: no component with this id. Source: https://tickwire.io/docs/errors/component_not_found/ HTTP 404. **Likely cause:** A typo in the component id. **What to do:** Read /api/v1/status.json for the list of component ids. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # conflict > The request conflicts with the current state. Source: https://tickwire.io/docs/errors/conflict/ HTTP 409. **Likely cause:** The resource changed or already exists. **What to do:** Re-read the resource, then decide. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ConflictError > Error name for a conflict (409) on the `/users/current/…` routes. Source: https://tickwire.io/docs/errors/conflicterror/ HTTP 409. **Likely causes:** - The resource already exists. - An Idempotency-Key or clientId was reused for a different request. **What to do:** Read the Tickwire code in `code` (or `tickwireError`) for the exact reason. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # connected_app_not_found > OAuth (Sign in with Tickwire): no such connected app in this organisation. Source: https://tickwire.io/docs/errors/connected_app_not_found/ HTTP 404. **Likely cause:** Wrong id, or the app belongs to another organisation. **What to do:** List connected apps with GET /v1/connected-apps. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # consent_token_invalid > OAuth (Sign in with Tickwire): the approval did not come from the consent page this session opened (CSRF protection). Source: https://tickwire.io/docs/errors/consent_token_invalid/ HTTP 403. **Likely causes:** - The page was reloaded (a new token was issued) or the request was forged. - Another session or organisation tried to answer the request. **What to do:** Reload the consent page and answer again. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # controlplane_unavailable > We could not check your token or route the request. Source: https://tickwire.io/docs/errors/controlplane_unavailable/ HTTP 503. Nothing reached the broker. **Likely cause:** An internal service is restarting or overloaded. **What to do:** Retry after Retry-After. Nothing was sent. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # controlplane_unreachable > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/controlplane_unreachable/ `controlplane_unreachable` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # credential_error > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/credential_error/ `credential_error` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # dedicated_ip_refused > The dedicated-IP change can't be made. Source: https://tickwire.io/docs/errors/dedicated_ip_refused/ HTTP 409. **Likely causes:** - The requested count is above what the plan allows. - An IP is still in use by an account. **What to do:** Read the message; change the count or free the IP. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # depth_unavailable > The terminal has no market depth for this symbol. Source: https://tickwire.io/docs/errors/depth_unavailable/ HTTP 404. **Likely cause:** The broker does not publish depth for the symbol. **What to do:** Use quotes instead. **Retry:** No. The same request gets the same answer; change something first. Listed under [Market data and platform support](https://tickwire.io/docs/errors/#market-data-and-platform-support) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # discount_too_large > The discount code gives more off than allowed. Source: https://tickwire.io/docs/errors/discount_too_large/ HTTP 400. **Likely cause:** The code takes more off than we accept for this order. **What to do:** Use another code. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # docs_unavailable > The MCP docs search could not fetch the Tickwire docs. Source: https://tickwire.io/docs/errors/docs_unavailable/ MCP tool result. **Likely cause:** The docs site was unreachable or slow. **What to do:** Try the search again later, or read the docs at [/docs/](https://tickwire.io/docs/). **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # driver_error > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/driver_error/ `driver_error` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # duplicate > This already exists. Source: https://tickwire.io/docs/errors/duplicate/ HTTP 409. **Likely causes:** - The trading account is already linked. - A token id is already in use. **What to do:** Use the existing resource. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # egress_in_use > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/egress_in_use/ `egress_in_use` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # egress_unavailable > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/egress_unavailable/ `egress_unavailable` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # email_notifications_unavailable > Status page: email updates are not available yet. Source: https://tickwire.io/docs/errors/email_notifications_unavailable/ HTTP 503. **Likely cause:** Email updates aren't switched on yet. **What to do:** Follow the RSS, Atom or JSON feed instead; the message has their URLs. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # email_taken > An account with this email already exists. Source: https://tickwire.io/docs/errors/email_taken/ HTTP 409. **Likely cause:** Sign-up with a registered email. **What to do:** Sign in instead. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # endpoint_deleted > A webhook delivery was abandoned because its endpoint was deleted (the delivery's `error`, not an HTTP status). Source: https://tickwire.io/docs/errors/endpoint_deleted/ Not an HTTP error. **Likely cause:** The webhook endpoint was deleted while deliveries were still queued. **What to do:** Nothing to do. Create a new endpoint to receive future events. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # endpoint_disabled > A webhook delivery was abandoned because its endpoint is disabled (the delivery's `error`, not an HTTP status). Source: https://tickwire.io/docs/errors/endpoint_disabled/ Not an HTTP error. **Likely causes:** - You disabled the endpoint. - We disabled it after it kept failing (for example 72 hours of failures). **What to do:** Fix the endpoint, re-enable it, then resend the events you missed while they are inside the resend window. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # event_expired > A webhook delivery was abandoned because the event is past its retention (the delivery's `error`, not an HTTP status). Source: https://tickwire.io/docs/errors/event_expired/ Not an HTTP error. **Likely cause:** The endpoint stayed down longer than events are kept. **What to do:** Reconcile from the API (positions, orders, history) instead of waiting for the event. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # event_ingest_unavailable > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/event_ingest_unavailable/ `event_ingest_unavailable` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # event_scope_mismatch > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/event_scope_mismatch/ `event_scope_mismatch` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # event_type_not_allowed > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/event_type_not_allowed/ `event_type_not_allowed` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # events_token_invalid > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/events_token_invalid/ `events_token_invalid` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # execution_unavailable > A trade sent over streaming could not reach the execution service, so it was not sent (`stringCode` of a streaming `InternalError`). Source: https://tickwire.io/docs/errors/execution_unavailable/ WebSocket error frame. Nothing reached the broker. **Likely cause:** A short outage inside Tickwire. **What to do:** Retry with the same `requestId`. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # forbidden > Your credential may not do this. Source: https://tickwire.io/docs/errors/forbidden/ HTTP 403. Nothing reached the broker. **Likely causes:** - A read-only key on a mutating route. - Your role lacks the permission. **What to do:** Use a credential with the needed access. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ForbiddenError > Error name for a forbidden request (403) on the `/users/current/…` routes. Source: https://tickwire.io/docs/errors/forbiddenerror/ HTTP 403. **Likely cause:** The token may not do this (read-only, account-scoped, or missing a role). **What to do:** Use a token with the needed access. The Tickwire code is in `code`. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # gateway_timeout > An upstream did not answer in time. Source: https://tickwire.io/docs/errors/gateway_timeout/ HTTP 504. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely cause:** The terminal or a service is slow or stuck. **What to do:** Reads: retry. Mutations: the outcome is unknown; repeat only with the same Idempotency-Key. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hold_expired > A held order expired before a decision; it was not and will not be executed. Source: https://tickwire.io/docs/errors/hold_expired/ HTTP 409. Nothing reached the broker. **Likely cause:** The pre-trade hook did not approve in time. **What to do:** Send a new order with a new Idempotency-Key if still wanted. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hold_not_found > No such hold. Source: https://tickwire.io/docs/errors/hold_not_found/ HTTP 404. **Likely cause:** Wrong hold id. **What to do:** Check the id. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hold_rejected > A held order was rejected by the pre-trade hook or the owner; nothing was sent. Source: https://tickwire.io/docs/errors/hold_rejected/ HTTP 409. Nothing reached the broker. **Likely cause:** The hook or owner rejected the hold. **What to do:** Read the message for why. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hook_denied > The account owner's pre-trade hook denied this order; nothing was sent. Source: https://tickwire.io/docs/errors/hook_denied/ HTTP 403. Nothing reached the broker. **Likely cause:** The order broke a rule the hook enforces. **What to do:** Read `hook_message`. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hook_exists > This account or agent key already has a pre-trade hook. Source: https://tickwire.io/docs/errors/hook_exists/ HTTP 409. **Likely cause:** A second hook was created. **What to do:** Update or delete the existing hook. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hook_not_found > No such pre-trade hook. Source: https://tickwire.io/docs/errors/hook_not_found/ HTTP 404. **Likely cause:** Wrong id. **What to do:** Check the id. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hook_not_holding > This hook did not place this hold. Source: https://tickwire.io/docs/errors/hook_not_holding/ HTTP 403. **Likely cause:** A different hook tried to release the hold. **What to do:** Release from the hook that holds it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # hook_unavailable > The pre-trade hook didn't give a valid answer. The hook fails closed, so the order wasn't sent. Source: https://tickwire.io/docs/errors/hook_unavailable/ HTTP 503. Nothing reached the broker. **Likely cause:** The hook URL is down, slow or answered invalidly. **What to do:** Fix the hook, then send the order again. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # host_retired > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/host_retired/ `host_retired` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # http_error > An HTTP error with no more specific code. Source: https://tickwire.io/docs/errors/http_error/ HTTP 404, 405. **Likely causes:** - Status page API: the path or method does not exist (a typo in the URL, or the wrong HTTP method). - MCP tool result: the Tickwire API answered with an HTTP error whose body had no code of its own; `message` gives the HTTP status. **What to do:** Check the path and the method. From an MCP tool, read `message` and retry only if the status says it is temporary (429 or 5xx). **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # idempotency_conflict > This Idempotency-Key was already used with a different request body. Source: https://tickwire.io/docs/errors/idempotency_conflict/ HTTP 409. Nothing reached the broker. **Likely cause:** A key was reused for a new request. **What to do:** Use a new key for a new request; the earlier one stands. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # idempotency_in_flight > A request with this Idempotency-Key is still running. This request was not sent (`sent: false`); the earlier one may still execute. Source: https://tickwire.io/docs/errors/idempotency_in_flight/ HTTP 409. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely cause:** A retry arrived before the first attempt finished, for example after a gateway timeout (504) or a client-side timeout. **What to do:** Wait Retry-After seconds, then repeat with the same key: once the first attempt finishes you get its stored result. Never switch to a new key while the outcome is open, and check positions and orders (or the trade status by key) first. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # idempotency_key_required > Every trade needs an Idempotency-Key. Source: https://tickwire.io/docs/errors/idempotency_key_required/ HTTP 400. Nothing reached the broker. **Likely cause:** The header is missing or too long. **What to do:** Send a unique Idempotency-Key. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # idempotency_key_reused > This Idempotency-Key was used for a different order, account or batch; this request was not sent. Source: https://tickwire.io/docs/errors/idempotency_key_reused/ HTTP 409, 422. Nothing reached the broker. **Likely cause:** A key was reused for a new request. **What to do:** Use a new key; the earlier request stands. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # idempotency_unavailable > Idempotency can't be guaranteed right now, so nothing was sent. Source: https://tickwire.io/docs/errors/idempotency_unavailable/ HTTP 503. Nothing reached the broker. **Likely causes:** - The idempotency store is unavailable. - The idempotency store is full of requests that are still running. **What to do:** Retry after Retry-After, or drop the header to trade without idempotency. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # incident_closed > Status page: the incident or maintenance is already resolved or completed. Source: https://tickwire.io/docs/errors/incident_closed/ HTTP 409. **Likely cause:** An update was posted to a closed incident. **What to do:** Open a new incident; a closed one takes no more updates. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # incident_not_closed > Status page: a postmortem can only be written once the incident is resolved. Source: https://tickwire.io/docs/errors/incident_not_closed/ HTTP 409. **Likely cause:** The incident is still open. **What to do:** Resolve the incident first, then write the postmortem. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # incident_not_found > Status page: no incident with this id. Source: https://tickwire.io/docs/errors/incident_not_found/ HTTP 404. **Likely cause:** A typo in the incident id. **What to do:** List incidents with /api/v1/incidents. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # insufficient_balance > The wallet balance does not cover this purchase. Source: https://tickwire.io/docs/errors/insufficient_balance/ HTTP 402. **Likely cause:** Not enough prepaid balance; `shortfall_eur_cents` says how much is missing. **What to do:** Top up, then repeat. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # interaction_required > OAuth (Sign in with Tickwire): the user has to approve the app on the consent page (shown on the sign-in error page). Source: https://tickwire.io/docs/errors/interaction_required/ HTTP 400. **Likely cause:** The app sent prompt=none. **What to do:** Start the sign-in without prompt=none. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # internal_error > An unexpected failure inside Tickwire. Source: https://tickwire.io/docs/errors/internal_error/ HTTP 500. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely cause:** A bug or an unexpected state. **What to do:** Reads: retry. Mutations: repeat only with the same Idempotency-Key. If the answer has created_id, a credential (key, token or hook secret) was created before the failure: revoke or rotate it by that id. Report the requestId if it persists. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # InternalError > Error name for a server-side failure on the `/users/current/…` routes. Source: https://tickwire.io/docs/errors/internalerror/ HTTP 500, 502, 503, 504. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely causes:** - The terminal returned an error. - A Tickwire service failed. **What to do:** Read the Tickwire code in `code` or `tickwireError`. Reads can be retried; repeat a trade only with the same clientId or Idempotency-Key. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid > The subscription frame on the terminal WebSocket (`/{mt4|mt5}/{id}/ws`) is invalid. Source: https://tickwire.io/docs/errors/invalid/ WebSocket error frame. **Likely causes:** - Unknown topic. - A prices or bars topic without a symbol. **What to do:** Fix the subscription frame. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_actor > X-Actor names a server-assigned identity that is not the calling credential's own. Nothing was changed. Source: https://tickwire.io/docs/errors/invalid_actor/ HTTP 400. Nothing reached the broker. **Likely cause:** The value starts with api-key:, user: or firebase: but is not api-key: (or, for a signed-in user, your own firebase: id). **What to do:** Send a free-text label (for example copier-7 or ops:jane), your own api-key:, or no X-Actor. The audit log always records the calling credential's key_id separately. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_agent_key > The agent key is missing, invalid or revoked. Source: https://tickwire.io/docs/errors/invalid_agent_key/ HTTP 401. Nothing reached the broker. **Likely cause:** No X-Tickwire-Agent-Key header, or a revoked key. **What to do:** Send a valid agent key (twag_...). **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_api_version > The Tickwire-Version header, or the apiVersion to pin, names no published API version. Source: https://tickwire.io/docs/errors/invalid_api_version/ HTTP 400. Nothing reached the broker. **Likely causes:** - The value is not a date in YYYY-MM-DD form. - The date is not one of the published versions (the message and metadata.supportedVersions list them). **What to do:** Send a published version from the versioning page, or omit the header to use your organisation's pinned version. Nothing was sent or changed. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_batch > The batch request is invalid; nothing was sent. Source: https://tickwire.io/docs/errors/invalid_batch/ HTTP 400. Nothing reached the broker. **Likely cause:** A malformed leg or a missing field. **What to do:** Fix the batch; the message names the field. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_client > OAuth (Sign in with Tickwire): the client could not be identified or authenticated. Source: https://tickwire.io/docs/errors/invalid_client/ HTTP 400, 401. **Likely causes:** - Unknown client_id: register the app first (DCR) or use a valid client metadata document URL. - Wrong or missing client secret for a confidential client, or a secret sent by a public client. - The client metadata document could not be loaded or is invalid. - The app sent a token exchange request with credentials we do not accept. **What to do:** Check the client registration and its credentials; re-register if needed. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_client_metadata > OAuth (Sign in with Tickwire): the dynamic client registration request is not acceptable. Source: https://tickwire.io/docs/errors/invalid_client_metadata/ HTTP 400. **Likely causes:** - The body is not a JSON object. - Unsupported grant_types, response_types or token_endpoint_auth_method. **What to do:** Register with response_types ["code"], grant_types authorization_code (+ refresh_token), and auth method none, client_secret_post or client_secret_basic. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_credentials > Email or password is wrong. Source: https://tickwire.io/docs/errors/invalid_credentials/ HTTP 401. **Likely cause:** Wrong password. **What to do:** Check the credentials, or use a magic link. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_cursor > The pagination cursor is not one this list issued. Source: https://tickwire.io/docs/errors/invalid_cursor/ HTTP 400. **Likely causes:** - The cursor was edited, truncated, or taken from a different list endpoint. - The filters changed between pages (a cursor is bound to the list and filters it came from). **What to do:** Start again without cursor, or pass the next_cursor value from the previous page unchanged with the same filters. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_egress_ip > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/invalid_egress_ip/ `invalid_egress_ip` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # invalid_email > The email address is not valid. Source: https://tickwire.io/docs/errors/invalid_email/ HTTP 400. **Likely cause:** A typo. **What to do:** Enter a valid email address. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_grant > OAuth (Sign in with Tickwire): the authorization code, refresh token or access token is not valid for this request. Source: https://tickwire.io/docs/errors/invalid_grant/ HTTP 400. **Likely causes:** - The code or refresh token was already used, expired or revoked. - A rotated-out refresh token was reused, so the whole token chain was revoked. - PKCE verification failed, or redirect_uri differs from the authorization request. - The connection was disconnected, expired, or its agent key was revoked. - The access token was issued for another resource (MCP server URL). **What to do:** Start the sign-in again from the app (a new authorization request). Never retry with the same refresh token. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_hook > The pre-trade hook definition is invalid. Source: https://tickwire.io/docs/errors/invalid_hook/ HTTP 400. **Likely cause:** A hook on an agent key must apply to agents only. **What to do:** Fix the hook body. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_hook_url > The pre-trade hook URL is not allowed. Source: https://tickwire.io/docs/errors/invalid_hook_url/ HTTP 400. **Likely cause:** Not https, or it points to a private address. **What to do:** Use a public https URL. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_idempotency_key > The Idempotency-Key (or `transaction-id` header) is longer than 255 characters or holds non-printable characters. Nothing was changed. Source: https://tickwire.io/docs/errors/invalid_idempotency_key/ HTTP 400. Nothing reached the broker. **Likely cause:** A key built from long ids, or one carrying control characters, tabs or bidi marks. **What to do:** Send 1 to 255 printable characters. Keys are never truncated, so two long keys can't collide. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_incident_status > Status page: that status doesn't belong to this kind of event. Source: https://tickwire.io/docs/errors/invalid_incident_status/ HTTP 422. **Likely cause:** An incident given a maintenance status (scheduled, in_progress, completed), or the reverse. **What to do:** Incidents use investigating, identified, monitoring, resolved; maintenance uses scheduled, in_progress, completed. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_link > The sign-in or invite link is invalid or expired. Source: https://tickwire.io/docs/errors/invalid_link/ HTTP 401. **Likely cause:** The link was used already or is too old. **What to do:** Request a new link. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_maintenance > Status page: the maintenance window is invalid. Source: https://tickwire.io/docs/errors/invalid_maintenance/ HTTP 422. **Likely causes:** - scheduled_for is missing. - scheduled_until is not after scheduled_for. **What to do:** Send a start time, and an end time after it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_message > A WebSocket frame is not a valid message (sent as an error frame, not an HTTP status). Source: https://tickwire.io/docs/errors/invalid_message/ WebSocket error frame. **Likely cause:** Not JSON, not an object, an unknown type, or a bad field. **What to do:** Fix the frame; the message names the field. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_order > The order is invalid; nothing was sent. Source: https://tickwire.io/docs/errors/invalid_order/ HTTP 400. Nothing reached the broker. **Likely cause:** A missing or malformed order field. **What to do:** Fix the order; the message names the field. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_parameter > A query or path parameter is invalid; `details` names it. Source: https://tickwire.io/docs/errors/invalid_parameter/ HTTP 400. **Likely cause:** A value out of range or of the wrong type. **What to do:** Fix the parameter. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_redirect_uri > OAuth (Sign in with Tickwire): a registered redirect URI is not allowed. Source: https://tickwire.io/docs/errors/invalid_redirect_uri/ HTTP 400. **Likely causes:** - Not https, not loopback http, and not a reverse-domain app scheme. - It has a fragment, user info, backslashes or spaces, or is longer than 2000 characters. - More than 10 redirect URIs. **What to do:** Use exact https redirect URIs (or http on 127.0.0.1, [::1] or localhost). **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_request > The request body is invalid. Source: https://tickwire.io/docs/errors/invalid_request/ HTTP 400. **Likely cause:** Not a JSON object, or a field fails validation. **What to do:** Fix the body; the message names the field. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_scope > OAuth (Sign in with Tickwire): the requested scope is wider than what was granted. Source: https://tickwire.io/docs/errors/invalid_scope/ HTTP 400. **Likely cause:** A refresh request asked for a scope the user did not grant (for example tickwire.trade on a read-only connection). **What to do:** Refresh without scope, or ask the user to connect again with the wider access. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_signature > A hold release was not signed with the holding hook's secret. Source: https://tickwire.io/docs/errors/invalid_signature/ HTTP 401. **Likely cause:** Wrong secret, missing headers, or a stale timestamp. **What to do:** Sign with X-Tickwire-Hook-Id, X-Tickwire-Timestamp and X-Tickwire-Signature. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_subscription > A market-data subscription is invalid (sent as an error frame). Source: https://tickwire.io/docs/errors/invalid_subscription/ WebSocket error frame. **Likely cause:** Unknown market data type, or a bad interval or timeframe. **What to do:** Fix the subscription. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_target > OAuth (Sign in with Tickwire): the resource parameter is not the Tickwire MCP server. Source: https://tickwire.io/docs/errors/invalid_target/ HTTP 400. **Likely causes:** - resource names another server, or several resources were requested. - At the token endpoint, resource differs from the one the grant was issued for. **What to do:** Send resource set to the Tickwire MCP server URL: the same address you gave the app, shown on the AI agents page. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_token > The token is invalid, expired or revoked. Source: https://tickwire.io/docs/errors/invalid_token/ HTTP 401. Nothing reached the broker. **Likely cause:** A typo, or the token was revoked or expired. **What to do:** Use a current token. Repeated bad tokens from one IP are rate limited. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # invalid_url > The webhook URL is not allowed. The message is the same whatever rule refused it. Source: https://tickwire.io/docs/errors/invalid_url/ HTTP 400. **Likely causes:** - Not https://. - The host is localhost, *.localhost, *.internal or *.local, or the URL carries a username or password. - The host is, or resolves to, a non-public address (loopback, private, link-local, carrier-grade NAT, multicast, reserved), or cannot be resolved. - Re-enabling an endpoint whose URL breaks these rules. **What to do:** Use an https URL whose host resolves only to public internet addresses. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ip_allocation_refused > The dedicated-IP operation can't be done in the IP's current state. Source: https://tickwire.io/docs/errors/ip_allocation_refused/ HTTP 409. **Likely cause:** For example, confirming cancellation before release. **What to do:** Follow the order in the message. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ip_not_allowed > The token is valid, but it has an IP allowlist and this request came from an address outside it. The message never shows the allowlist. Source: https://tickwire.io/docs/errors/ip_not_allowed/ HTTP 403. Nothing reached the broker. **Likely causes:** - The call came from a server or network that is not on the token's allowlist. - Your public IP changed (a new office line, VPN, NAT or cloud egress address). - The allowlist was narrowed; open WebSockets using the token are closed (code 1008) at the next re-check. **What to do:** Call from an address on the allowlist, or create a token whose allowlist includes this address. Retrying from the same address will not help. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ip_previously_owned > This IP has had an owner before; a dedicated IP is never reassigned. Source: https://tickwire.io/docs/errors/ip_previously_owned/ HTTP 409. **Likely cause:** An attempt to allocate a previously held IP. **What to do:** Allocate a fresh IP. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # keyring_missing > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/keyring_missing/ `keyring_missing` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # kill_switch_engaged > The kill switch for this account or agent key is engaged; nothing was sent. Source: https://tickwire.io/docs/errors/kill_switch_engaged/ HTTP 403. Nothing reached the broker. **Likely cause:** The owner engaged the kill switch (`scope`, `kill_reason`). **What to do:** The owner must release the kill switch. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # last_owner > An organisation needs at least one owner. Source: https://tickwire.io/docs/errors/last_owner/ HTTP 409. **Likely cause:** Removing or demoting the last owner. **What to do:** Promote another member first. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # length_required > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/length_required/ `length_required` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # market_depth_unavailable > The terminal gave no market depth for the symbol (stream error frame). Source: https://tickwire.io/docs/errors/market_depth_unavailable/ WebSocket error frame. **Likely cause:** The broker does not publish depth for it. **What to do:** Unsubscribe from marketDepth for this symbol. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # method_access > This token may not call this method. Source: https://tickwire.io/docs/errors/method_access/ HTTP 403. **Likely causes:** - An account-access token on an account-management method. - A token without the needed application or role. **What to do:** Use an owner credential or a token with the role. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # method_not_allowed > This HTTP method is not supported on this path. Source: https://tickwire.io/docs/errors/method_not_allowed/ HTTP 405. Nothing reached the broker. **Likely cause:** For example POST on a read-only route. **What to do:** Check the API reference. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # missing_agent_key > The MCP endpoint needs a Tickwire agent key, and none was sent. Source: https://tickwire.io/docs/errors/missing_agent_key/ HTTP 401. Nothing reached the broker. **Likely causes:** - No `Authorization: Bearer …` header. - The bearer value is not an agent key (agent keys start with `twag_`). **What to do:** Create an agent key in the dashboard and send it as `Authorization: Bearer twag_…`. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # missing_credentials > The MCP endpoint was called without a sign-in or an agent key. Source: https://tickwire.io/docs/errors/missing_credentials/ HTTP 401. Nothing reached the broker. **Likely causes:** - The AI app has not signed in with Tickwire yet. - No `Authorization: Bearer …` header (or `X-Tickwire-Agent-Key`) was sent. **What to do:** Sign in with Tickwire from the AI app (it follows the `WWW-Authenticate` header in this answer), or send an agent key as `Authorization: Bearer twag_…`. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # missing_header > A required header is missing. Source: https://tickwire.io/docs/errors/missing_header/ HTTP 400. **Likely causes:** - X-Actor, X-Reason or Idempotency-Key is missing on a mutating call. - X-Actor, X-Reason or Idempotency-Key is missing when changing the API version pin. **What to do:** Send the headers named in the message. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # missing_token > No token was sent. Source: https://tickwire.io/docs/errors/missing_token/ HTTP 401. Nothing reached the broker. **Likely cause:** No auth-token, X-API-Key, Authorization: Bearer or ?auth-token= (WebSockets). **What to do:** Send your token. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # MRPC > Terminal route error (`/{mt4|mt5}/{id}/…`): the terminal processed the request but the operation failed. Source: https://tickwire.io/docs/errors/mrpc/ HTTP 500. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely causes:** - Unknown symbol (`reason: symbol_not_found`). - The terminal returned an error (`reason: backend_error`, MT code in `code`). **What to do:** Check `reason`. Fix the symbol, or retry a read. Repeat a trading call only with the same Idempotency-Key. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # MRPC_NOT_CONNECTED > Terminal route error (`/{mt4|mt5}/{id}/…`): the terminal has no broker connection right now. Source: https://tickwire.io/docs/errors/mrpc_not_connected/ HTTP 503. Nothing reached the broker. **Likely causes:** - The terminal is starting or reconnecting. - The broker server is down or rejected the login. **What to do:** Retry with backoff and check the account's health endpoint. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # MRPC_VALIDATION > Terminal route error (`/{mt4|mt5}/{id}/…`): a parameter is missing or invalid. Source: https://tickwire.io/docs/errors/mrpc_validation/ HTTP 400. Nothing reached the broker. **Likely causes:** - A required query or body field is missing. - A value has the wrong type or range. **What to do:** Fix the request; the message names the parameter. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # no_org > No organisation is selected. Source: https://tickwire.io/docs/errors/no_org/ HTTP 400. **Likely cause:** A dashboard session without an active organisation. **What to do:** Select or create an organisation. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # no_subscription > There is no subscription to manage yet. Source: https://tickwire.io/docs/errors/no_subscription/ HTTP 409. **Likely causes:** - Manage billing was opened before any subscription. - Cancel or resume was asked for without a subscription to cancel. **What to do:** Start a subscription first. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_connected > The terminal has no broker connection right now. Source: https://tickwire.io/docs/errors/not_connected/ HTTP 503. Nothing reached the broker. **Likely causes:** - The terminal is starting or reconnecting. - The broker server is unreachable or rejected the login. **What to do:** Retry with backoff and check the account's health. A trade answered with this was not sent. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_found > No such endpoint or resource. Source: https://tickwire.io/docs/errors/not_found/ HTTP 404. **Likely cause:** A wrong path or id. **What to do:** Check the URL and ids. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_implemented > This is not implemented here. Source: https://tickwire.io/docs/errors/not_implemented/ HTTP 501. **Likely cause:** A feature this backend or platform does not provide. **What to do:** Check the platform notes. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_revealable > Key values are shown only once, at creation (or rotation), and stored hashed. Source: https://tickwire.io/docs/errors/not_revealable/ HTTP 400. **Likely cause:** An attempt to reveal an existing full, read-only or sandbox key: only a digest is stored. **What to do:** Create a new key if you lost it, or rotate a read-only key to get a new value. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_subscribed > Unsubscribe without a subscription (stream error frame). Source: https://tickwire.io/docs/errors/not_subscribed/ WebSocket error frame. **Likely cause:** An unsubscribe before subscribe. **What to do:** Subscribe first. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_supported > This terminal backend does not provide the requested stream (stream error frame). Source: https://tickwire.io/docs/errors/not_supported/ WebSocket error frame. **Likely cause:** Market depth on a backend without it. **What to do:** Unsubscribe from it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_supported_on_mt4 > MetaTrader 4 doesn't support this. Source: https://tickwire.io/docs/errors/not_supported_on_mt4/ HTTP 400, 501. Nothing reached the broker. **Likely cause:** Market depth, tick history, stop-limit orders, OrderCheck and other MT5-only features. **What to do:** Use an MT5 account for this feature. Nothing was sent. **Retry:** No. The same request gets the same answer; change something first. Listed under [Market data and platform support](https://tickwire.io/docs/errors/#market-data-and-platform-support) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # not_supported_on_mt5 > MetaTrader 5 can't do this. Source: https://tickwire.io/docs/errors/not_supported_on_mt5/ HTTP 400, 501. Nothing reached the broker. **Likely cause:** An MT4-only feature asked of an MT5 account. **What to do:** Use the MT5 equivalent. Nothing was sent. **Retry:** No. The same request gets the same answer; change something first. Listed under [Market data and platform support](https://tickwire.io/docs/errors/#market-data-and-platform-support) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # NotAuthenticatedError > Error name in a streaming error: the account's terminal is not connected, or the account is not subscribed on this connection. Source: https://tickwire.io/docs/errors/notauthenticatederror/ WebSocket error frame. **Likely causes:** - The terminal is starting, reconnecting or stopped. - A request for an account this connection has not subscribed to. **What to do:** Subscribe to the account first. If it is subscribed, wait for the terminal to connect (see [Health](https://tickwire.io/docs/health/)) and retry. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # NotConnectedError > Error name on the `/users/current/…` routes: the terminal is not connected to the broker. Source: https://tickwire.io/docs/errors/notconnectederror/ HTTP 503. Nothing reached the broker. **Likely causes:** - The terminal is starting or reconnecting. - The broker server is unreachable. **What to do:** Retry after Retry-After; check account health. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # NotFoundError > Error name for a missing resource on the `/users/current/…` routes. Source: https://tickwire.io/docs/errors/notfounderror/ HTTP 404. **Likely cause:** See the Tickwire code in `code` or `tickwireError`. **What to do:** Check the id or symbol in the path. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # NotSynchronizedError > Error name on the `/users/current/…` routes: the terminal is not synchronized enough to answer (for example the broker time is not known yet). Source: https://tickwire.io/docs/errors/notsynchronizederror/ HTTP 503. **Likely cause:** No live ticks have arrived since the terminal started. **What to do:** Retry after Retry-After. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # oauth_not_configured > OAuth (Sign in with Tickwire): sign-in for AI apps is not enabled on this deployment. Source: https://tickwire.io/docs/errors/oauth_not_configured/ HTTP 404. **Likely cause:** Sign in with Tickwire is switched off or not fully set up on this server. **What to do:** Use an agent key instead, or contact support. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # order_not_found > No pending order with this id. Source: https://tickwire.io/docs/errors/order_not_found/ HTTP 404. **Likely cause:** It filled, was cancelled, or the id is wrong. **What to do:** Check history for it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ordering_not_configured > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/ordering_not_configured/ `ordering_not_configured` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # outcome_unknown > A trade sent over streaming got no answer from the execution service; it may have executed (`stringCode` of a streaming `InternalError`). Source: https://tickwire.io/docs/errors/outcome_unknown/ WebSocket error frame. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely cause:** The execution service or the terminal did not answer in time. **What to do:** Retry with the same `requestId` to learn the real outcome. Never send a new trade blindly. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # payload_too_large > The request body is too large. Source: https://tickwire.io/docs/errors/payload_too_large/ HTTP 413. Nothing reached the broker. **Likely cause:** A body over our size limit. **What to do:** Send less data per request. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # payment_provider_error > The payment provider failed the call. Source: https://tickwire.io/docs/errors/payment_provider_error/ HTTP 502. **Likely cause:** The provider is down or refused; `provider_code` has its code. **What to do:** Try again later. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # PaymentRequiredError > Error name for a request that needs payment (402) on the `/users/current/…` routes. Source: https://tickwire.io/docs/errors/paymentrequirederror/ HTTP 402. **Likely cause:** The wallet balance does not cover the purchase. **What to do:** Top up, then repeat. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ports_exhausted > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/ports_exhausted/ `ports_exhausted` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # position_not_found > No open position with this id. Source: https://tickwire.io/docs/errors/position_not_found/ HTTP 404. **Likely cause:** It was closed, or the id is wrong. **What to do:** Check history for it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # postmortem_not_found > Status page: this incident has no postmortem. Source: https://tickwire.io/docs/errors/postmortem_not_found/ HTTP 404. **Likely cause:** None was written, or it was deleted. **What to do:** Write one with PUT /api/v1/incidents/{id}/postmortem. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # pretrade_unavailable > The pre-trade check (pre-trade hooks) could not be completed, so the order was not sent. Source: https://tickwire.io/docs/errors/pretrade_unavailable/ HTTP 503. Nothing reached the broker. **Likely cause:** Our API or the pre-trade hook service is unreachable or slow. **What to do:** Retry after Retry-After with the same Idempotency-Key. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # rate_limited > Too many requests. Source: https://tickwire.io/docs/errors/rate_limited/ HTTP 429. Nothing reached the broker. **Likely causes:** - The per-key, per-account, per-account trade or per-IP budget is used up (metadata.bucket names it). - A heavy call (history, batch, stream connect) costs more than one unit. - Too many sandbox sign-ups from one address in an hour or a day, or from everyone in an hour (POST /v1/sandbox/signup). **What to do:** Wait for Retry-After, then retry. A refused trade carries sent: false: it was not sent, so it is safe to resend. See the rate-limits page. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # read_only_key > This key is read-only; it can't trade. Source: https://tickwire.io/docs/errors/read_only_key/ HTTP 403. Nothing reached the broker. **Likely cause:** A read-only API key or agent key sent an order. **What to do:** Use a full key. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # read_only_token > This token is read-only. Source: https://tickwire.io/docs/errors/read_only_token/ HTTP 403. Nothing reached the broker. **Likely cause:** A read-only token on a mutating route. **What to do:** Use a token with write access. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # reason_required > Every trade needs a reason (X-Reason). Source: https://tickwire.io/docs/errors/reason_required/ HTTP 400. Nothing reached the broker. **Likely causes:** - The X-Reason header is missing. - An MCP trading tool was called without a `reason`. **What to do:** Say why in X-Reason (or the MCP tool's `reason`). **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # reason_too_long > The reason is too long. Source: https://tickwire.io/docs/errors/reason_too_long/ HTTP 400. Nothing reached the broker. **Likely cause:** X-Reason over the limit. **What to do:** Shorten it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # request_belongs_to_someone_else > OAuth (Sign in with Tickwire): this sign-in request was opened by another signed-in user first. Source: https://tickwire.io/docs/errors/request_belongs_to_someone_else/ HTTP 403. **Likely cause:** The sign-in link was opened by someone else (or in another organisation) before you. **What to do:** Start connecting again from the app. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # request_body_timeout > The request body did not arrive in time; nothing was forwarded. Source: https://tickwire.io/docs/errors/request_body_timeout/ HTTP 408. Nothing reached the broker. **Likely cause:** The client sent the body too slowly (inbound provider webhooks allow 10 seconds by default). **What to do:** Send the whole body promptly, then retry. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # request_expired > OAuth (Sign in with Tickwire): the sign-in request is older than 10 minutes. Source: https://tickwire.io/docs/errors/request_expired/ HTTP 410. **Likely cause:** The consent page was left open too long. **What to do:** Start connecting again from the app. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # request_header_fields_too_large > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/request_header_fields_too_large/ `request_header_fields_too_large` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # request_log_not_found > There is no request log entry with this id in your organisation. Source: https://tickwire.io/docs/errors/request_log_not_found/ HTTP 404. **Likely causes:** - The id is mistyped, or belongs to another organisation. - The entry is older than 14 days, or was removed to keep the organisation within its request-log limits. **What to do:** List recent calls with GET /v1/request-logs (filter by requestId) and use an id from there. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # request_not_found > No trade was recorded under this Idempotency-Key. Source: https://tickwire.io/docs/errors/request_not_found/ HTTP 404. **Likely cause:** Nothing was sent with it, or it was refused before sending. **What to do:** It is safe to send the order with this key. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # request_not_supported > OAuth (Sign in with Tickwire): request objects (request, request_uri) are not supported (shown on the sign-in error page). Source: https://tickwire.io/docs/errors/request_not_supported/ HTTP 400. **Likely cause:** The authorization request carried a request or request_uri parameter. **What to do:** Send the authorization parameters in the query string. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # request_used > OAuth (Sign in with Tickwire): the sign-in request was already answered. Source: https://tickwire.io/docs/errors/request_used/ HTTP 409. **Likely cause:** Allow or Cancel was pressed twice, or in two tabs. **What to do:** Start connecting again from the app if it did not connect. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # resend_window_expired > The webhook event is too old to resend. Source: https://tickwire.io/docs/errors/resend_window_expired/ HTTP 410. **Likely cause:** A resend was asked for an event outside the resend window. **What to do:** Reconcile from the API instead of resending. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # sandbox_account_limit > Your sandbox already holds its maximum number of accounts (5 by default). Source: https://tickwire.io/docs/errors/sandbox_account_limit/ HTTP 403. Nothing reached the broker. **Likely cause:** Creating a sixth account with a sandbox (twsk_) key. **What to do:** Delete a sandbox account you no longer need, then create the new one. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sandbox](https://tickwire.io/docs/errors/#sandbox) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # sandbox_key_limit > Your sandbox already holds its maximum number of active credentials of this kind (5 sandbox keys; 20 each of API tokens, read-only keys and agent keys by default). Source: https://tickwire.io/docs/errors/sandbox_key_limit/ HTTP 403. Nothing reached the broker. **Likely causes:** - Creating another sandbox key (dashboard quickstart or POST /v1/sandbox/keys) while the sandbox holds the maximum. - Creating another API token, read-only key or agent key with a sandbox key or token while the sandbox holds the maximum of that kind. **What to do:** Revoke a sandbox credential of that kind you no longer need on the dashboard, then create the new one. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sandbox](https://tickwire.io/docs/errors/#sandbox) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # sandbox_key_required > Server Tickwire-Sandbox is only for sandbox keys; sandbox and live never mix. Source: https://tickwire.io/docs/errors/sandbox_key_required/ HTTP 400. Nothing reached the broker. **Likely cause:** Creating an account on server Tickwire-Sandbox with a live key. **What to do:** Get a twsk_ key with POST /v1/sandbox/keys (or /v1/sandbox/signup) and use it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sandbox](https://tickwire.io/docs/errors/#sandbox) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # sandbox_key_restricted > This sandbox key came from anonymous sign-up: it may manage its sandbox accounts, trade, stream and read, nothing else. Source: https://tickwire.io/docs/errors/sandbox_key_restricted/ HTTP 403. Nothing reached the broker. **Likely causes:** - Creating a webhook, pre-trade hook, agent key, API key or token, or another sandbox key with a key from POST /v1/sandbox/signup. - Creating, changing or deleting a risk-management tracker or guard rule (or resetting trading statistics) with such a key. Reading trackers, statistics and metrics stays allowed. - A sandbox key whose restrictions we could not confirm, on a risk-management write (it fails closed). **What to do:** Sign in, then create a sandbox key with POST /v1/sandbox/keys using your live key; it has full rights inside your sandbox. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sandbox](https://tickwire.io/docs/errors/#sandbox) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # sandbox_server_required > A sandbox key can only create simulated accounts. Source: https://tickwire.io/docs/errors/sandbox_server_required/ HTTP 400. Nothing reached the broker. **Likely cause:** Creating an account on a real broker server with a sandbox (twsk_) key. **What to do:** Use server Tickwire-Sandbox and a magic login, or use a live key for a broker account. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sandbox](https://tickwire.io/docs/errors/#sandbox) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # server_limit_reached > The maximum number of private servers is reached. Source: https://tickwire.io/docs/errors/server_limit_reached/ HTTP 409. **Likely cause:** A plan limit. **What to do:** Delete a server or raise the limit. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # service_unavailable > The service is not available right now. Source: https://tickwire.io/docs/errors/service_unavailable/ HTTP 503. Nothing reached the broker. **Likely cause:** Not available yet, or restarting. **What to do:** Retry later. Nothing was sent. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # sign_in_required > This invite link only works once you are signed in with the invited email address. Source: https://tickwire.io/docs/errors/sign_in_required/ HTTP 403. **Likely cause:** An invite link shared by hand was opened while signed out. **What to do:** Sign in or sign up with the invited address, then open the link again. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # slots_full > Every purchased slot is taken. Source: https://tickwire.io/docs/errors/slots_full/ HTTP 409. **Likely cause:** Linking an account without a free slot. **What to do:** Buy a slot or unlink an account. **Retry:** No. The same request gets the same answer; change something first. Listed under [Billing, slots and dedicated IPs](https://tickwire.io/docs/errors/#billing-slots-and-dedicated-ips) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # symbol_not_found > The terminal doesn't know this symbol. Source: https://tickwire.io/docs/errors/symbol_not_found/ HTTP 404. Nothing reached the broker. **Likely cause:** A typo, or the broker names it differently (suffixes such as .m or -ECN). **What to do:** List symbols and use the broker's exact name. **Retry:** No. The same request gets the same answer; change something first. Listed under [Market data and platform support](https://tickwire.io/docs/errors/#market-data-and-platform-support) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # temporarily_unavailable > The service could not answer just now; nothing was changed. Source: https://tickwire.io/docs/errors/temporarily_unavailable/ HTTP 503. Nothing reached the broker. **Likely causes:** - A read could not reach the database, even after one retry on a fresh connection (listings such as connected apps and dedicated IPs). - OAuth (Sign in with Tickwire): client registration is at capacity. **What to do:** Retry after Retry-After seconds (when sent), or later. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # terminal_event_value_invalid > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/terminal_event_value_invalid/ `terminal_event_value_invalid` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # terminal_events_disabled > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/terminal_events_disabled/ `terminal_events_disabled` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # terminal_timeout > The terminal did not answer a read in time. Source: https://tickwire.io/docs/errors/terminal_timeout/ HTTP 504. **Likely cause:** The terminal is busy or stuck. **What to do:** Retry the read. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # TICKWIRE_HELD > A pre-trade hook is holding this order; nothing has been sent yet (`stringCode` of a streaming `TradeError`). Source: https://tickwire.io/docs/errors/tickwire_held/ WebSocket error frame. Nothing reached the broker. **Likely cause:** Your pre-trade hook answered with a hold instead of allow or deny. **What to do:** Do not resend. Wait for the hook to release or reject the hold before `metadata.expiresAt`; `metadata.holdId` identifies it. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # tickwire_no_reply > The MCP tool sent the request but got no reply. If it was a trade, it may have executed. Source: https://tickwire.io/docs/errors/tickwire_no_reply/ MCP tool result. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely cause:** The connection dropped or timed out after the request was sent. **What to do:** For a trade, call `get_trade_status` with the same `idempotency_key` before doing anything else. Reads can be repeated. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # tickwire_unreachable > The MCP tool could not reach the Tickwire API, so nothing was sent. Source: https://tickwire.io/docs/errors/tickwire_unreachable/ MCP tool result. Nothing reached the broker. **Likely causes:** - A network problem between the MCP server and the API. - A wrong API address in a locally run MCP server's settings. **What to do:** Retry the tool. If it keeps happening, check the [status page](https://tickwire.io/status/), and for a local MCP server check the API address it uses. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # timeout > No answer in time: a batch leg's status, or a pre-trade hook's `error` in webhook events. For a batch leg the order may have executed. Source: https://tickwire.io/docs/errors/timeout/ Not an HTTP error. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely causes:** - The terminal or broker did not reply in time. - Your pre-trade hook did not answer in time. **What to do:** Batch legs: never resend blindly; repeat the batch with the same Idempotency-Key, or check positions and history. Hooks: make the hook answer faster. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # TimeoutError > Error name in a streaming error: the terminal did not answer in time. Source: https://tickwire.io/docs/errors/timeouterror/ WebSocket error frame. **Likely causes:** - The terminal or the broker is slow. - A wait for synchronization ran past its timeout. **What to do:** Repeat reads. Repeat a trade only with the same `requestId`, which returns the real outcome. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # too_many_attempts > Too many failed sign-ins or link requests. Source: https://tickwire.io/docs/errors/too_many_attempts/ HTTP 429. **Likely cause:** Repeated wrong passwords, or too many magic links in an hour. **What to do:** Wait, or use a magic link. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # too_many_connections > Too many concurrent WebSockets for this token. Source: https://tickwire.io/docs/errors/too_many_connections/ HTTP 429. **Likely cause:** More connections than the per-token limit. **What to do:** Close unused connections or multiplex subscriptions over one. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # too_many_requests > All concurrent market-data request slots for this account are in use. Source: https://tickwire.io/docs/errors/too_many_requests/ HTTP 429. **Likely cause:** Too many parallel history or market-data calls. **What to do:** Wait for Retry-After, or send fewer calls at once. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Market data and platform support](https://tickwire.io/docs/errors/#market-data-and-platform-support) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # too_many_sessions > Too many stream sessions for this account (error frame, then the socket closes). Source: https://tickwire.io/docs/errors/too_many_sessions/ WebSocket error frame. **Likely cause:** More sessions than allowed per account. **What to do:** Reuse one session. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # TooManyRequestsError > Error name for a rate limit on the `/users/current/…` routes; `metadata.recommendedRetryTime` says when to retry. Source: https://tickwire.io/docs/errors/toomanyrequestserror/ HTTP 429. **Likely causes:** - Too many requests for this token, account or IP. - All concurrent market-data request slots are in use. **What to do:** Wait for Retry-After (or recommendedRetryTime), then retry. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # TradeError > Error name in a streaming error: the trade was refused or is being held. `stringCode` says which, and `metadata.sent` says whether anything reached the broker. Source: https://tickwire.io/docs/errors/tradeerror/ WebSocket error frame. **Likely causes:** - A pre-trade hook is holding the order (`stringCode: TICKWIRE_HELD`). - The order failed a check or the broker refused it. **What to do:** Read `stringCode`, `message` and `metadata`, fix the order if needed, and send a new one only if `metadata.sent` is false. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unauthorized > Missing or invalid credentials. Source: https://tickwire.io/docs/errors/unauthorized/ HTTP 401. Nothing reached the broker. **Likely cause:** No key, a wrong key, or a revoked key. **What to do:** Send a valid key. **Retry:** No. The same request gets the same answer; change something first. Listed under [Keys, tokens and permissions](https://tickwire.io/docs/errors/#keys-tokens-and-permissions) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # UnauthorizedError > Error name for a missing or invalid token on the `/users/current/…` routes. Source: https://tickwire.io/docs/errors/unauthorizederror/ HTTP 401. **Likely causes:** - No auth-token header. - The token is invalid, expired or revoked. **What to do:** Send a valid token. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unavailable > A dependent feature isn't running right now. Source: https://tickwire.io/docs/errors/unavailable/ HTTP 503. **Likely cause:** Webhook delivery is not running. **What to do:** Try again later. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unknown_account > An account id in the request is not yours. Source: https://tickwire.io/docs/errors/unknown_account/ HTTP 400. **Likely cause:** A wrong id in account_ids. **What to do:** Use ids from your account list. **Retry:** No. The same request gets the same answer; change something first. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unknown_actor > The original caller of a held order can't be verified; nothing was sent. Source: https://tickwire.io/docs/errors/unknown_actor/ HTTP 401. Nothing reached the broker. **Likely cause:** The credential that sent it no longer exists. **What to do:** Send the order again with a current credential. **Retry:** No. The same request gets the same answer; change something first. Listed under [Pre-trade hooks, holds and kill switches](https://tickwire.io/docs/errors/#pre-trade-hooks-holds-and-kill-switches) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unknown_component > Status page: an incident names a component that doesn't exist. Source: https://tickwire.io/docs/errors/unknown_component/ HTTP 422. **Likely cause:** A typo in a component id. **What to do:** Use ids from /api/v1/status.json. **Retry:** No. The same request gets the same answer; change something first. Listed under [Status page API](https://tickwire.io/docs/errors/#status-page-api) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unknown_event_type > The webhook event type is not in the event catalog. Source: https://tickwire.io/docs/errors/unknown_event_type/ HTTP 400. **Likely causes:** - Triggering a test event (POST /v1/webhook-events/trigger) with a type that does not exist. - Filtering a webhook listener's events with a type or family that does not exist. **What to do:** Use a type from GET /v1/webhook-event-types, or a family wildcard such as trade.*. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unknown_host > No Tickwire service is served at this hostname. Source: https://tickwire.io/docs/errors/unknown_host/ HTTP 404. Nothing reached the broker. **Likely cause:** A wrong base URL. **What to do:** Use the hostnames from the docs. **Retry:** No. The same request gets the same answer; change something first. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unknown_platform > Used between Tickwire's own services; the public API does not return it. Source: https://tickwire.io/docs/errors/unknown_platform/ `unknown_platform` is used between Tickwire's own services, for example between a trading server or a terminal and Tickwire. The public API does not return it, so your application should not see it, and there is nothing for you to change. If an API response or a webhook does show it, send the error's `requestId` to support and we will look into it. Every code the API returns is listed in [Errors](https://tickwire.io/docs/errors/). --- # unknown_region > This region is not served. Source: https://tickwire.io/docs/errors/unknown_region/ HTTP 404. Nothing reached the broker. **Likely cause:** A wrong region in a regional API hostname. **What to do:** Use a served region. **Retry:** No. The same request gets the same answer; change something first. Listed under [Accounts and terminals](https://tickwire.io/docs/errors/#accounts-and-terminals) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unreachable_account > Some accounts in the batch have no terminal; nothing was sent. Source: https://tickwire.io/docs/errors/unreachable_account/ HTTP 400. Nothing reached the broker. **Likely cause:** Accounts undeployed or their terminals down. **What to do:** Deploy them or drop them from the batch. **Retry:** No. The same request gets the same answer; change something first. Listed under [Orders and idempotency](https://tickwire.io/docs/errors/#orders-and-idempotency) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unsupported_grant_type > OAuth (Sign in with Tickwire): the token endpoint only supports authorization_code and refresh_token. Source: https://tickwire.io/docs/errors/unsupported_grant_type/ HTTP 400. **Likely cause:** grant_type is password, client_credentials, implicit or another type. **What to do:** Use the authorization code flow with PKCE. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unsupported_media_type > The request body has an unsupported content type. Source: https://tickwire.io/docs/errors/unsupported_media_type/ HTTP 415. Nothing reached the broker. **Likely cause:** Not application/json. **What to do:** Send JSON with Content-Type: application/json. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # unsupported_response_type > OAuth (Sign in with Tickwire): only response_type=code is supported (shown on the sign-in error page). Source: https://tickwire.io/docs/errors/unsupported_response_type/ HTTP 400. **Likely cause:** The app used the implicit flow or another response type. **What to do:** Use response_type=code with PKCE (S256). **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign in with Tickwire (OAuth)](https://tickwire.io/docs/errors/#sign-in-with-tickwire-oauth) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # upstream_misconfigured > The account's terminal refused our API. Source: https://tickwire.io/docs/errors/upstream_misconfigured/ HTTP 502. Nothing reached the broker. **Likely cause:** An internal credential mismatch. **What to do:** Contact support with the requestId. **Retry:** No. The same request gets the same answer; change something first. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # upstream_refused > The upstream refused the WebSocket. Source: https://tickwire.io/docs/errors/upstream_refused/ HTTP 400, 401, 403, 404, 409, 429, 502. **Likely cause:** The upstream answered the upgrade with an error status. **What to do:** Check the path and the subscription. **Retry:** No. The same request gets the same answer; change something first. Listed under [Streaming](https://tickwire.io/docs/errors/#streaming) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # upstream_timeout > The upstream did not answer in time. For a mutating request the outcome is unknown (`metadata.outcome: unknown`): it may have executed. Source: https://tickwire.io/docs/errors/upstream_timeout/ HTTP 504. Unknown: it may have executed. Resolve it with the same idempotency key before acting. **Likely cause:** The terminal or broker is slow. **What to do:** Never resend a trade blindly: repeat it with the same Idempotency-Key (or clientId) to learn the real outcome. Reads can be retried. **Retry:** Only with the same `Idempotency-Key` (or `clientId`). The first attempt may have executed; never resend a trade blindly. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # upstream_unavailable > A Tickwire service is unreachable; the request was not sent. Source: https://tickwire.io/docs/errors/upstream_unavailable/ HTTP 502. Nothing reached the broker. **Likely cause:** The service is restarting. **What to do:** Retry after Retry-After. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # url_not_allowed > A webhook delivery was not sent because the endpoint's URL failed our egress rules at send time (the delivery's `lastError`, and an endpoint's `disabledReason`; not an HTTP status). Source: https://tickwire.io/docs/errors/url_not_allowed/ Not an HTTP error. **Likely causes:** - The host now resolves to a non-public address (for example after a DNS change). - The URL was registered before the rules applied and is not https://, or names an internal host or address; such endpoints are disabled. **What to do:** Point the endpoint at an https URL that resolves only to public addresses, re-enable it, then resend missed events inside the resend window. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # validation_error > The request failed validation. Source: https://tickwire.io/docs/errors/validation_error/ HTTP 400, 422. Nothing reached the broker. **Likely cause:** A missing field, a wrong type or an out-of-range value. **What to do:** Fix the fields named in `details` or the message. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # ValidationError > Error name for an invalid request on the `/users/current/…` routes; `details` lists the parameters. Source: https://tickwire.io/docs/errors/validationerror/ HTTP 400. Nothing reached the broker. **Likely cause:** A field is missing or has the wrong type or value. **What to do:** Fix the fields named in `details`. **Retry:** No. The same request gets the same answer; change something first. Listed under [Compatibility error names](https://tickwire.io/docs/errors/#compatibility-error-names) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # waking_up > Tickwire was paused to save cost while nobody was using it, and your request started it again. Starting takes about 2 minutes. Source: https://tickwire.io/docs/errors/waking_up/ HTTP 503. Nothing reached the broker. **Likely cause:** The first request after a quiet period (only before launch: the automatic sleep is off once trading customers are live). **What to do:** Retry after Retry-After (30 seconds). In a browser the page reloads itself. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Outages and timeouts](https://tickwire.io/docs/errors/#outages-and-timeouts) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # weak_password > The password is too weak. Source: https://tickwire.io/docs/errors/weak_password/ HTTP 400. **Likely cause:** Too short or too common. **What to do:** Choose a longer, less common password. **Retry:** No. The same request gets the same answer; change something first. Listed under [Sign-in and organisations](https://tickwire.io/docs/errors/#sign-in-and-organisations) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # webhook_trigger_sandbox_only > On a live key only webhook.test can be triggered; other test events are sandbox-only. Source: https://tickwire.io/docs/errors/webhook_trigger_sandbox_only/ HTTP 403. **Likely cause:** POST /v1/webhook-events/trigger with a live key and an event type other than webhook.test. **What to do:** Use a sandbox key (POST /v1/sandbox/keys) to trigger other event types, so a test trade never reaches a production handler. **Retry:** No. The same request gets the same answer; change something first. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # webhook_unavailable > The test event was published, but the webhook pipeline could not store or queue it, so your endpoints will not receive it. Source: https://tickwire.io/docs/errors/webhook_unavailable/ HTTP 503. **Likely cause:** POST /v1/webhook-events/trigger while webhook storage or the delivery queue is failing. **What to do:** Retry later with a new Idempotency-Key. Running tickwire listen sessions still received the event. If it persists, check the status page and contact support with the requestId. **Retry:** Yes. Nothing happened (or it was a read), so repeat it, after `Retry-After` when present. Listed under [Webhooks](https://tickwire.io/docs/errors/#webhooks) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # window_too_large > The time window is too large for one call. Source: https://tickwire.io/docs/errors/window_too_large/ HTTP 400. **Likely cause:** More than 31 days requested. **What to do:** Page by time. **Retry:** No. The same request gets the same answer; change something first. Listed under [Requests and validation](https://tickwire.io/docs/errors/#requests-and-validation) in [Errors](https://tickwire.io/docs/errors/). Send the error's `requestId` to support and we can find the request. --- # API reference > 200 operations, generated from the OpenAPI document the services export (version 0.1.0). Base URL: https://api.tickwire.io. OpenAPI: https://tickwire.io/openapi.json. Postman collection: https://tickwire.io/docs/reference/tickwire.postman_collection.json. Authenticate with `auth-token` (on `/users/current/…`), `X-API-Key` (everywhere else) or `Authorization: Bearer`; the agent API takes `X-Tickwire-Agent-Key`. ## Account REST API (/users/current) The `/users/current/…` REST API: provisioning, account state, market data, history and trading. Code already written for this API style needs only a new base URL and key. Works for MT4 and MT5. ### [Accounts and provisioning](https://tickwire.io/docs/reference/provisioning.md) - `GET /users/current/accounts`: List Accounts - `POST /users/current/accounts`: Create Account - `GET /users/current/accounts/{account_id}`: Get Account - `PUT /users/current/accounts/{account_id}`: Update Account - `DELETE /users/current/accounts/{account_id}`: Delete Account - `PUT /users/current/accounts/{account_id}/credentials`: Set Credentials - `POST /users/current/accounts/{account_id}/deploy`: Deploy - `POST /users/current/accounts/{account_id}/enable-account-features`: Enable Account Features - `POST /users/current/accounts/{account_id}/enable-copy-factory-api`: Enable the copy trading API - `POST /users/current/accounts/{account_id}/enable-metastats-api`: Enable the trading statistics API - `POST /users/current/accounts/{account_id}/enable-risk-management-api`: Enable Risk Management - `POST /users/current/accounts/{account_id}/increase-reliability`: Increase Reliability - `POST /users/current/accounts/{account_id}/redeploy`: Redeploy - `POST /users/current/accounts/{account_id}/undeploy`: Undeploy - `GET /users/current/provisioning-profiles`: List Profiles - `POST /users/current/provisioning-profiles`: Create Profile - `GET /users/current/provisioning-profiles/{profile_id}`: Get Profile - `PUT /users/current/provisioning-profiles/{profile_id}`: Update Profile - `DELETE /users/current/provisioning-profiles/{profile_id}`: Delete Profile - `PUT /users/current/provisioning-profiles/{profile_id}/{file_name}`: Upload File ### [Account state](https://tickwire.io/docs/reference/account-state.md) - `GET /users/current/accounts/{account_id}/account-information`: Account Information - `GET /users/current/accounts/{account_id}/capabilities`: Capabilities - `GET /users/current/accounts/{account_id}/orders`: Orders - `GET /users/current/accounts/{account_id}/orders/{order_id}`: Order - `GET /users/current/accounts/{account_id}/positions`: Positions - `GET /users/current/accounts/{account_id}/positions/{position_id}`: Position - `GET /users/current/accounts/{account_id}/server-time`: Server Time ### [Market data](https://tickwire.io/docs/reference/market-data.md) - `GET /users/current/accounts/{account_id}/historical-market-data/symbols/{symbol}/ticks`: Historical Ticks - `GET /users/current/accounts/{account_id}/historical-market-data/symbols/{symbol}/timeframes/{timeframe}/candles`: Historical Candles - `GET /users/current/accounts/{account_id}/symbols`: Symbols - `GET /users/current/accounts/{account_id}/symbols/{symbol}/current-book`: Current Book - `GET /users/current/accounts/{account_id}/symbols/{symbol}/current-candles/{timeframe}`: Current Candle - `GET /users/current/accounts/{account_id}/symbols/{symbol}/current-price`: Current Price - `GET /users/current/accounts/{account_id}/symbols/{symbol}/current-tick`: Current Tick - `GET /users/current/accounts/{account_id}/symbols/{symbol}/specification`: Specification - `POST /users/current/accounts/{account_id}/symbols/{symbol}/unsubscribe`: Unsubscribe ### [History](https://tickwire.io/docs/reference/history.md) - `GET /users/current/accounts/{account_id}/history-deals/position/{position_id}`: History Deals By Position - `GET /users/current/accounts/{account_id}/history-deals/ticket/{ticket}`: History Deals By Ticket - `GET /users/current/accounts/{account_id}/history-deals/time/{start_time}/{end_time}`: History Deals By Time - `GET /users/current/accounts/{account_id}/history-orders/position/{position_id}`: History Orders By Position - `GET /users/current/accounts/{account_id}/history-orders/ticket/{ticket}`: History Orders By Ticket - `GET /users/current/accounts/{account_id}/history-orders/time/{start_time}/{end_time}`: History Orders By Time ### [Trading](https://tickwire.io/docs/reference/trading.md) - `POST /users/current/accounts/{account_id}/calculate-margin`: Calculate Margin - `POST /users/current/accounts/{account_id}/trade`: Trade - `POST /users/current/accounts/{account_id}/trade/check`: Trade Check - `GET /users/current/accounts/{account_id}/trailing-stop-losses`: List Trailing - `DELETE /users/current/accounts/{account_id}/trailing-stop-losses/{position_id}`: Delete Trailing ### [Health, snapshot and audit trail](https://tickwire.io/docs/reference/account-health-audit.md) - `GET /users/current/accounts/{account_id}/audit`: Account Audit - `GET /users/current/accounts/{account_id}/health`: Account Health - `GET /users/current/accounts/{account_id}/snapshot`: Account Snapshot ### [Tokens and discovery](https://tickwire.io/docs/reference/tokens-discovery.md) - `POST /users/current/narrow-down-auth-token`: Narrow Down - `GET /users/current/regions`: Regions - `GET /users/current/servers/mt-client-api`: Client Api Domain - `GET /users/current/tokens`: List Tokens - `POST /users/current/tokens`: Create Token - `GET /users/current/tokens/{token_id}`: Get Token - `PATCH /users/current/tokens/{token_id}`: Patch Token - `DELETE /users/current/tokens/{token_id}`: Revoke Token - `GET /v1/access-rule-manifest`: Access Rule Manifest - `GET /v1/known-mt-servers/{version}/search`: Search Servers ## Terminal routes and batch orders Per-account terminal routes on `/mt4/{id}/…` and `/mt5/{id}/…`, and batch orders on `/v1/orders`. ### [MT5 terminal](https://tickwire.io/docs/reference/mt5-terminal.md) - `GET /mt5/{account_id}/AccountInfo`: GET /mt5/{account_id}/AccountInfo - `GET /mt5/{account_id}/AccountSummary`: GET /mt5/{account_id}/AccountSummary - `POST /mt5/{account_id}/CloseAll`: POST /mt5/{account_id}/CloseAll - `GET /mt5/{account_id}/OpenedOrders`: GET /mt5/{account_id}/OpenedOrders - `GET /mt5/{account_id}/OrderCalcMargin`: GET /mt5/{account_id}/OrderCalcMargin - `GET /mt5/{account_id}/OrderCalcProfit`: GET /mt5/{account_id}/OrderCalcProfit - `POST /mt5/{account_id}/OrderClose`: POST /mt5/{account_id}/OrderClose - `GET /mt5/{account_id}/OrderHistory`: GET /mt5/{account_id}/OrderHistory - `POST /mt5/{account_id}/OrderModify`: POST /mt5/{account_id}/OrderModify - `POST /mt5/{account_id}/OrderSend`: POST /mt5/{account_id}/OrderSend - `GET /mt5/{account_id}/PositionHistory`: GET /mt5/{account_id}/PositionHistory - `GET /mt5/{account_id}/PriceHistory`: GET /mt5/{account_id}/PriceHistory - `GET /mt5/{account_id}/ServerTimezone`: GET /mt5/{account_id}/ServerTimezone - `GET /mt5/{account_id}/SymbolInfo`: GET /mt5/{account_id}/SymbolInfo - `GET /mt5/{account_id}/getQuote`: GET /mt5/{account_id}/getQuote - `GET /mt5/{account_id}/healthz`: GET /mt5/{account_id}/healthz - `GET /mt5/{account_id}/livez`: GET /mt5/{account_id}/livez - `GET /mt5/{account_id}/status`: GET /mt5/{account_id}/status - `GET /mt5/{account_id}/symbols`: GET /mt5/{account_id}/symbols ### [MT4 terminal](https://tickwire.io/docs/reference/mt4-terminal.md) - `GET /mt4/{account_id}/AccountInfo`: GET /mt4/{account_id}/AccountInfo - `GET /mt4/{account_id}/AccountSummary`: GET /mt4/{account_id}/AccountSummary - `POST /mt4/{account_id}/CloseAll`: POST /mt4/{account_id}/CloseAll - `GET /mt4/{account_id}/OpenedOrders`: GET /mt4/{account_id}/OpenedOrders - `GET /mt4/{account_id}/OrderCalcMargin`: GET /mt4/{account_id}/OrderCalcMargin - `GET /mt4/{account_id}/OrderCalcProfit`: GET /mt4/{account_id}/OrderCalcProfit - `POST /mt4/{account_id}/OrderClose`: POST /mt4/{account_id}/OrderClose - `GET /mt4/{account_id}/OrderHistory`: GET /mt4/{account_id}/OrderHistory - `POST /mt4/{account_id}/OrderModify`: POST /mt4/{account_id}/OrderModify - `POST /mt4/{account_id}/OrderSend`: POST /mt4/{account_id}/OrderSend - `GET /mt4/{account_id}/PositionHistory`: GET /mt4/{account_id}/PositionHistory - `GET /mt4/{account_id}/PriceHistory`: GET /mt4/{account_id}/PriceHistory - `GET /mt4/{account_id}/ServerTimezone`: GET /mt4/{account_id}/ServerTimezone - `GET /mt4/{account_id}/SymbolInfo`: GET /mt4/{account_id}/SymbolInfo - `GET /mt4/{account_id}/getQuote`: GET /mt4/{account_id}/getQuote - `GET /mt4/{account_id}/healthz`: GET /mt4/{account_id}/healthz - `GET /mt4/{account_id}/livez`: GET /mt4/{account_id}/livez - `GET /mt4/{account_id}/status`: GET /mt4/{account_id}/status - `GET /mt4/{account_id}/symbols`: GET /mt4/{account_id}/symbols ### [Batch orders](https://tickwire.io/docs/reference/batch-orders.md) - `POST /v1/orders`: Batch orders - `POST /v1/orders/close`: Batch close ## Native /v1 Tickwire's own API: accounts, webhooks, keys, private servers, dedicated IPs and billing. ### [Sandbox](https://tickwire.io/docs/reference/sandbox.md) - `GET /v1/sandbox`: Sandbox Info - `POST /v1/sandbox/keys`: Create Key - `POST /v1/sandbox/signup`: Signup ### [Accounts](https://tickwire.io/docs/reference/accounts.md) - `GET /v1/accounts`: List Accounts - `POST /v1/accounts`: Link Account - `GET /v1/accounts/{account_id}`: Get Account - `PATCH /v1/accounts/{account_id}`: Patch Account - `DELETE /v1/accounts/{account_id}`: Unlink Account ### [Webhooks and events](https://tickwire.io/docs/reference/webhooks.md) - `POST /v1/events/{event_id}/resend`: Resend Event - `GET /v1/webhook-event-types`: Event Types - `POST /v1/webhook-events/trigger`: Trigger - `POST /v1/webhook-listeners`: Create Listener - `GET /v1/webhook-listeners/{listener_id}/events`: Listener Events - `GET /v1/webhooks`: List Webhooks - `POST /v1/webhooks`: Create Webhook - `GET /v1/webhooks/{webhook_id}`: Get Webhook - `PATCH /v1/webhooks/{webhook_id}`: Patch Endpoint - `DELETE /v1/webhooks/{webhook_id}`: Delete Webhook - `GET /v1/webhooks/{webhook_id}/deliveries`: List Deliveries - `GET /v1/webhooks/{webhook_id}/deliveries/{delivery_id}`: Get Delivery - `POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/resend`: Resend Delivery - `POST /v1/webhooks/{webhook_id}/disable`: Disable Endpoint - `POST /v1/webhooks/{webhook_id}/enable`: Enable Endpoint - `POST /v1/webhooks/{webhook_id}/reveal-secret`: Reveal Secret - `POST /v1/webhooks/{webhook_id}/rotate-secret`: Rotate Secret - `GET /v1/webhooks/{webhook_id}/settings`: Endpoint Settings ### [Read-only keys](https://tickwire.io/docs/reference/keys.md) - `GET /v1/readonly-keys`: List Ro Keys - `POST /v1/readonly-keys`: Create Ro Key - `GET /v1/readonly-keys/{key_id}`: Get Ro Key - `PATCH /v1/readonly-keys/{key_id}`: Patch Ro Key - `DELETE /v1/readonly-keys/{key_id}`: Delete Ro Key - `POST /v1/readonly-keys/{key_id}/rotate`: Rotate Ro Key ### [Private servers](https://tickwire.io/docs/reference/private-servers.md) - `GET /v1/private-servers`: List Servers - `POST /v1/private-servers`: Buy Server - `GET /v1/private-servers/regions`: Regions - `GET /v1/private-servers/{server_id}`: Get Server - `PATCH /v1/private-servers/{server_id}`: Resize Server - `DELETE /v1/private-servers/{server_id}`: Cancel Server - `POST /v1/private-servers/{server_id}/accounts`: Add Server Account - `DELETE /v1/private-servers/{server_id}/accounts/{account_id}`: Remove Server Account ### [Dedicated IPs and billing](https://tickwire.io/docs/reference/billing.md) - `GET /v1/billing`: Billing - `POST /v1/billing/upgrade`: Upgrade - `GET /v1/billing/upgrade/quote`: Upgrade Quote - `GET /v1/dedicated-ips`: My Dedicated Ips - `POST /v1/dedicated-ips/move-accounts`: My Move Accounts - `GET /v1/subscription`: Subscription - `GET /v1/wallet`: Wallet - `GET /v1/wallet/assets`: Wallet Assets - `POST /v1/wallet/topup`: Create Topup - `GET /v1/wallet/topup/{topup_id}`: Get Topup - `POST /v1/wallet/topup/{topup_id}/confirm`: Confirm Topup - `GET /v1/wallet/topups`: List Topups ### [Identity and other routes](https://tickwire.io/docs/reference/native-other.md) - `GET /v1/api-version`: Get Api Version - `POST /v1/api-version`: Set Api Version - `GET /v1/meta/whoami`: Whoami - `GET /v1/request-logs`: List Request Logs - `GET /v1/request-logs/summary`: Request Log Summary - `GET /v1/request-logs/{log_id}`: Get Request Log ## AI agents Scoped agent keys, kill switches, pre-trade hooks and holds, and the agent API itself. ### [Agent API](https://tickwire.io/docs/reference/agent-api.md) - `GET /v1/agent/accounts`: Agent Accounts - `GET /v1/agent/accounts/{account_id}/account-information`: Agent Account Info - `GET /v1/agent/accounts/{account_id}/health`: Agent Health - `GET /v1/agent/accounts/{account_id}/history-deals`: Agent Deals - `GET /v1/agent/accounts/{account_id}/orders`: Agent Orders - `GET /v1/agent/accounts/{account_id}/positions`: Agent Positions - `GET /v1/agent/accounts/{account_id}/snapshot`: Agent Snapshot - `GET /v1/agent/accounts/{account_id}/symbols/{symbol}/current-price`: Agent Price - `GET /v1/agent/accounts/{account_id}/symbols/{symbol}/specification`: Agent Spec - `POST /v1/agent/accounts/{account_id}/trade`: Agent Trade - `GET /v1/agent/audit`: Agent Own Audit - `GET /v1/agent/me`: Agent Me - `GET /v1/agent/requests/{idempotency_key}`: Agent Request Status ### [Agent keys and kill switches](https://tickwire.io/docs/reference/agent-admin.md) - `GET /v1/agent-audit`: Agent Audit - `GET /v1/agent-keys`: List Agent Keys - `POST /v1/agent-keys`: Create Agent Key - `GET /v1/agent-keys/{key_id}`: Get Agent Key - `PATCH /v1/agent-keys/{key_id}`: Patch Agent Key - `DELETE /v1/agent-keys/{key_id}`: Revoke Agent Key - `PUT /v1/agent-keys/{key_id}/kill-switch`: Set Key Kill Switch - `GET /v1/agent-kill-switches`: List Kill Switches - `PUT /v1/agent-kill-switches/accounts/{account_id}`: Set Account Kill Switch ### [Pre-trade hooks and holds](https://tickwire.io/docs/reference/pretrade.md) - `GET /v1/pretrade-holds`: List Holds - `GET /v1/pretrade-holds/{hold_id}`: Get Hold - `POST /v1/pretrade-holds/{hold_id}/cancel`: Cancel Hold - `POST /v1/pretrade-holds/{hold_id}/release`: Release Hold - `GET /v1/pretrade-hooks`: List Hooks - `POST /v1/pretrade-hooks`: Create Hook - `GET /v1/pretrade-hooks/{hook_id}`: Get Hook - `PATCH /v1/pretrade-hooks/{hook_id}`: Patch Hook - `DELETE /v1/pretrade-hooks/{hook_id}`: Delete Hook - `POST /v1/pretrade-hooks/{hook_id}/rotate-secret`: Rotate Hook Secret ### [Sign in with Tickwire (OAuth) and connected apps](https://tickwire.io/docs/reference/oauth.md) - `GET /.well-known/oauth-authorization-server`: As Metadata - `GET /oauth/authorize`: Authorize - `POST /oauth/consent/decide`: Consent Decide - `POST /oauth/consent/view`: Consent View - `POST /oauth/register`: Register - `POST /oauth/revoke`: Revoke - `POST /oauth/token`: Token - `GET /v1/connected-apps`: List Apps - `DELETE /v1/connected-apps/{grant_id}`: Disconnect App ## Guarded execution Trades placed with an API key through the same guarded pipeline agents use. ### [Guarded trades](https://tickwire.io/docs/reference/execution.md) - `POST /v1/execution/accounts/{account_id}/trade`: Guarded Trade --- # Accounts and provisioning (Account REST API (/users/current)) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/provisioning/ ### GET /users/current/accounts **List Accounts** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `offset` | query | `integer` | no | | | `limit` | query | `integer` | no | | | `version` | query | `integer[] \| null` | no | | | `type` | query | `string \| null` | no | | | `state` | query | `string[] \| null` | no | | | `connectionStatus` | query | `string[] \| null` | no | | | `deploymentStatus` | query | `"deployed" \| "undeployed" \| "failed" \| null` | no | | | `query` | query | `string \| null` | no | | | `provisioningProfileId` | query | `string \| null` | no | | | `region` | query | `string[] \| null` | no | | | `tags` | query | `string[] \| null` | no | | | `sortOrder` | query | `"asc" \| "desc" \| null` | no | | | `api-version` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts"); console.log(result); tw.close(); ``` ### POST /users/current/accounts **Create Account** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `transaction-id` | header | `string \| null` | no | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `NewTradingAccount` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | yes | | | `server` | `string` | yes | | | `login` | `string \| integer \| null` | no | | | `password` | `string \| null` | no | | | `platform` | `"mt4" \| "mt5" \| null` | no | | | `provisioningProfileId` | `string \| null` | no | | | `magic` | `integer` | no | | | `manualTrades` | `boolean` | no | | | `slippage` | `number \| null` | no | | | `quoteStreamingIntervalInSeconds` | `number` | no | | | `tags` | `string[]` | no | | | `metadata` | `object \| null` | no | | | `reliability` | `"regular" \| "high"` | no | | | `resourceSlots` | `integer` | no | | | `copyFactoryResourceSlots` | `integer` | no | | | `region` | `string \| null` | no | | | `type` | `"cloud" \| "cloud-g1" \| "cloud-g2"` | no | | | `symbol` | `string \| null` | no | | | `baseCurrency` | `string \| null` | no | | | `copyFactoryRoles` | `"PROVIDER" \| "SUBSCRIBER"[]` | no | | | `riskManagementApiEnabled` | `boolean` | no | | | `metastatsApiEnabled` | `boolean` | no | | | `allocateDedicatedIp` | `"ipv4" \| "none" \| null` | no | | | `keywords` | `string[]` | no | | | `serverAddress` | `string \| null` | no | | Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"name":"example","server":"Tickwire-Sandbox","magic":0,"manualTrades":false,"quoteStreamingIntervalInSeconds":2.5,"reliability":"regular","resourceSlots":1,"copyFactoryResourceSlots":1,"type":"cloud-g2","riskManagementApiEnabled":false,"metastatsApiEnabled":false}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts", json={ "name": "example", "server": "Tickwire-Sandbox", "magic": 0, "manualTrades": False, "quoteStreamingIntervalInSeconds": 2.5, "reliability": "regular", "resourceSlots": 1, "copyFactoryResourceSlots": 1, "type": "cloud-g2", "riskManagementApiEnabled": False, "metastatsApiEnabled": False, }, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts", { body: { "name": "example", "server": "Tickwire-Sandbox", "magic": 0, "manualTrades": false, "quoteStreamingIntervalInSeconds": 2.5, "reliability": "regular", "resourceSlots": 1, "copyFactoryResourceSlots": 1, "type": "cloud-g2", "riskManagementApiEnabled": false, "metastatsApiEnabled": false }, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id} **Get Account** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID"); console.log(result); tw.close(); ``` ### PUT /users/current/accounts/{account_id} **Update Account** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `UpdateTradingAccount` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `password` | `string \| null` | no | | | `server` | `string \| null` | no | | | `magic` | `integer \| null` | no | | | `manualTrades` | `boolean \| null` | no | | | `slippage` | `number \| null` | no | | | `quoteStreamingIntervalInSeconds` | `number \| null` | no | | | `tags` | `string[] \| null` | no | | | `metadata` | `object \| null` | no | | | `copyFactoryRoles` | `"PROVIDER" \| "SUBSCRIBER"[] \| null` | no | | | `resourceSlots` | `integer \| null` | no | | | `copyFactoryResourceSlots` | `integer \| null` | no | | | `metastatsApiEnabled` | `boolean \| null` | no | | | `allocateDedicatedIp` | `"ipv4" \| "none" \| null` | no | | | `serverAddress` | `string \| null` | no | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X PUT 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PUT", "/users/current/accounts/YOUR_ACCOUNT_ID", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PUT", "/users/current/accounts/YOUR_ACCOUNT_ID", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /users/current/accounts/{account_id} **Delete Account** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `executeForAllReplicas` | query | `boolean` | no | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/users/current/accounts/YOUR_ACCOUNT_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/users/current/accounts/YOUR_ACCOUNT_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### PUT /users/current/accounts/{account_id}/credentials **Set Credentials** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `Credentials` (required) | Field | Type | Required | Description | |---|---|---|---| | `login` | `string \| integer \| null` | no | | | `password` | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X PUT 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/credentials' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"password":"YOUR_PASSWORD"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PUT", "/users/current/accounts/YOUR_ACCOUNT_ID/credentials", json={"password": "YOUR_PASSWORD"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PUT", "/users/current/accounts/YOUR_ACCOUNT_ID/credentials", { body: {"password":"YOUR_PASSWORD"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/deploy **Deploy** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `executeForAllReplicas` | query | `boolean` | no | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/deploy' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/deploy", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/deploy", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/enable-account-features **Enable Account Features** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `AccountFeatures` (required) | Field | Type | Required | Description | |---|---|---|---| | `copyFactoryApi` | `CopyTradingEnable \| null` | no | | | `riskManagementApiEnabled` | `boolean \| null` | no | | | `metastatsApiEnabled` | `boolean \| null` | no | | | `reliabilityIncreased` | `boolean \| null` | no | | | `allocateDedicatedIp` | `"ipv4" \| "none" \| null` | no | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/enable-account-features' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-account-features", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-account-features", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/enable-copy-factory-api **Enable the copy trading API** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `CopyTradingEnable` (required) | Field | Type | Required | Description | |---|---|---|---| | `copyFactoryRoles` | `"PROVIDER" \| "SUBSCRIBER"[]` | yes | | | `copyFactoryResourceSlots` | `integer \| null` | no | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/enable-copy-factory-api' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"copyFactoryRoles":["PROVIDER"]}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-copy-factory-api", json={"copyFactoryRoles": ["PROVIDER"]}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-copy-factory-api", { body: {"copyFactoryRoles":["PROVIDER"]}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/enable-metastats-api **Enable the trading statistics API** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/enable-metastats-api' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-metastats-api", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-metastats-api", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/enable-risk-management-api **Enable Risk Management** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/enable-risk-management-api' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-risk-management-api", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/enable-risk-management-api", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/increase-reliability **Increase Reliability** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/increase-reliability' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/increase-reliability", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/increase-reliability", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/redeploy **Redeploy** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `executeForAllReplicas` | query | `boolean` | no | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/redeploy' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/redeploy", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/redeploy", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/undeploy **Undeploy** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `executeForAllReplicas` | query | `boolean` | no | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/undeploy' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/undeploy", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/undeploy", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /users/current/provisioning-profiles **List Profiles** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `version` | query | `integer \| null` | no | | | `status` | query | `"new" \| "active" \| null` | no | | | `type` | query | `"mtTerminal" \| "managerApi" \| null` | no | | | `query` | query | `string \| null` | no | | | `offset` | query | `integer` | no | | | `limit` | query | `integer` | no | | | `api-version` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/provisioning-profiles' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/provisioning-profiles", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/provisioning-profiles"); console.log(result); tw.close(); ``` ### POST /users/current/provisioning-profiles **Create Profile** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `NewProfile` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | yes | | | `version` | `4 \| 5` | yes | | | `brokerTimezone` | `string` | yes | | | `brokerDSTSwitchTimezone` | `string` | yes | | | `type` | `"mtTerminal" \| "managerApi"` | no | | | `managerLogin` | `string \| null` | no | | | `managerPassword` | `string \| null` | no | | | `managerServer` | `string \| null` | no | | Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/provisioning-profiles' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"name":"example","version":4,"brokerTimezone":"2026-09-01T00:00:00.000","brokerDSTSwitchTimezone":"2026-09-01T00:00:00.000","type":"mtTerminal"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/provisioning-profiles", json={ "name": "example", "version": 4, "brokerTimezone": "2026-09-01T00:00:00.000", "brokerDSTSwitchTimezone": "2026-09-01T00:00:00.000", "type": "mtTerminal", }, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/provisioning-profiles", { body: { "name": "example", "version": 4, "brokerTimezone": "2026-09-01T00:00:00.000", "brokerDSTSwitchTimezone": "2026-09-01T00:00:00.000", "type": "mtTerminal" }, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /users/current/provisioning-profiles/{profile_id} **Get Profile** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `profile_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/provisioning-profiles/PROFILE_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/provisioning-profiles/PROFILE_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/provisioning-profiles/PROFILE_ID"); console.log(result); tw.close(); ``` ### PUT /users/current/provisioning-profiles/{profile_id} **Update Profile** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `profile_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `UpdateProfile` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `brokerTimezone` | `string \| null` | no | | | `brokerDSTSwitchTimezone` | `string \| null` | no | | | `managerLogin` | `string \| null` | no | | | `managerPassword` | `string \| null` | no | | | `managerServer` | `string \| null` | no | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X PUT 'https://api.tickwire.io/users/current/provisioning-profiles/PROFILE_ID' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PUT", "/users/current/provisioning-profiles/PROFILE_ID", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PUT", "/users/current/provisioning-profiles/PROFILE_ID", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /users/current/provisioning-profiles/{profile_id} **Delete Profile** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `profile_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/users/current/provisioning-profiles/PROFILE_ID' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/users/current/provisioning-profiles/PROFILE_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/users/current/provisioning-profiles/PROFILE_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### PUT /users/current/provisioning-profiles/{profile_id}/{file_name} **Upload File** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `profile_id` | path | `string` | yes | | | `file_name` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X PUT 'https://api.tickwire.io/users/current/provisioning-profiles/PROFILE_ID/FILE_NAME' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PUT", "/users/current/provisioning-profiles/PROFILE_ID/FILE_NAME", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PUT", "/users/current/provisioning-profiles/PROFILE_ID/FILE_NAME", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Account state (Account REST API (/users/current)) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/account-state/ ### GET /users/current/accounts/{account_id}/account-information **Account Information** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `refreshTerminalState` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/account-information' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/account-information", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/account-information"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/capabilities **Capabilities** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/capabilities' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/capabilities", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/capabilities"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/orders **Orders** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `refreshTerminalState` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/orders' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/orders", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/orders"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/orders/{order_id} **Order** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `order_id` | path | `string` | yes | | | `refreshTerminalState` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/orders/ORDER_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/orders/ORDER_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/orders/ORDER_ID"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/positions **Positions** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `refreshTerminalState` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/positions' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/positions", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/positions"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/positions/{position_id} **Position** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `position_id` | path | `string` | yes | | | `refreshTerminalState` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/positions/POSITION_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/positions/POSITION_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/positions/POSITION_ID"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/server-time **Server Time** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `refresh` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/server-time' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/server-time", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/server-time"); console.log(result); tw.close(); ``` --- # Market data (Account REST API (/users/current)) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/market-data/ ### GET /users/current/accounts/{account_id}/historical-market-data/symbols/{symbol}/ticks **Historical Ticks** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | | `startTime` | query | `string \| null` | no | | | `offset` | query | `string \| null` | no | | | `limit` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `400, 501` [`not_supported_on_mt4`](https://tickwire.io/docs/errors/not_supported_on_mt4/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/historical-market-data/symbols/EURUSD/ticks' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/historical-market-data/symbols/EURUSD/ticks", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/historical-market-data/symbols/EURUSD/ticks"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/historical-market-data/symbols/{symbol}/timeframes/{timeframe}/candles **Historical Candles** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | | `timeframe` | path | `string` | yes | | | `startTime` | query | `string \| null` | no | | | `limit` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `400, 501` [`not_supported_on_mt4`](https://tickwire.io/docs/errors/not_supported_on_mt4/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/historical-market-data/symbols/EURUSD/timeframes/1h/candles' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/historical-market-data/symbols/EURUSD/timeframes/1h/candles", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/historical-market-data/symbols/EURUSD/timeframes/1h/candles"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/symbols **Symbols** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/symbols' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/symbols/{symbol}/current-book **Current Book** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | | `keepSubscription` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `400, 501` [`not_supported_on_mt4`](https://tickwire.io/docs/errors/not_supported_on_mt4/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-book' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-book", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-book"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/symbols/{symbol}/current-candles/{timeframe} **Current Candle** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | | `timeframe` | path | `string` | yes | | | `keepSubscription` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-candles/1h' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-candles/1h", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-candles/1h"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/symbols/{symbol}/current-price **Current Price** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | | `keepSubscription` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-price' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-price", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-price"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/symbols/{symbol}/current-tick **Current Tick** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | | `keepSubscription` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-tick' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-tick", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-tick"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/symbols/{symbol}/specification **Specification** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/specification' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/specification", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/specification"); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/symbols/{symbol}/unsubscribe **Unsubscribe** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/unsubscribe' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/unsubscribe", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/unsubscribe", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # History (Account REST API (/users/current)) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/history/ ### GET /users/current/accounts/{account_id}/history-deals/position/{position_id} **History Deals By Position** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `position_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/position/POSITION_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/position/POSITION_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/position/POSITION_ID"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/history-deals/ticket/{ticket} **History Deals By Ticket** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `ticket` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/ticket/TICKET' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/ticket/TICKET", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/ticket/TICKET"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/history-deals/time/{start_time}/{end_time} **History Deals By Time** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `start_time` | path | `string` | yes | | | `end_time` | path | `string` | yes | | | `offset` | query | `string \| null` | no | | | `limit` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/time/2026-09-01T00%3A00%3A00.000/2026-09-02T00%3A00%3A00.000' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/time/2026-09-01T00%3A00%3A00.000/2026-09-02T00%3A00%3A00.000", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-deals/time/2026-09-01T00%3A00%3A00.000/2026-09-02T00%3A00%3A00.000"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/history-orders/position/{position_id} **History Orders By Position** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `position_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/position/POSITION_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/position/POSITION_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/position/POSITION_ID"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/history-orders/ticket/{ticket} **History Orders By Ticket** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `ticket` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/ticket/TICKET' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/ticket/TICKET", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/ticket/TICKET"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/history-orders/time/{start_time}/{end_time} **History Orders By Time** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `start_time` | path | `string` | yes | | | `end_time` | path | `string` | yes | | | `offset` | query | `string \| null` | no | | | `limit` | query | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/time/2026-09-01T00%3A00%3A00.000/2026-09-02T00%3A00%3A00.000' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/time/2026-09-01T00%3A00%3A00.000/2026-09-02T00%3A00%3A00.000", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/history-orders/time/2026-09-01T00%3A00%3A00.000/2026-09-02T00%3A00%3A00.000"); console.log(result); tw.close(); ``` --- # Trading (Account REST API (/users/current)) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/trading/ ### POST /users/current/accounts/{account_id}/calculate-margin **Calculate Margin** Auth: `auth-token` Margin for an order: `{margin}`, or `{}` if not calculable. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/calculate-margin' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"symbol":"EURUSD","type":"ORDER_TYPE_BUY","volume":0.01,"openPrice":1.1}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/calculate-margin", json={ "symbol": "EURUSD", "type": "ORDER_TYPE_BUY", "volume": 0.01, "openPrice": 1.1, }, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/calculate-margin", { body: {"symbol":"EURUSD","type":"ORDER_TYPE_BUY","volume":0.01,"openPrice":1.1}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/trade **Trade** · takes `Idempotency-Key` Auth: `auth-token` Execute a trade (MT4 and MT5). Body: a `MetatraderTrade`. `actionType` is one of `ORDER_TYPE_BUY|SELL`, `ORDER_TYPE_BUY_LIMIT|SELL_LIMIT|BUY_STOP|SELL_STOP`, `ORDER_TYPE_BUY_STOP_LIMIT|SELL_STOP_LIMIT` (MT5 only), `POSITION_MODIFY`, `POSITION_PARTIAL`, `POSITION_CLOSE_ID`, `POSITION_CLOSE_BY`, `POSITIONS_CLOSE_SYMBOL`, `ORDER_MODIFY` or `ORDER_CANCEL`. Relative SL/TP units, `fillingModes`, `expiration`, `slippage`, `magic`, `comment` + `clientId` (30 characters together) and `trailingStopLoss` are supported. **HTTP 200 even when the broker rejects the trade**: `{numericCode, stringCode, message, orderId?, positionId?}`. Success codes are 0, 10008, 10009, 10010 and 10025. Tickwire adds `outcome` (`applied|no_change|partial|rejected|unknown`), `isEffective`, `retcode` (the terminal's own code), `replayed` and, for `POSITIONS_CLOSE_SYMBOL`, a per-position `positions` list. `outcome=unknown` means the order may have executed: check positions and orders before retrying. Tickwire never resends new exposure on its own. Idempotency: the `Idempotency-Key` header, else `clientId`. A replay returns the stored result with `replayed: true`; the same key with a different body is 409 `ConflictError`. `X-Actor` and `X-Reason` go to the audit trail. A malformed request is 400 `ValidationError` with `details: [{parameter, message}]`; what MT4 can't do (stop-limit, DAY expiry) answers `numericCode` -4 with `error: not_supported_on_mt4`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string` | no | | | `X-Reason` | header | `string` | no | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/trade' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/trade", json={"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.01}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/trade", { body: {"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /users/current/accounts/{account_id}/trade/check **Trade Check** Auth: `auth-token` Dry-run a trade: the same body as `/trade`. Runs every pre-flight check (and, on MT5, the terminal's own order check) and returns the resolved request plus margin figures. Nothing is sent. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/trade/check' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/accounts/YOUR_ACCOUNT_ID/trade/check", json={"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.01}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/accounts/YOUR_ACCOUNT_ID/trade/check", { body: {"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/trailing-stop-losses **List Trailing** Auth: `auth-token` Trailing stop rules Tickwire runs for this account (`state`: `active` | `pending`; `pending` waits for its pending order to fill). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/trailing-stop-losses' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/trailing-stop-losses", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/trailing-stop-losses"); console.log(result); tw.close(); ``` ### DELETE /users/current/accounts/{account_id}/trailing-stop-losses/{position_id} **Delete Trailing** · takes `Idempotency-Key` Auth: `auth-token` Stop trailing a position (the current SL stays where it is). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `position_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string` | no | | | `X-Reason` | header | `string` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/trailing-stop-losses/POSITION_ID' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/users/current/accounts/YOUR_ACCOUNT_ID/trailing-stop-losses/POSITION_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/users/current/accounts/YOUR_ACCOUNT_ID/trailing-stop-losses/POSITION_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Health, snapshot and audit trail (Account REST API (/users/current)) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/account-health-audit/ ### GET /users/current/accounts/{account_id}/audit **Account Audit** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `limit` | query | `integer` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/audit' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/audit", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/audit"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/health **Account Health** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/health' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/health", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/health"); console.log(result); tw.close(); ``` ### GET /users/current/accounts/{account_id}/snapshot **Account Snapshot** Auth: `auth-token` Account information, positions, orders, health and server time in one read (MT4 and MT5). Agents reach it as `GET /v1/agent/accounts/{id}/snapshot`. Body: `{account_id, platform, as_of, complete, terminal_connected, account_information, positions, orders, health, server_time}`. `as_of` is when the snapshot was complete (UTC); `complete` is true when every section is `ok`; `terminal_connected` is `null` when it is not known. Each section is `{status, read_at, age_ms, data, error?}`. `status` is `ok` (read from a terminal connected to its broker), `stale` (read, but the terminal was not connected, so values may be out of date) or `unavailable` (`data` is `null` and `error` is `{error, message}`); `health` and `server_time` are `ok` whenever they could be read. Sections are read one after another: compare `read_at` when that matters. `data` has the same shape as the individual routes; `server_time` gives `brokerUtcOffsetMinutes` (`null` until known, never assumed to be 0). Always 200 (an unreadable section says so); 503 only if nothing could be read. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/accounts/YOUR_ACCOUNT_ID/snapshot' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/accounts/YOUR_ACCOUNT_ID/snapshot", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/accounts/YOUR_ACCOUNT_ID/snapshot"); console.log(result); tw.close(); ``` --- # Tokens and discovery (Account REST API (/users/current)) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/tokens-discovery/ ### POST /users/current/narrow-down-auth-token **Narrow Down** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `validity-in-hours` | query | `number` | no | | | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/narrow-down-auth-token' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/narrow-down-auth-token", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/narrow-down-auth-token", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /users/current/regions **Regions** Auth: `auth-token` Responses: - `200` Successful Response (`string[]`) - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/regions' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/regions", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/regions"); console.log(result); tw.close(); ``` ### GET /users/current/servers/mt-client-api **Client Api Domain** Auth: `auth-token` Responses: - `200` Successful Response (`object`) - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/servers/mt-client-api' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/servers/mt-client-api", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/servers/mt-client-api"); console.log(result); tw.close(); ``` ### GET /users/current/tokens **List Tokens** Auth: `auth-token` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/tokens' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/tokens", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/tokens"); console.log(result); tw.close(); ``` ### POST /users/current/tokens **Create Token** · takes `Idempotency-Key` Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | Request body: `NewToken` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | no | | | `kind` | `"api" \| "account"` | no | | | `applications` | `string[] \| null` | no | | | `roles` | `string[] \| null` | no | | | `accountIds` | `string[] \| null` | no | | | `readOnly` | `boolean` | no | | | `ttlInHours` | `number \| null` | no | | | `ipAllowlist` | `string[] \| null` | no | | Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/users/current/tokens' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'Content-Type: application/json' \ -d '{"name":"","kind":"api","readOnly":false}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/users/current/tokens", json={"name": "", "kind": "api", "readOnly": False}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/users/current/tokens", { body: {"name":"","kind":"api","readOnly":false}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /users/current/tokens/{token_id} **Get Token** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `token_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/users/current/tokens/TOKEN_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/users/current/tokens/TOKEN_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/users/current/tokens/TOKEN_ID"); console.log(result); tw.close(); ``` ### PATCH /users/current/tokens/{token_id} **Patch Token** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `token_id` | path | `string` | yes | | Request body: `PatchToken` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `ipAllowlist` | `string[] \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X PATCH 'https://api.tickwire.io/users/current/tokens/TOKEN_ID' \ -H 'auth-token: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PATCH", "/users/current/tokens/TOKEN_ID", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PATCH", "/users/current/tokens/TOKEN_ID", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /users/current/tokens/{token_id} **Revoke Token** Auth: `auth-token` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `token_id` | path | `string` | yes | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/users/current/tokens/TOKEN_ID' \ -H 'auth-token: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/users/current/tokens/TOKEN_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/users/current/tokens/TOKEN_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/access-rule-manifest **Access Rule Manifest** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/access-rule-manifest' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/access-rule-manifest", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/access-rule-manifest"); console.log(result); tw.close(); ``` ### GET /v1/known-mt-servers/{version}/search **Search Servers** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `version` | path | `integer` | yes | | | `query` | query | `string` | no | | Responses: - `200` Successful Response (`object`) - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/known-mt-servers/5/search' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/known-mt-servers/5/search", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/known-mt-servers/5/search"); console.log(result); tw.close(); ``` --- # MT5 terminal (Terminal routes and batch orders) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/mt5-terminal/ ### GET /mt5/{account_id}/AccountInfo **GET /mt5/{account_id}/AccountInfo** Auth: `X-API-Key` Static account identity and configuration: name, login, server, company, currency, leverage, type, margin mode (Netting/Hedging/Exchange; always Hedging on MT4), stop-out configuration and trade permissions. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/AccountInfo' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/AccountInfo", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/AccountInfo"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/AccountSummary **GET /mt5/{account_id}/AccountSummary** Auth: `X-API-Key` Live financial snapshot: balance, credit, floating profit, equity, margin, free margin, margin level, leverage, currency and account type (Demo/Contest/Real; `Unknown` if the terminal does not say). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/AccountSummary' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/AccountSummary", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/AccountSummary"); console.log(result); tw.close(); ``` ### POST /mt5/{account_id}/CloseAll **POST /mt5/{account_id}/CloseAll** Auth: `X-API-Key` Close every open position, optionally only `symbol` and/or `magic` (`magic: 0` means manually opened), and with `deletePending: true` also delete matching pending orders. Each ticket is its own audited, idempotent close (`Idempotency-Key` + `#ticket`); the whole reply is replayed for the same key. `closed` counts tickets now closed (including ones already gone), `failed` rejections, `unknown` lost replies. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/CloseAll' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt5/YOUR_ACCOUNT_ID/CloseAll", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt5/YOUR_ACCOUNT_ID/CloseAll", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/OpenedOrders **GET /mt5/{account_id}/OpenedOrders** Auth: `X-API-Key` All open positions (`kind: position`) and pending orders (`kind: pending`). Pending rows show their trigger price in `openPrice`, the current market price on their side in `currentPrice`, and zero swap/profit. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/OpenedOrders' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/OpenedOrders", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/OpenedOrders"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/OrderCalcMargin **GET /mt5/{account_id}/OrderCalcMargin** Auth: `X-API-Key` Margin (account currency) needed to open `volume` lots of `operation` on `symbol` at `price`. Places nothing. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/OrderCalcMargin' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/OrderCalcMargin", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/OrderCalcMargin"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/OrderCalcProfit **GET /mt5/{account_id}/OrderCalcProfit** Auth: `X-API-Key` Projected P/L (account currency) of `volume` lots from `priceOpen` to `priceClose`; pending operations count by direction only. Places nothing. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/OrderCalcProfit' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/OrderCalcProfit", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/OrderCalcProfit"); console.log(result); tw.close(); ``` ### POST /mt5/{account_id}/OrderClose **POST /mt5/{account_id}/OrderClose** Auth: `X-API-Key` Close a position (`volume` for a partial close; omitted or 0 closes it all) or delete a pending order: the ticket type decides. `slippage` in points (default 10). Closing a ticket that is already gone is `outcome: no_change` with `isEffective: true` and nothing sent, so a retried close is safe. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/OrderClose' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt5/YOUR_ACCOUNT_ID/OrderClose", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt5/YOUR_ACCOUNT_ID/OrderClose", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/OrderHistory **GET /mt5/{account_id}/OrderHistory** Auth: `X-API-Key` Closed deals (executions, not orders) in `[from, to]`, broker server time, ISO-8601 or YYYY-MM-DD; absent bounds mean all time. Each row carries `entry` (In/Out/InOut/OutBy) and `position` (the round trip it belongs to). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/OrderHistory' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/OrderHistory", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/OrderHistory"); console.log(result); tw.close(); ``` ### POST /mt5/{account_id}/OrderModify **POST /mt5/{account_id}/OrderModify** Auth: `X-API-Key` Modify a position (`stopLoss`/`takeProfit` only) or a pending order (also `price`, `stopLimitPrice`, `expiration`). Omitted fields keep their current value; `0` clears a stop. An unknown ticket is a `rejected` result with retcode 0 and nothing is sent. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/OrderModify' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt5/YOUR_ACCOUNT_ID/OrderModify", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt5/YOUR_ACCOUNT_ID/OrderModify", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /mt5/{account_id}/OrderSend **POST /mt5/{account_id}/OrderSend** Auth: `X-API-Key` Submit a market (Buy/Sell) or pending (*Limit/*Stop/*StopLimit) order. Body: `symbol`*, `operation`* (case/separator-insensitive), `volume`*, `price` (pending), `stopLimitPrice` (*StopLimit), `stopLoss`, `takeProfit`, `slippage` (points, default 10), `expiration` (pending; absent = good till cancelled), `comment`, `expertId` (magic). Unknown fields are refused; an unknown symbol is never sent (HTTP 500, reason `symbol_not_found`). A 200 only means the terminal answered: read `success` and `outcome`. Stop-limit orders on MT4 give `not_supported_on_mt4`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/OrderSend' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt5/YOUR_ACCOUNT_ID/OrderSend", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt5/YOUR_ACCOUNT_ID/OrderSend", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/PositionHistory **GET /mt5/{account_id}/PositionHistory** Auth: `X-API-Key` Closed positions closed within `[from, to]`: one row per round trip with volume-weighted open/close prices, summed profit/swap/commission and `netProfit`. A position still partly open is not listed. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/PositionHistory' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/PositionHistory", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/PositionHistory"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/PriceHistory **GET /mt5/{account_id}/PriceHistory** Auth: `X-API-Key` OHLC bars for `symbol` and `timeframe` (M1, M5, M15, M30, H1, H4, D1, W1, MN1 or 5min/1h/1d) in `[from, to]` (broker time). Without `from` the most recent 50 000 bars are searched. MT5-only timeframes on MT4 give `not_supported_on_mt4`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/PriceHistory' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/PriceHistory", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/PriceHistory"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/ServerTimezone **GET /mt5/{account_id}/ServerTimezone** Auth: `X-API-Key` Broker server time and its offset from UTC: `utc = serverTime - utcOffsetSeconds`. `utcOffsetSource` says where the offset came from (`terminal` or `estimated` from a live broker clock). If neither is possible the answer is 503 `broker_offset_unknown`, never a guess. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/ServerTimezone' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/ServerTimezone", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/ServerTimezone"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/SymbolInfo **GET /mt5/{account_id}/SymbolInfo** Auth: `X-API-Key` Contract specification for `symbol`: digits, point, spread, contract size, tick size/value, volume limits, trade mode, swaps, currencies, plus the current bid/ask. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/SymbolInfo' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/SymbolInfo", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/SymbolInfo"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/getQuote **GET /mt5/{account_id}/getQuote** Auth: `X-API-Key` Latest tick for `symbol`: bid, ask, last, volume and broker time. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/getQuote' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/getQuote", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/getQuote"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/healthz **GET /mt5/{account_id}/healthz** Auth: `X-API-Key` Readiness check: 200 once the terminal is `ready`, otherwise 503. The body holds no personal data: `{status, terminal, broker, account}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/healthz' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/healthz", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/healthz"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/livez **GET /mt5/{account_id}/livez** Auth: `X-API-Key` Liveness check: 200 while the terminal answers (whatever the broker link), otherwise 503. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/livez' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/livez", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/livez"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/status **GET /mt5/{account_id}/status** Auth: `X-API-Key` Connection health in one call, always HTTP 200: `ready` (connected, logged in, ticks live), `starting` (not ready yet since the terminal started, within 5 minutes), `degraded` (broker link down or quotes frozen) or `down` (terminal not answering). `tickwire` carries our full ladder (healthy/stale/disconnected/down) with reasons and ages. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/status' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/status", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/status"); console.log(result); tw.close(); ``` ### GET /mt5/{account_id}/symbols **GET /mt5/{account_id}/symbols** Auth: `X-API-Key` Names of all symbols available on this terminal. Use them verbatim: brokers suffix symbols (EURUSD.sd, XAUUSDm). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt5/YOUR_ACCOUNT_ID/symbols' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt5/YOUR_ACCOUNT_ID/symbols", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt5/YOUR_ACCOUNT_ID/symbols"); console.log(result); tw.close(); ``` --- # MT4 terminal (Terminal routes and batch orders) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/mt4-terminal/ ### GET /mt4/{account_id}/AccountInfo **GET /mt4/{account_id}/AccountInfo** Auth: `X-API-Key` Static account identity and configuration: name, login, server, company, currency, leverage, type, margin mode (Netting/Hedging/Exchange; always Hedging on MT4), stop-out configuration and trade permissions. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/AccountInfo' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/AccountInfo", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/AccountInfo"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/AccountSummary **GET /mt4/{account_id}/AccountSummary** Auth: `X-API-Key` Live financial snapshot: balance, credit, floating profit, equity, margin, free margin, margin level, leverage, currency and account type (Demo/Contest/Real; `Unknown` if the terminal does not say). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/AccountSummary' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/AccountSummary", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/AccountSummary"); console.log(result); tw.close(); ``` ### POST /mt4/{account_id}/CloseAll **POST /mt4/{account_id}/CloseAll** Auth: `X-API-Key` Close every open position, optionally only `symbol` and/or `magic` (`magic: 0` means manually opened), and with `deletePending: true` also delete matching pending orders. Each ticket is its own audited, idempotent close (`Idempotency-Key` + `#ticket`); the whole reply is replayed for the same key. `closed` counts tickets now closed (including ones already gone), `failed` rejections, `unknown` lost replies. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/CloseAll' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt4/YOUR_ACCOUNT_ID/CloseAll", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt4/YOUR_ACCOUNT_ID/CloseAll", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/OpenedOrders **GET /mt4/{account_id}/OpenedOrders** Auth: `X-API-Key` All open positions (`kind: position`) and pending orders (`kind: pending`). Pending rows show their trigger price in `openPrice`, the current market price on their side in `currentPrice`, and zero swap/profit. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/OpenedOrders' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/OpenedOrders", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/OpenedOrders"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/OrderCalcMargin **GET /mt4/{account_id}/OrderCalcMargin** Auth: `X-API-Key` Margin (account currency) needed to open `volume` lots of `operation` on `symbol` at `price`. Places nothing. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/OrderCalcMargin' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/OrderCalcMargin", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/OrderCalcMargin"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/OrderCalcProfit **GET /mt4/{account_id}/OrderCalcProfit** Auth: `X-API-Key` Projected P/L (account currency) of `volume` lots from `priceOpen` to `priceClose`; pending operations count by direction only. Places nothing. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/OrderCalcProfit' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/OrderCalcProfit", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/OrderCalcProfit"); console.log(result); tw.close(); ``` ### POST /mt4/{account_id}/OrderClose **POST /mt4/{account_id}/OrderClose** Auth: `X-API-Key` Close a position (`volume` for a partial close; omitted or 0 closes it all) or delete a pending order: the ticket type decides. `slippage` in points (default 10). Closing a ticket that is already gone is `outcome: no_change` with `isEffective: true` and nothing sent, so a retried close is safe. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/OrderClose' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt4/YOUR_ACCOUNT_ID/OrderClose", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt4/YOUR_ACCOUNT_ID/OrderClose", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/OrderHistory **GET /mt4/{account_id}/OrderHistory** Auth: `X-API-Key` Closed deals (executions, not orders) in `[from, to]`, broker server time, ISO-8601 or YYYY-MM-DD; absent bounds mean all time. Each row carries `entry` (In/Out/InOut/OutBy) and `position` (the round trip it belongs to). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/OrderHistory' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/OrderHistory", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/OrderHistory"); console.log(result); tw.close(); ``` ### POST /mt4/{account_id}/OrderModify **POST /mt4/{account_id}/OrderModify** Auth: `X-API-Key` Modify a position (`stopLoss`/`takeProfit` only) or a pending order (also `price`, `stopLimitPrice`, `expiration`). Omitted fields keep their current value; `0` clears a stop. An unknown ticket is a `rejected` result with retcode 0 and nothing is sent. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/OrderModify' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt4/YOUR_ACCOUNT_ID/OrderModify", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt4/YOUR_ACCOUNT_ID/OrderModify", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /mt4/{account_id}/OrderSend **POST /mt4/{account_id}/OrderSend** Auth: `X-API-Key` Submit a market (Buy/Sell) or pending (*Limit/*Stop/*StopLimit) order. Body: `symbol`*, `operation`* (case/separator-insensitive), `volume`*, `price` (pending), `stopLimitPrice` (*StopLimit), `stopLoss`, `takeProfit`, `slippage` (points, default 10), `expiration` (pending; absent = good till cancelled), `comment`, `expertId` (magic). Unknown fields are refused; an unknown symbol is never sent (HTTP 500, reason `symbol_not_found`). A 200 only means the terminal answered: read `success` and `outcome`. Stop-limit orders on MT4 give `not_supported_on_mt4`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/OrderSend' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/mt4/YOUR_ACCOUNT_ID/OrderSend", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/mt4/YOUR_ACCOUNT_ID/OrderSend", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/PositionHistory **GET /mt4/{account_id}/PositionHistory** Auth: `X-API-Key` Closed positions closed within `[from, to]`: one row per round trip with volume-weighted open/close prices, summed profit/swap/commission and `netProfit`. A position still partly open is not listed. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/PositionHistory' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/PositionHistory", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/PositionHistory"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/PriceHistory **GET /mt4/{account_id}/PriceHistory** Auth: `X-API-Key` OHLC bars for `symbol` and `timeframe` (M1, M5, M15, M30, H1, H4, D1, W1, MN1 or 5min/1h/1d) in `[from, to]` (broker time). Without `from` the most recent 50 000 bars are searched. MT5-only timeframes on MT4 give `not_supported_on_mt4`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/PriceHistory' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/PriceHistory", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/PriceHistory"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/ServerTimezone **GET /mt4/{account_id}/ServerTimezone** Auth: `X-API-Key` Broker server time and its offset from UTC: `utc = serverTime - utcOffsetSeconds`. `utcOffsetSource` says where the offset came from (`terminal` or `estimated` from a live broker clock). If neither is possible the answer is 503 `broker_offset_unknown`, never a guess. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/ServerTimezone' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/ServerTimezone", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/ServerTimezone"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/SymbolInfo **GET /mt4/{account_id}/SymbolInfo** Auth: `X-API-Key` Contract specification for `symbol`: digits, point, spread, contract size, tick size/value, volume limits, trade mode, swaps, currencies, plus the current bid/ask. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/SymbolInfo' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/SymbolInfo", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/SymbolInfo"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/getQuote **GET /mt4/{account_id}/getQuote** Auth: `X-API-Key` Latest tick for `symbol`: bid, ask, last, volume and broker time. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/getQuote' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/getQuote", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/getQuote"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/healthz **GET /mt4/{account_id}/healthz** Auth: `X-API-Key` Readiness check: 200 once the terminal is `ready`, otherwise 503. The body holds no personal data: `{status, terminal, broker, account}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/healthz' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/healthz", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/healthz"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/livez **GET /mt4/{account_id}/livez** Auth: `X-API-Key` Liveness check: 200 while the terminal answers (whatever the broker link), otherwise 503. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/livez' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/livez", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/livez"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/status **GET /mt4/{account_id}/status** Auth: `X-API-Key` Connection health in one call, always HTTP 200: `ready` (connected, logged in, ticks live), `starting` (not ready yet since the terminal started, within 5 minutes), `degraded` (broker link down or quotes frozen) or `down` (terminal not answering). `tickwire` carries our full ladder (healthy/stale/disconnected/down) with reasons and ages. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/status' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/status", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/status"); console.log(result); tw.close(); ``` ### GET /mt4/{account_id}/symbols **GET /mt4/{account_id}/symbols** Auth: `X-API-Key` Names of all symbols available on this terminal. Use them verbatim: brokers suffix symbols (EURUSD.sd, XAUUSDm). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `503` [`not_connected`](https://tickwire.io/docs/errors/not_connected/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/mt4/YOUR_ACCOUNT_ID/symbols' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/mt4/YOUR_ACCOUNT_ID/symbols", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/mt4/YOUR_ACCOUNT_ID/symbols"); console.log(result); tw.close(); ``` --- # Batch orders (Terminal routes and batch orders) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/batch-orders/ ### POST /v1/orders **Batch orders** Auth: `X-API-Key` Send one order to several accounts at once (at most 20 legs). Every leg inherits `defaults` and may override any of it, including with a falsy value (`slippage: 0` means zero). Fields are snake_case: `symbol`, `operation` (buy, sell, buyLimit, sellLimit, buyStop, sellStop, buyStopLimit, sellStopLimit), `volume`, `price`, `slippage`, `stop_loss`, `take_profit`, `stop_limit_price`, `expiration`, `comment`, `expert_id` and, on the leg, `account_id`. `results` mirrors `orders` one for one. Leg `status`: `filled` (the broker accepted), `rejected` (the broker refused; `retcode` says why), `invalid` (the terminal refused the request), `unavailable` (terminal up but not trading), `unreachable` (no terminal), `timeout` (**unknown**: it may have executed, including when the broker's reply was lost; reconcile or replay with the same `Idempotency-Key`, never blind-retry). Validation is all-or-nothing, execution is not. Errors: 400 `invalid_batch` / `unknown_account` / `unreachable_account` (with `require_reachable`), 401, 403 (read-only key), 409 `idempotency_in_flight`, 422 `idempotency_key_reused`, 429 `rate_limited` (60 batches a minute per organisation, with `Retry-After`), 503 `idempotency_unavailable`. `Idempotency-Key` (at most 128 characters) replays the stored response for 15 minutes with `idempotent_replay: true`; each leg also carries its own derived key, so a retry never double-fills a leg that already executed. Every leg is in its account's audit trail. Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/orders' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/orders", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/orders", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/orders/close **Batch close** Auth: `X-API-Key` Close by selector (or explicit tickets) across several accounts at once (at most 20 accounts, 20 orders each; more come back `skipped`). Each account entry is a selector (`symbol` required, `*` for all, typed literally; `symbol_match` `exact` or `base` to accept broker suffixes like `.sd` / `m`; `side` long, short or any; `kind` position (default), pending or any; `magic`) or an explicit `tickets` list, never both. `volume` closes part of each matched position. Accounts run concurrently; the tickets of one account run in sequence. Account `status`: closed, partial, failed, nothing_matched (not an error), unavailable / unreachable / invalid (the lookup failed, so nothing is known), timeout (orders may have closed). Ticket `status`: closed, rejected, invalid, unavailable, unreachable, timeout (may have closed), skipped (never sent). A ticket that was already gone counts as `closed` with a message saying so. Errors and `Idempotency-Key` work as on `POST /v1/orders`. Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/orders/close' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/orders/close", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/orders/close", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Sandbox (Native /v1) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/sandbox/ ### GET /v1/sandbox **Sandbox Info** Auth: `X-API-Key` Public description of the sandbox; no key needed. `{sandbox: true, server, keyPrefix, maxAccounts, signup, magicLogins: [{login, scenario}]}`. `signup` says whether anonymous sign-up is open; each magic login, used as the account login on the sandbox server, plays its scenario (see the Sandbox guide). Responses: - `200` Successful Response Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/sandbox' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/sandbox", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/sandbox"); console.log(result); tw.close(); ``` ### POST /v1/sandbox/keys **Create Key** · takes `Idempotency-Key` Auth: `X-API-Key` A `twsk_` key for the caller's sandbox (linked to a live tenant). `Idempotency-Key` is honoured: a replay mints nothing and answers `apiKey: null` with an `apiKeyNotice`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | Request body: `KeyBody | null` Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/sandbox/keys' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'Content-Type: application/json' \ -d '{"name":"sandbox"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/sandbox/keys", json={"name": "sandbox"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/sandbox/keys", { body: {"name":"sandbox"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/sandbox/signup **Signup** Auth: `X-API-Key` Anonymous sandbox sign-up: a sandbox, a **restricted** `twsk_` key and one deployed account (login `1000`, server `Tickwire-Sandbox`). Body (optional): `{"platform": "mt5"|"mt4"}`. 201 `{sandbox: true, restricted: true, tenantId, apiKey, account: {id, platform, server, login, state, connectionStatus}}`. The key is shown once. A restricted key may manage its accounts, trade, stream and read; anything else that changes state (webhooks, pre-trade hooks, agent keys, more keys or tokens) answers 403 `sandbox_key_restricted`. Sign-ups are limited per client address (5 an hour, 10 a day) and in total; over a limit, 429 `rate_limited` with `Retry-After`. 403 `forbidden` when sign-up is turned off. Anonymous sandboxes unused for 7 days are deleted. Request body: `SandboxSignupBody | null` Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/sandbox/signup' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"platform":"mt5"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/sandbox/signup", json={"platform": "mt5"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/sandbox/signup", { body: {"platform":"mt5"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Accounts (Native /v1) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/accounts/ ### GET /v1/accounts **List Accounts** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/accounts' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/accounts", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/accounts"); console.log(result); tw.close(); ``` ### POST /v1/accounts **Link Account** · takes `Idempotency-Key` Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | Request body: `CreateAccount` (required) | Field | Type | Required | Description | |---|---|---|---| | `platform` | `"mt4" \| "mt5"` | no | | | `server` | `string` | yes | | | `login` | `integer` | yes | | | `password` | `string` | yes | | | `nickname` | `string` | no | | | `trade_ea_symbol` | `string` | no | | | `proxy_address` | `string` | no | | | `proxy_type` | `string` | no | | | `proxy_auth` | `string` | no | | | `proxy_local_port` | `integer` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/accounts' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'Content-Type: application/json' \ -d '{"platform":"mt5","server":"Tickwire-Sandbox","login":1,"password":"YOUR_PASSWORD","nickname":"","trade_ea_symbol":"","proxy_address":"","proxy_type":"","proxy_auth":"","proxy_local_port":0}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/accounts", json={ "platform": "mt5", "server": "Tickwire-Sandbox", "login": 1, "password": "YOUR_PASSWORD", "nickname": "", "trade_ea_symbol": "", "proxy_address": "", "proxy_type": "", "proxy_auth": "", "proxy_local_port": 0, }, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/accounts", { body: { "platform": "mt5", "server": "Tickwire-Sandbox", "login": 1, "password": "YOUR_PASSWORD", "nickname": "", "trade_ea_symbol": "", "proxy_address": "", "proxy_type": "", "proxy_auth": "", "proxy_local_port": 0 }, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/accounts/{account_id} **Get Account** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/accounts/YOUR_ACCOUNT_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/accounts/YOUR_ACCOUNT_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/accounts/YOUR_ACCOUNT_ID"); console.log(result); tw.close(); ``` ### PATCH /v1/accounts/{account_id} **Patch Account** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Request body: `PatchAccount` (required) | Field | Type | Required | Description | |---|---|---|---| | `trade_ea_symbol` | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) curl: ```bash curl -sS -X PATCH 'https://api.tickwire.io/v1/accounts/YOUR_ACCOUNT_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PATCH", "/v1/accounts/YOUR_ACCOUNT_ID", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PATCH", "/v1/accounts/YOUR_ACCOUNT_ID", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /v1/accounts/{account_id} **Unlink Account** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/accounts/YOUR_ACCOUNT_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/accounts/YOUR_ACCOUNT_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/accounts/YOUR_ACCOUNT_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Webhooks and events (Native /v1) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/webhooks/ ### POST /v1/events/{event_id}/resend **Resend Event** · takes `Idempotency-Key` Auth: `X-API-Key` Queue an event again to every endpoint that received it (or `webhookId`). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `event_id` | path | `string` | yes | | | `webhookId` | query | `string \| null` | no | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `202` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/events/EVENT_ID/resend' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/events/EVENT_ID/resend", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/events/EVENT_ID/resend", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/webhook-event-types **Event Types** Auth: `X-API-Key` Every webhook event type, with a description, its source and an example envelope. Responses: - `200` Successful Response Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/webhook-event-types' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/webhook-event-types", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/webhook-event-types"); console.log(result); tw.close(); ``` ### POST /v1/webhook-events/trigger **Trigger** · takes `Idempotency-Key` Auth: `X-API-Key` Publish one test event of a catalog type (any type in the sandbox; live: `webhook.test`). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `TriggerBody` (required) | Field | Type | Required | Description | |---|---|---|---| | `type` | `string` | yes | | | `accountId` | `string \| null` | no | | Responses: - `202` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhook-events/trigger' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"type":"string"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhook-events/trigger", json={"type": "string"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhook-events/trigger", { body: {"type":"string"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/webhook-listeners **Create Listener** Auth: `X-API-Key` Start a local-forwarding listener: its signing secret and the current cursor. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhook-listeners' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhook-listeners", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhook-listeners", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/webhook-listeners/{listener_id}/events **Listener Events** Auth: `X-API-Key` The tenant's events after the `after` cursor, each signed with the listener secret. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `listener_id` | path | `string` | yes | | | `after` | query | `string` | no | | | `types` | query | `string[] \| null` | no | | | `limit` | query | `integer` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/webhook-listeners/LISTENER_ID/events' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/webhook-listeners/LISTENER_ID/events", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/webhook-listeners/LISTENER_ID/events"); console.log(result); tw.close(); ``` ### GET /v1/webhooks **List Webhooks** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/webhooks' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/webhooks", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/webhooks"); console.log(result); tw.close(); ``` ### POST /v1/webhooks **Create Webhook** Auth: `X-API-Key` Request body: `CreateWebhook` (required) | Field | Type | Required | Description | |---|---|---|---| | `url` | `string` | yes | | | `secret` | `string \| null` | no | | Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhooks' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"url":"https://example.com/hook"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhooks", json={"url": "https://example.com/hook"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhooks", { body: {"url":"https://example.com/hook"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/webhooks/{webhook_id} **Get Webhook** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/webhooks/WEBHOOK_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/webhooks/WEBHOOK_ID"); console.log(result); tw.close(); ``` ### PATCH /v1/webhooks/{webhook_id} **Patch Endpoint** · takes `Idempotency-Key` Auth: `X-API-Key` Change the event filter (`enabledEvents`), URL or description. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `PatchEndpoint` (required) | Field | Type | Required | Description | |---|---|---|---| | `enabledEvents` | `string[] \| null` | no | | | `url` | `string \| null` | no | | | `description` | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X PATCH 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PATCH", "/v1/webhooks/WEBHOOK_ID", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PATCH", "/v1/webhooks/WEBHOOK_ID", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /v1/webhooks/{webhook_id} **Delete Webhook** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/webhooks/WEBHOOK_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/webhooks/WEBHOOK_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/webhooks/{webhook_id}/deliveries **List Deliveries** Auth: `X-API-Key` The endpoint's deliveries, newest first (`{data, hasMore, nextCursor}`). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `status` | query | `string \| null` | no | | | `eventType` | query | `string \| null` | no | | | `eventId` | query | `string \| null` | no | | | `since` | query | `string \| null` | no | | | `until` | query | `string \| null` | no | | | `cursor` | query | `string \| null` | no | | | `limit` | query | `integer` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/deliveries' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/webhooks/WEBHOOK_ID/deliveries", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/webhooks/WEBHOOK_ID/deliveries"); console.log(result); tw.close(); ``` ### GET /v1/webhooks/{webhook_id}/deliveries/{delivery_id} **Get Delivery** Auth: `X-API-Key` One delivery with every attempt, the signed payload and the last response body. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `delivery_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/deliveries/DELIVERY_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/webhooks/WEBHOOK_ID/deliveries/DELIVERY_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/webhooks/WEBHOOK_ID/deliveries/DELIVERY_ID"); console.log(result); tw.close(); ``` ### POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/resend **Resend Delivery** · takes `Idempotency-Key` Auth: `X-API-Key` Queue this delivery's event again to the endpoint. Returns the new delivery (202). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `delivery_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `202` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/deliveries/DELIVERY_ID/resend' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhooks/WEBHOOK_ID/deliveries/DELIVERY_ID/resend", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhooks/WEBHOOK_ID/deliveries/DELIVERY_ID/resend", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/webhooks/{webhook_id}/disable **Disable Endpoint** · takes `Idempotency-Key` Auth: `X-API-Key` Stop deliveries to an endpoint; unfinished deliveries are closed as failed. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/disable' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhooks/WEBHOOK_ID/disable", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhooks/WEBHOOK_ID/disable", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/webhooks/{webhook_id}/enable **Enable Endpoint** · takes `Idempotency-Key` Auth: `X-API-Key` Re-enable an endpoint (after an automatic disable, or your own). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/enable' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhooks/WEBHOOK_ID/enable", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhooks/WEBHOOK_ID/enable", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/webhooks/{webhook_id}/reveal-secret **Reveal Secret** Auth: `X-API-Key` The current signing secret (and the previous one during a rotation overlap). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/reveal-secret' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhooks/WEBHOOK_ID/reveal-secret", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhooks/WEBHOOK_ID/reveal-secret", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/webhooks/{webhook_id}/rotate-secret **Rotate Secret** · takes `Idempotency-Key` Auth: `X-API-Key` New signing secret; the old one stays valid for `overlapHours` (default 24). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `RotateSecret | null` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/rotate-secret' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"overlapHours":24}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/webhooks/WEBHOOK_ID/rotate-secret", json={"overlapHours": 24}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/webhooks/WEBHOOK_ID/rotate-secret", { body: {"overlapHours":24}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/webhooks/{webhook_id}/settings **Endpoint Settings** Auth: `X-API-Key` Endpoint status, failure streak, event filter and secret-rotation state. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `webhook_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/webhooks/WEBHOOK_ID/settings' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/webhooks/WEBHOOK_ID/settings", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/webhooks/WEBHOOK_ID/settings"); console.log(result); tw.close(); ``` --- # Read-only keys (Native /v1) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/keys/ ### GET /v1/readonly-keys **List Ro Keys** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/readonly-keys' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/readonly-keys", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/readonly-keys"); console.log(result); tw.close(); ``` ### POST /v1/readonly-keys **Create Ro Key** · takes `Idempotency-Key` Auth: `X-API-Key` Create a read-only key. `key` is shown once and can't be shown again. With `Idempotency-Key` a replay creates nothing and answers `key: null` with a `key_notice` saying it was already shown. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | Request body: `CreateReadonlyKey` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | yes | | | `scope` | `"all" \| "selected"` | no | | | `account_ids` | `string[]` | no | | Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/readonly-keys' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'Content-Type: application/json' \ -d '{"name":"example","scope":"all"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/readonly-keys", json={"name": "example", "scope": "all"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/readonly-keys", { body: {"name":"example","scope":"all"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/readonly-keys/{key_id} **Get Ro Key** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/readonly-keys/KEY_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/readonly-keys/KEY_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/readonly-keys/KEY_ID"); console.log(result); tw.close(); ``` ### PATCH /v1/readonly-keys/{key_id} **Patch Ro Key** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | Request body: `PatchReadonlyKey` (required) | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `scope` | `"all" \| "selected" \| null` | no | | | `account_ids` | `string[] \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X PATCH 'https://api.tickwire.io/v1/readonly-keys/KEY_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PATCH", "/v1/readonly-keys/KEY_ID", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PATCH", "/v1/readonly-keys/KEY_ID", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /v1/readonly-keys/{key_id} **Delete Ro Key** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/readonly-keys/KEY_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/readonly-keys/KEY_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/readonly-keys/KEY_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/readonly-keys/{key_id}/rotate **Rotate Ro Key** · takes `Idempotency-Key` Auth: `X-API-Key` Issue a new value for a read-only key (same id, scope and accounts); the old value stops working. The new `key` is shown once (`key_notice`). With `Idempotency-Key` a replay rotates nothing and answers `key: null` with a `key_notice` saying it was already shown; the same `Idempotency-Key` on another key's rotate answers `409 idempotency_conflict`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/readonly-keys/KEY_ID/rotate' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/readonly-keys/KEY_ID/rotate", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/readonly-keys/KEY_ID/rotate", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Private servers (Native /v1) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/private-servers/ ### GET /v1/private-servers **List Servers** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/private-servers' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/private-servers", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/private-servers"); console.log(result); tw.close(); ``` ### POST /v1/private-servers **Buy Server** · takes `Idempotency-Key` Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | Request body: `CreatePrivateServer` (required) | Field | Type | Required | Description | |---|---|---|---| | `slots` | `integer` | yes | | | `region` | `string` | yes | | | `name` | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/private-servers' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'Content-Type: application/json' \ -d '{"slots":1,"region":"eu","name":"example"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/private-servers", json={"slots": 1, "region": "eu", "name": "example"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/private-servers", { body: {"slots":1,"region":"eu","name":"example"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/private-servers/regions **Regions** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/private-servers/regions' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/private-servers/regions", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/private-servers/regions"); console.log(result); tw.close(); ``` ### GET /v1/private-servers/{server_id} **Get Server** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `server_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/private-servers/SERVER_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/private-servers/SERVER_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/private-servers/SERVER_ID"); console.log(result); tw.close(); ``` ### PATCH /v1/private-servers/{server_id} **Resize Server** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `server_id` | path | `string` | yes | | Request body: `PatchPrivateServer` (required) | Field | Type | Required | Description | |---|---|---|---| | `slots` | `integer` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X PATCH 'https://api.tickwire.io/v1/private-servers/SERVER_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{"slots":1}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PATCH", "/v1/private-servers/SERVER_ID", json={"slots": 1}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PATCH", "/v1/private-servers/SERVER_ID", { body: {"slots":1}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /v1/private-servers/{server_id} **Cancel Server** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `server_id` | path | `string` | yes | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/private-servers/SERVER_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/private-servers/SERVER_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/private-servers/SERVER_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/private-servers/{server_id}/accounts **Add Server Account** · takes `Idempotency-Key` Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `server_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | Request body: `PrivateServerAddAccount` (required) | Field | Type | Required | Description | |---|---|---|---| | `platform` | `"mt4" \| "mt5"` | no | | | `server` | `string` | yes | | | `login` | `integer` | yes | | | `password` | `string` | yes | | | `nickname` | `string` | no | | | `trade_ea_symbol` | `string` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/private-servers/SERVER_ID/accounts' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'Content-Type: application/json' \ -d '{"platform":"mt5","server":"Tickwire-Sandbox","login":1,"password":"YOUR_PASSWORD","nickname":"","trade_ea_symbol":""}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/private-servers/SERVER_ID/accounts", json={ "platform": "mt5", "server": "Tickwire-Sandbox", "login": 1, "password": "YOUR_PASSWORD", "nickname": "", "trade_ea_symbol": "", }, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/private-servers/SERVER_ID/accounts", { body: { "platform": "mt5", "server": "Tickwire-Sandbox", "login": 1, "password": "YOUR_PASSWORD", "nickname": "", "trade_ea_symbol": "" }, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /v1/private-servers/{server_id}/accounts/{account_id} **Remove Server Account** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `server_id` | path | `string` | yes | | | `account_id` | path | `string` | yes | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/private-servers/SERVER_ID/accounts/YOUR_ACCOUNT_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/private-servers/SERVER_ID/accounts/YOUR_ACCOUNT_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/private-servers/SERVER_ID/accounts/YOUR_ACCOUNT_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Dedicated IPs and billing (Native /v1) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/billing/ ### GET /v1/billing **Billing** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/billing' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/billing", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/billing"); console.log(result); tw.close(); ``` ### POST /v1/billing/upgrade **Upgrade** · takes `Idempotency-Key` Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | Optional; replays the first answer | | `X-Actor` | header | `string \| null` | no | Who is acting (audit log) | | `X-Reason` | header | `string \| null` | no | Why (audit log; percent-encode non-ASCII) | Request body: `UpgradeBody` (required) | Field | Type | Required | Description | |---|---|---|---| | `accounts` | `integer` | yes | | | `own_address` | `boolean` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/billing/upgrade' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"accounts":1,"own_address":false}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/billing/upgrade", json={"accounts": 1, "own_address": False}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/billing/upgrade", { body: {"accounts":1,"own_address":false}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/billing/upgrade/quote **Upgrade Quote** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `accounts` | query | `integer` | yes | | | `own_address` | query | `boolean` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/billing/upgrade/quote?accounts=1' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/billing/upgrade/quote", params={"accounts": 1}, ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/billing/upgrade/quote", { params: {"accounts":1}, }); console.log(result); tw.close(); ``` ### GET /v1/dedicated-ips **My Dedicated Ips** Auth: `X-API-Key` Your dedicated IPs and open requests: `{ips, open_requests}`. Each IP gives its `region` code and a readable `region_name`. If the list can't be read right now the answer is `503 temporarily_unavailable` with `Retry-After`. Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/dedicated-ips' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/dedicated-ips", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/dedicated-ips"); console.log(result); tw.close(); ``` ### POST /v1/dedicated-ips/move-accounts **My Move Accounts** · takes `Idempotency-Key` Auth: `X-API-Key` Approve moving these accounts onto your dedicated IP. Each move **restarts the account's terminal**, so do it when no trade is in flight. Each result says whether the account moved and, if not, why. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `MoveAccounts` (required) | Field | Type | Required | Description | |---|---|---|---| | `account_ids` | `string[]` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/dedicated-ips/move-accounts' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"account_ids":["string"]}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/dedicated-ips/move-accounts", json={"account_ids": ["string"]}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/dedicated-ips/move-accounts", { body: {"account_ids":["string"]}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/subscription **Subscription** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/subscription' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/subscription", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/subscription"); console.log(result); tw.close(); ``` ### GET /v1/wallet **Wallet** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/wallet' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/wallet", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/wallet"); console.log(result); tw.close(); ``` ### GET /v1/wallet/assets **Wallet Assets** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/wallet/assets' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/wallet/assets", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/wallet/assets"); console.log(result); tw.close(); ``` ### POST /v1/wallet/topup **Create Topup** · takes `Idempotency-Key` Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | Request body: `CreateTopup` (required) | Field | Type | Required | Description | |---|---|---|---| | `amount_eur_cents` | `integer` | yes | | | `method` | `"crypto" \| "manual"` | no | | Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/wallet/topup' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'Content-Type: application/json' \ -d '{"amount_eur_cents":1000,"method":"crypto"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/wallet/topup", json={"amount_eur_cents": 1000, "method": "crypto"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/wallet/topup", { body: {"amount_eur_cents":1000,"method":"crypto"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/wallet/topup/{topup_id} **Get Topup** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `topup_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/wallet/topup/TOPUP_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/wallet/topup/TOPUP_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/wallet/topup/TOPUP_ID"); console.log(result); tw.close(); ``` ### POST /v1/wallet/topup/{topup_id}/confirm **Confirm Topup** Auth: `X-API-Key` | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `topup_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/wallet/topup/TOPUP_ID/confirm' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/wallet/topup/TOPUP_ID/confirm", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/wallet/topup/TOPUP_ID/confirm", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/wallet/topups **List Topups** Auth: `X-API-Key` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/wallet/topups' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/wallet/topups", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/wallet/topups"); console.log(result); tw.close(); ``` --- # Identity and other routes (Native /v1) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/native-other/ ### GET /v1/api-version **Get Api Version** Auth: `X-API-Key` The organisation's pinned API version, the latest one and every supported one. Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/api-version' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/api-version", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/api-version"); console.log(result); tw.close(); ``` ### POST /v1/api-version **Set Api Version** · takes `Idempotency-Key` Auth: `X-API-Key` Pin the organisation to `apiVersion` (owner or admin credential; audited). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `PinBody` (required) | Field | Type | Required | Description | |---|---|---|---| | `apiVersion` | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/api-version' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"apiVersion":"string"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/api-version", json={"apiVersion": "string"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/api-version", { body: {"apiVersion":"string"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/meta/whoami **Whoami** Auth: `X-API-Key` Responses: - `200` Successful Response (`object`) - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/meta/whoami' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/meta/whoami", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/meta/whoami"); console.log(result); tw.close(); ``` ### GET /v1/request-logs **List Request Logs** Auth: `X-API-Key` The organisation's request log, newest first (metadata only). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `status` | query | `string \| null` | no | | | `method` | query | `string \| null` | no | | | `route` | query | `string \| null` | no | | | `errorCode` | query | `string \| null` | no | | | `keyId` | query | `string \| null` | no | | | `accountId` | query | `string \| null` | no | | | `requestId` | query | `string \| null` | no | | | `since` | query | `string \| null` | no | | | `until` | query | `string \| null` | no | | | `cursor` | query | `string \| null` | no | | | `limit` | query | `integer` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/request-logs' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/request-logs", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/request-logs"); console.log(result); tw.close(); ``` ### GET /v1/request-logs/summary **Request Log Summary** Auth: `X-API-Key` Totals, error rate and the top error codes and routes over the last `hours`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hours` | query | `integer` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/request-logs/summary' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/request-logs/summary", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/request-logs/summary"); console.log(result); tw.close(); ``` ### GET /v1/request-logs/{log_id} **Get Request Log** Auth: `X-API-Key` One call; body excerpts only for a full-access key with the writer role. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `log_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/request-logs/LOG_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/request-logs/LOG_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/request-logs/LOG_ID"); console.log(result); tw.close(); ``` --- # Agent API (AI agents) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/agent-api/ ### GET /v1/agent/accounts **Agent Accounts** Auth: `X-Tickwire-Agent-Key` Accounts this key may use, by account id. Cursor-paginated: `{accounts, has_more, next_cursor}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `limit` | query | `integer` | no | Page size, 1..500 (default 100). | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/account-information **Agent Account Info** Auth: `X-Tickwire-Agent-Key` Balance, equity, margin… as reported by the broker (same shape as `/users/current/…`). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/account-information' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/account-information", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/account-information"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/health **Agent Health** Auth: `X-Tickwire-Agent-Key` Truthful health with evidence (connected / disconnected / unknown). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/health' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/health", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/health"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/history-deals **Agent Deals** Auth: `X-Tickwire-Agent-Key` Deals in a bounded window (default last 24 h, max 31 days). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `start_time` | query | `string \| null` | no | | | `end_time` | query | `string \| null` | no | | | `limit` | query | `integer` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/history-deals' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/history-deals", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/history-deals"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/orders **Agent Orders** Auth: `X-Tickwire-Agent-Key` Pending orders (same shape as `/users/current/accounts/{id}/orders`). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/orders' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/orders", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/orders"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/positions **Agent Positions** Auth: `X-Tickwire-Agent-Key` Open positions (same shape as `/users/current/accounts/{id}/positions`). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/positions' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/positions", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/positions"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/snapshot **Agent Snapshot** Auth: `X-Tickwire-Agent-Key` Account information, positions, orders, health and server time in one read, with `as_of` and per-section freshness. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/snapshot' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/snapshot", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/snapshot"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/symbols/{symbol}/current-price **Agent Price** Auth: `X-Tickwire-Agent-Key` Current bid/ask with broker time. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-price' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-price", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/current-price"); console.log(result); agent.close(); ``` ### GET /v1/agent/accounts/{account_id}/symbols/{symbol}/specification **Agent Spec** Auth: `X-Tickwire-Agent-Key` Symbol specification: volume limits and step, digits, contract size… | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `symbol` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/specification' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/specification", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/accounts/YOUR_ACCOUNT_ID/symbols/EURUSD/specification"); console.log(result); agent.close(); ``` ### POST /v1/agent/accounts/{account_id}/trade **Agent Trade** · takes `Idempotency-Key` Auth: `X-Tickwire-Agent-Key` Place, modify, close or cancel a trade. Each trade is checked against the key's limits, the pre-trade hooks and the kill switches before it is sent, and is recorded in the audit trail. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `any` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/agent/accounts/YOUR_ACCOUNT_ID/trade' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "POST", "/v1/agent/accounts/YOUR_ACCOUNT_ID/trade", json={"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.01}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("POST", "/v1/agent/accounts/YOUR_ACCOUNT_ID/trade", { body: {"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); agent.close(); ``` ### GET /v1/agent/audit **Agent Own Audit** Auth: `X-Tickwire-Agent-Key` This key's own audit entries, newest first. Cursor-paginated: `{entries, has_more, next_cursor}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `limit` | query | `integer` | no | Page size, 1..500 (default 50). | | `before` | query | `integer \| null` | no | | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/audit' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/audit", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/audit"); console.log(result); agent.close(); ``` ### GET /v1/agent/me **Agent Me** Auth: `X-Tickwire-Agent-Key` This key's permissions, kill switches and applicable hooks. Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/me' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/me", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/me"); console.log(result); agent.close(); ``` ### GET /v1/agent/requests/{idempotency_key} **Agent Request Status** Auth: `X-Tickwire-Agent-Key` What happened to the trade sent with this idempotency key. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `idempotency_key` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `401` [`invalid_agent_key`](https://tickwire.io/docs/errors/invalid_agent_key/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent/requests/IDEMPOTENCY_KEY' \ -H 'X-Tickwire-Agent-Key: YOUR_AGENT_KEY' ``` Python: ```python from tickwire import AgentClient with AgentClient("https://api.tickwire.io", "YOUR_AGENT_KEY") as agent: result = agent.request( "GET", "/v1/agent/requests/IDEMPOTENCY_KEY", ) print(result) ``` TypeScript: ```typescript import { AgentClient } from "@tickwire/sdk"; const agent = new AgentClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_AGENT_KEY" }); const result = await agent.request("GET", "/v1/agent/requests/IDEMPOTENCY_KEY"); console.log(result); agent.close(); ``` --- # Agent keys and kill switches (AI agents) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/agent-admin/ ### GET /v1/agent-audit **Agent Audit** Auth: `X-API-Key` The agent audit log, newest first (by `seq`). Cursor-paginated: `{entries, has_more, next_cursor}`; `before` (a `seq`) still works. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `agent_key_id` | query | `string \| null` | no | | | `account_id` | query | `string \| null` | no | | | `before` | query | `integer \| null` | no | | | `limit` | query | `integer` | no | Page size, 1..500 (default 100). | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent-audit' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/agent-audit", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/agent-audit"); console.log(result); tw.close(); ``` ### GET /v1/agent-keys **List Agent Keys** Auth: `X-API-Key` Agent keys of this tenant (never the key values), oldest first. Cursor-paginated: `{data, has_more, next_cursor}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `limit` | query | `integer` | no | Page size, 1..500 (default 100). | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent-keys' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/agent-keys", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/agent-keys"); console.log(result); tw.close(); ``` ### POST /v1/agent-keys **Create Agent Key** · takes `Idempotency-Key` Auth: `X-API-Key` Create an agent key scoped to accounts. The `key` is shown once. `Idempotency-Key` is honoured: a replay returns the same key record without minting another key, with `key: null` and a `key_notice` saying it was already shown. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/agent-keys' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"name":"my-agent","account_ids":["YOUR_ACCOUNT_ID"],"read_only":false}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/agent-keys", json={ "name": "my-agent", "account_ids": ["YOUR_ACCOUNT_ID"], "read_only": False, }, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/agent-keys", { body: {"name":"my-agent","account_ids":["YOUR_ACCOUNT_ID"],"read_only":false}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/agent-keys/{key_id} **Get Agent Key** Auth: `X-API-Key` One agent key record. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent-keys/KEY_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/agent-keys/KEY_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/agent-keys/KEY_ID"); console.log(result); tw.close(); ``` ### PATCH /v1/agent-keys/{key_id} **Patch Agent Key** Auth: `X-API-Key` Rename, re-scope or flip read-only. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X PATCH 'https://api.tickwire.io/v1/agent-keys/KEY_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"name":"my-agent"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PATCH", "/v1/agent-keys/KEY_ID", json={"name": "my-agent"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PATCH", "/v1/agent-keys/KEY_ID", { body: {"name":"my-agent"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /v1/agent-keys/{key_id} **Revoke Agent Key** Auth: `X-API-Key` Revoke an agent key (irreversible). | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/agent-keys/KEY_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/agent-keys/KEY_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/agent-keys/KEY_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### PUT /v1/agent-keys/{key_id}/kill-switch **Set Key Kill Switch** Auth: `X-API-Key` Engage or release the kill switch of one agent key. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X PUT 'https://api.tickwire.io/v1/agent-keys/KEY_ID/kill-switch' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"engaged":true,"reason":"stop this agent"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PUT", "/v1/agent-keys/KEY_ID/kill-switch", json={"engaged": True, "reason": "stop this agent"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PUT", "/v1/agent-keys/KEY_ID/kill-switch", { body: {"engaged":true,"reason":"stop this agent"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/agent-kill-switches **List Kill Switches** Auth: `X-API-Key` Engaged account kill switches (agent-key switches are on each key), by account id. Cursor-paginated: `{accounts, has_more, next_cursor}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `limit` | query | `integer` | no | Page size, 1..500 (default 100). | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/agent-kill-switches' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/agent-kill-switches", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/agent-kill-switches"); console.log(result); tw.close(); ``` ### PUT /v1/agent-kill-switches/accounts/{account_id} **Set Account Kill Switch** Auth: `X-API-Key` Engage or release the agent kill switch of one account. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) curl: ```bash curl -sS -X PUT 'https://api.tickwire.io/v1/agent-kill-switches/accounts/YOUR_ACCOUNT_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"engaged":true,"reason":"stop all agents"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PUT", "/v1/agent-kill-switches/accounts/YOUR_ACCOUNT_ID", json={"engaged": True, "reason": "stop all agents"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PUT", "/v1/agent-kill-switches/accounts/YOUR_ACCOUNT_ID", { body: {"engaged":true,"reason":"stop all agents"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Pre-trade hooks and holds (AI agents) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/pretrade/ ### GET /v1/pretrade-holds **List Holds** Auth: `X-API-Key` Holds, newest first (`created_at`, then `id`). Cursor-paginated: `{data, has_more, next_cursor}`; the cursor is bound to `status` and `account_id`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `status` | query | `string \| null` | no | | | `account_id` | query | `string \| null` | no | | | `limit` | query | `integer` | no | Page size, 1..500 (default 100). | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/pretrade-holds' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/pretrade-holds", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/pretrade-holds"); console.log(result); tw.close(); ``` ### GET /v1/pretrade-holds/{hold_id} **Get Hold** Auth: `X-API-Key` One hold. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hold_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/pretrade-holds/HOLD_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/pretrade-holds/HOLD_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/pretrade-holds/HOLD_ID"); console.log(result); tw.close(); ``` ### POST /v1/pretrade-holds/{hold_id}/cancel **Cancel Hold** Auth: `X-API-Key` Owner override: reject a pending hold. Nothing is sent. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hold_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/pretrade-holds/HOLD_ID/cancel' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/pretrade-holds/HOLD_ID/cancel", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/pretrade-holds/HOLD_ID/cancel", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/pretrade-holds/{hold_id}/release **Release Hold** Auth: `X-API-Key` Approve or reject a hold; signed with the holding hook's secret. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hold_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/pretrade-holds/HOLD_ID/release' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/pretrade-holds/HOLD_ID/release", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/pretrade-holds/HOLD_ID/release", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/pretrade-hooks **List Hooks** Auth: `X-API-Key` This tenant's hooks (never the secrets), oldest first. Cursor-paginated: `{data, has_more, next_cursor}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `limit` | query | `integer` | no | Page size, 1..500 (default 100). | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/pretrade-hooks' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/pretrade-hooks", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/pretrade-hooks"); console.log(result); tw.close(); ``` ### POST /v1/pretrade-hooks **Create Hook** · takes `Idempotency-Key` Auth: `X-API-Key` Register a pre-trade decision hook. The `secret` is shown once. `Idempotency-Key` is honoured: a replay returns the same hook without registering another, with `secret: null` and a `secret_notice`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `201` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/pretrade-hooks' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"url":"https://example.com/pretrade","account_id":"YOUR_ACCOUNT_ID"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/pretrade-hooks", json={ "url": "https://example.com/pretrade", "account_id": "YOUR_ACCOUNT_ID", }, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/pretrade-hooks", { body: {"url":"https://example.com/pretrade","account_id":"YOUR_ACCOUNT_ID"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/pretrade-hooks/{hook_id} **Get Hook** Auth: `X-API-Key` One hook. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hook_id` | path | `string` | yes | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/pretrade-hooks/HOOK_ID' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/pretrade-hooks/HOOK_ID", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/pretrade-hooks/HOOK_ID"); console.log(result); tw.close(); ``` ### PATCH /v1/pretrade-hooks/{hook_id} **Patch Hook** Auth: `X-API-Key` Change url, applies_to, fail_mode, timeout, hold TTL or enabled. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hook_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X PATCH 'https://api.tickwire.io/v1/pretrade-hooks/HOOK_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"url":"https://example.com/pretrade"}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "PATCH", "/v1/pretrade-hooks/HOOK_ID", json={"url": "https://example.com/pretrade"}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("PATCH", "/v1/pretrade-hooks/HOOK_ID", { body: {"url":"https://example.com/pretrade"}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### DELETE /v1/pretrade-hooks/{hook_id} **Delete Hook** Auth: `X-API-Key` Remove a hook. Its pending holds stay pending until they expire. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hook_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `204` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/pretrade-hooks/HOOK_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/pretrade-hooks/HOOK_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/pretrade-hooks/HOOK_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /v1/pretrade-hooks/{hook_id}/rotate-secret **Rotate Hook Secret** · takes `Idempotency-Key` Auth: `X-API-Key` Issue a new signing secret (shown once); the old one stops working. With `Idempotency-Key` a replay rotates nothing and answers `secret: null` with a `secret_notice`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `hook_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/pretrade-hooks/HOOK_ID/rotate-secret' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/pretrade-hooks/HOOK_ID/rotate-secret", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/pretrade-hooks/HOOK_ID/rotate-secret", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Sign in with Tickwire (OAuth) and connected apps (AI agents) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/oauth/ ### GET /.well-known/oauth-authorization-server **As Metadata** Auth: `X-API-Key` RFC 8414 Authorization Server Metadata. Responses: - `200` Successful Response Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/.well-known/oauth-authorization-server' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/.well-known/oauth-authorization-server", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/.well-known/oauth-authorization-server"); console.log(result); tw.close(); ``` ### GET /oauth/authorize **Authorize** Auth: `X-API-Key` Validate the request, then send the browser to the consent page. Responses: - `200` Successful Response Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/oauth/authorize' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/oauth/authorize", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/oauth/authorize"); console.log(result); tw.close(); ``` ### POST /oauth/consent/decide **Consent Decide** Auth: `X-API-Key` Approve or deny; answers where to send the browser next. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `X-Reason` | header | `string \| null` | no | | | `X-Tickwire-CSRF` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/oauth/consent/decide' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/oauth/consent/decide", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/oauth/consent/decide", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /oauth/consent/view **Consent View** Auth: `X-API-Key` What the consent page shows, plus a consent token bound to this session. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `X-Tickwire-CSRF` | header | `string \| null` | no | | Request body: `object` (required) Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/oauth/consent/view' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/oauth/consent/view", json={}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/oauth/consent/view", { body: {}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /oauth/register **Register** Auth: `X-API-Key` RFC 7591 Dynamic Client Registration. Responses: - `201` Successful Response Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/oauth/register' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/oauth/register", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/oauth/register", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /oauth/revoke **Revoke** Auth: `X-API-Key` RFC 7009 token revocation. Responses: - `200` Successful Response Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/oauth/revoke' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/oauth/revoke", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/oauth/revoke", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### POST /oauth/token **Token** Auth: `X-API-Key` Exchange an authorization code or a refresh token for tokens. Never retry a refresh token that was refused: start a new sign-in instead. Responses: - `200` Successful Response Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/oauth/token' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/oauth/token", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/oauth/token", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` ### GET /v1/connected-apps **List Apps** Auth: `X-API-Key` Apps connected to this tenant through Sign in with Tickwire, oldest first. Cursor-paginated: `{apps, has_more, next_cursor}`. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `include_ended` | query | `boolean` | no | | | `limit` | query | `integer` | no | Page size, 1..500 (default 100). | | `cursor` | query | `string \| null` | no | The next_cursor of the previous page, unchanged. | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X GET 'https://api.tickwire.io/v1/connected-apps' \ -H 'X-API-Key: YOUR_API_KEY' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "GET", "/v1/connected-apps", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("GET", "/v1/connected-apps"); console.log(result); tw.close(); ``` ### DELETE /v1/connected-apps/{grant_id} **Disconnect App** Auth: `X-API-Key` Disconnect: revoke the app's agent key and all of its tokens. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `grant_id` | path | `string` | yes | | | `X-Actor` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) curl: ```bash curl -sS -X DELETE 'https://api.tickwire.io/v1/connected-apps/GRANT_ID' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'X-Reason: why you are doing this' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "DELETE", "/v1/connected-apps/GRANT_ID", idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("DELETE", "/v1/connected-apps/GRANT_ID", { idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Guarded trades (Guarded execution) > Tickwire API reference, generated from the OpenAPI document the services export. Base URL: https://api.tickwire.io. Replace YOUR_API_KEY and YOUR_ACCOUNT_ID with your own values; use a sandbox key (twsk_…) to experiment. Source: https://tickwire.io/docs/reference/execution/ ### POST /v1/execution/accounts/{account_id}/trade **Guarded Trade** · takes `Idempotency-Key` Auth: `X-API-Key` Trade with an ordinary API key under the same checks agent keys get: pre-trade hooks with `applies_to: all`, kill switches and the audit trail. Same body and answers as the agent trade route. | Parameter | In | Type | Required | Description | |---|---|---|---|---| | `account_id` | path | `string` | yes | | | `Idempotency-Key` | header | `string \| null` | no | | | `X-Reason` | header | `string \| null` | no | | Request body: `any` Responses: - `200` Successful Response - `422` Validation Error (`HTTPValidationError`) Common errors: - `401` [`unauthorized`](https://tickwire.io/docs/errors/unauthorized/) - `429` [`rate_limited`](https://tickwire.io/docs/errors/rate_limited/) - `400, 422` [`validation_error`](https://tickwire.io/docs/errors/validation_error/) - `404` [`account_not_found`](https://tickwire.io/docs/errors/account_not_found/) - `409` [`idempotency_conflict`](https://tickwire.io/docs/errors/idempotency_conflict/) - `500, 502` [`backend_error`](https://tickwire.io/docs/errors/backend_error/) - `403` [`kill_switch_engaged`](https://tickwire.io/docs/errors/kill_switch_engaged/) curl: ```bash curl -sS -X POST 'https://api.tickwire.io/v1/execution/accounts/YOUR_ACCOUNT_ID/trade' \ -H 'X-API-Key: YOUR_API_KEY' \ -H 'Idempotency-Key: my-request-1' \ -H 'X-Reason: why you are doing this' \ -H 'Content-Type: application/json' \ -d '{"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}' ``` Python: ```python from tickwire import Tickwire with Tickwire("https://api.tickwire.io", "YOUR_API_KEY") as tw: result = tw.request( "POST", "/v1/execution/accounts/YOUR_ACCOUNT_ID/trade", json={"actionType": "ORDER_TYPE_BUY", "symbol": "EURUSD", "volume": 0.01}, idempotency_key="my-request-1", reason="why you are doing this", ) print(result) ``` TypeScript: ```typescript import { TickwireClient } from "@tickwire/sdk"; const tw = new TickwireClient({ baseUrl: "https://api.tickwire.io", token: "YOUR_API_KEY" }); const result = await tw.request("POST", "/v1/execution/accounts/YOUR_ACCOUNT_ID/trade", { body: {"actionType":"ORDER_TYPE_BUY","symbol":"EURUSD","volume":0.01}, idempotencyKey: "my-request-1", reason: "why you are doing this", }); console.log(result); tw.close(); ``` --- # Models > Every schema in the Tickwire OpenAPI document. ## AccountFeatures | Field | Type | Required | Description | |---|---|---|---| | `copyFactoryApi` | `CopyTradingEnable \| null` | no | | | `riskManagementApiEnabled` | `boolean \| null` | no | | | `metastatsApiEnabled` | `boolean \| null` | no | | | `reliabilityIncreased` | `boolean \| null` | no | | | `allocateDedicatedIp` | `"ipv4" \| "none" \| null` | no | | ## CopyTradingEnable | Field | Type | Required | Description | |---|---|---|---| | `copyFactoryRoles` | `"PROVIDER" \| "SUBSCRIBER"[]` | yes | | | `copyFactoryResourceSlots` | `integer \| null` | no | | ## CreateAccount | Field | Type | Required | Description | |---|---|---|---| | `platform` | `"mt4" \| "mt5"` | no | | | `server` | `string` | yes | | | `login` | `integer` | yes | | | `password` | `string` | yes | | | `nickname` | `string` | no | | | `trade_ea_symbol` | `string` | no | | | `proxy_address` | `string` | no | | | `proxy_type` | `string` | no | | | `proxy_auth` | `string` | no | | | `proxy_local_port` | `integer` | no | | ## CreatePrivateServer | Field | Type | Required | Description | |---|---|---|---| | `slots` | `integer` | yes | | | `region` | `string` | yes | | | `name` | `string` | yes | | ## CreateReadonlyKey | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | yes | | | `scope` | `"all" \| "selected"` | no | | | `account_ids` | `string[]` | no | | ## CreateTopup | Field | Type | Required | Description | |---|---|---|---| | `amount_eur_cents` | `integer` | yes | | | `method` | `"crypto" \| "manual"` | no | | ## CreateWebhook | Field | Type | Required | Description | |---|---|---|---| | `url` | `string` | yes | | | `secret` | `string \| null` | no | | ## Credentials | Field | Type | Required | Description | |---|---|---|---| | `login` | `string \| integer \| null` | no | | | `password` | `string` | yes | | ## HTTPValidationError | Field | Type | Required | Description | |---|---|---|---| | `detail` | `ValidationError[]` | no | | ## KeyBody | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | no | | ## MoveAccounts | Field | Type | Required | Description | |---|---|---|---| | `account_ids` | `string[]` | yes | | ## NewProfile | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | yes | | | `version` | `4 \| 5` | yes | | | `brokerTimezone` | `string` | yes | | | `brokerDSTSwitchTimezone` | `string` | yes | | | `type` | `"mtTerminal" \| "managerApi"` | no | | | `managerLogin` | `string \| null` | no | | | `managerPassword` | `string \| null` | no | | | `managerServer` | `string \| null` | no | | ## NewToken | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | no | | | `kind` | `"api" \| "account"` | no | | | `applications` | `string[] \| null` | no | | | `roles` | `string[] \| null` | no | | | `accountIds` | `string[] \| null` | no | | | `readOnly` | `boolean` | no | | | `ttlInHours` | `number \| null` | no | | | `ipAllowlist` | `string[] \| null` | no | | ## NewTradingAccount | Field | Type | Required | Description | |---|---|---|---| | `name` | `string` | yes | | | `server` | `string` | yes | | | `login` | `string \| integer \| null` | no | | | `password` | `string \| null` | no | | | `platform` | `"mt4" \| "mt5" \| null` | no | | | `provisioningProfileId` | `string \| null` | no | | | `magic` | `integer` | no | | | `manualTrades` | `boolean` | no | | | `slippage` | `number \| null` | no | | | `quoteStreamingIntervalInSeconds` | `number` | no | | | `tags` | `string[]` | no | | | `metadata` | `object \| null` | no | | | `reliability` | `"regular" \| "high"` | no | | | `resourceSlots` | `integer` | no | | | `copyFactoryResourceSlots` | `integer` | no | | | `region` | `string \| null` | no | | | `type` | `"cloud" \| "cloud-g1" \| "cloud-g2"` | no | | | `symbol` | `string \| null` | no | | | `baseCurrency` | `string \| null` | no | | | `copyFactoryRoles` | `"PROVIDER" \| "SUBSCRIBER"[]` | no | | | `riskManagementApiEnabled` | `boolean` | no | | | `metastatsApiEnabled` | `boolean` | no | | | `allocateDedicatedIp` | `"ipv4" \| "none" \| null` | no | | | `keywords` | `string[]` | no | | | `serverAddress` | `string \| null` | no | | ## PatchAccount | Field | Type | Required | Description | |---|---|---|---| | `trade_ea_symbol` | `string \| null` | no | | ## PatchEndpoint | Field | Type | Required | Description | |---|---|---|---| | `enabledEvents` | `string[] \| null` | no | | | `url` | `string \| null` | no | | | `description` | `string \| null` | no | | ## PatchPrivateServer | Field | Type | Required | Description | |---|---|---|---| | `slots` | `integer` | yes | | ## PatchReadonlyKey | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `scope` | `"all" \| "selected" \| null` | no | | | `account_ids` | `string[] \| null` | no | | ## PatchToken | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `ipAllowlist` | `string[] \| null` | no | | ## PinBody | Field | Type | Required | Description | |---|---|---|---| | `apiVersion` | `string` | yes | | ## PrivateServerAddAccount | Field | Type | Required | Description | |---|---|---|---| | `platform` | `"mt4" \| "mt5"` | no | | | `server` | `string` | yes | | | `login` | `integer` | yes | | | `password` | `string` | yes | | | `nickname` | `string` | no | | | `trade_ea_symbol` | `string` | no | | ## RotateSecret | Field | Type | Required | Description | |---|---|---|---| | `secret` | `string \| null` | no | | | `overlapHours` | `number` | no | | ## SandboxSignupBody | Field | Type | Required | Description | |---|---|---|---| | `platform` | `"mt4" \| "mt5"` | no | | ## TriggerBody | Field | Type | Required | Description | |---|---|---|---| | `type` | `string` | yes | | | `accountId` | `string \| null` | no | | ## UpdateProfile | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `brokerTimezone` | `string \| null` | no | | | `brokerDSTSwitchTimezone` | `string \| null` | no | | | `managerLogin` | `string \| null` | no | | | `managerPassword` | `string \| null` | no | | | `managerServer` | `string \| null` | no | | ## UpdateTradingAccount | Field | Type | Required | Description | |---|---|---|---| | `name` | `string \| null` | no | | | `password` | `string \| null` | no | | | `server` | `string \| null` | no | | | `magic` | `integer \| null` | no | | | `manualTrades` | `boolean \| null` | no | | | `slippage` | `number \| null` | no | | | `quoteStreamingIntervalInSeconds` | `number \| null` | no | | | `tags` | `string[] \| null` | no | | | `metadata` | `object \| null` | no | | | `copyFactoryRoles` | `"PROVIDER" \| "SUBSCRIBER"[] \| null` | no | | | `resourceSlots` | `integer \| null` | no | | | `copyFactoryResourceSlots` | `integer \| null` | no | | | `metastatsApiEnabled` | `boolean \| null` | no | | | `allocateDedicatedIp` | `"ipv4" \| "none" \| null` | no | | | `serverAddress` | `string \| null` | no | | ## UpgradeBody | Field | Type | Required | Description | |---|---|---|---| | `accounts` | `integer` | yes | | | `own_address` | `boolean` | no | | ## ValidationError | Field | Type | Required | Description | |---|---|---|---| | `loc` | `string \| integer[]` | yes | | | `msg` | `string` | yes | | | `type` | `string` | yes | | | `input` | `any` | no | | | `ctx` | `object` | no | |