WireMT API
Quick start
1. Sign up on WireMT and copy your API key (wmt_live_...). 2. Connect an account. 3. Trade.
curl -X POST $BASE/v1/connect \
-H "x-api-key: wmt_live_YOUR_KEY" -H "content-type: application/json" \
-d '{"login":"12345678","password":"MT5_PASSWORD","server":"Exness-MT5Trial"}'
# -> {"id":"acc_...","status":"connected"}
curl -X POST $BASE/v1/trade \
-H "x-api-key: wmt_live_YOUR_KEY" -H "content-type: application/json" \
-d '{"id":"acc_...","symbol":"XAUUSD","side":"buy","volume":0.01,"sl":0,"tp":0}'
. Use the trading password of the MT5 account, not the investor (read-only) password.Authentication
| Header | Use |
|---|---|
x-api-key: wmt_live_... | Your own key. Works on your own accounts. Keep it on your server, never in browser code. |
x-student-uuid: stu_... | A student's ID. Works on that student's accounts while their access is paid. See Student UUID. |
Send JSON bodies with content-type: application/json. Every call that acts on an account takes the account id returned by /v1/connect (in the body for POST, in the query for GET).
Connect an MT5 account
POST/v1/connect
| Field | |
|---|---|
login | MT5 account number |
password | Trading password |
server | Broker server name, e.g. Exness-MT5Real8 |
Returns {"id","sessionId","status":"connected"}. Connecting the same login and server again is fine and returns a working id. Starter accounts are locked to one MT5 account; Pro and Enterprise can disconnect (the account's UUID is deleted for good) and reconnect (a new UUID). A new login beyond your plan's account limit returns 403 ACCOUNT_LIMIT with limit and used.
Status
GET/v1/status?id=acc_...
Returns {"id","status":"connected"|"disconnected","login","server","account":{...}}. A dropped session is reconnected automatically when you call it.
Account info
GET/v1/account?id=acc_...
{"login":12345678,"name":"...","server":"...","currency":"USD","leverage":500,
"balance":1000.0,"equity":1004.2,"margin":12.5,"free_margin":991.7,"profit":4.2,"trade_allowed":true}
Disconnect
POST/v1/disconnect?id=acc_... removes the session. It does not close trades.
Open a trade
POST/v1/trade (market orders)
| Field | |
|---|---|
id | Account id |
symbol | e.g. XAUUSD. Broker suffixes like m or .r are found for you. |
side | buy or sell |
volume | Lots, e.g. 0.01 |
sl, tp | Price levels. 0 or leave out for none. |
comment | Optional text on the trade |
count | Optional. Open this many identical positions in one call (1 to 20). |
Single trade reply: {"ticket","symbol","side","volume","price","sl","tp","retcode","comment"}.
With count the reply is a summary. It counts as one request for rate limits.
{"requested":3,"opened":3,"failed":0,
"results":[{"n":1,"ok":true,"status":200,"result":{...}}, ...]}
HTTP 200 if at least one opened. If none opened you get the first failure's status. A bad count returns 400 COUNT_INVALID.
Open positions
GET/v1/positions?id=acc_...
[{"ticket":100001,"symbol":"XAUUSD","side":"BUY","volume":0.01,"priceOpen":2654.38,"sl":0,"tp":0,"profit":1.2,"comment":""}]
Modify SL / TP
POST/v1/modify body {"id","ticket","sl","tp"}. Returns the updated position.
Close one position
POST/v1/close body {"id","ticket","volume"}. Leave out volume to close it all, or send a smaller volume for a partial close.
Close all
POST/v1/close-all body {"id"} closes every open position. Add "symbol":"XAUUSD" to close only that symbol. Returns {"id","closed":N}.
Order history
GET/v1/history?id=acc_...&days=7&symbol=XAUUSD&limit=200
days 1 to 90 (default 7). symbol and limit (1 to 1000, default 200) are optional. Newest first. Deposits and balance lines are left out.
{"count":2,"returned":2,
"summary":{"net_profit":4.9,"wins":1,"losses":1,"win_rate":50.0},
"trades":[{"ticket":12,"symbol":"EURUSD","side":"SELL","volume":0.1,"openPrice":1.0845,"closePrice":1.0850,
"openTime":"2026-11-05T09:00:00","closeTime":"2026-11-05T11:00:00",
"profit":-5.0,"swap":0.0,"commission":0.0,"comment":""}]}
Net profit is profit + swap + commission. Times are broker server time.
Candles
GET/v1/candles?id=acc_...&symbol=XAUUSD&timeframe=M5&count=20
Returns {"symbol","timeframe","bars":[{"time","open","high","low","close","volume"}]}.
Last trade result
GET/v1/last-trade?id=acc_...&symbol=XAUUSD returns {"hasHistory","won","profit"} for the most recent closed trade on that symbol in the last 7 days.
Live stream (WebSocket)
Instead of asking again and again, open one socket and get account and position changes as they happen.
const ws = new WebSocket("wss://YOUR-HOST/v1/stream?id=acc_...");
ws.onmessage = (e) => {
const m = JSON.parse(e.data);
if (m.type === "update") console.log(m.account.equity, m.positions);
};
Websites use their login cookie. Server code can send x-api-key or x-student-uuid headers. Messages: hello, update (account and positions, sent when something changes and at least every 10 seconds) and error (the socket stays open and keeps trying). Streams do not use up your request limit. You can have up to 10 open at once.
| Close code | |
|---|---|
| 4001 | Not logged in |
| 4002 | Account not found or not yours |
| 4003 | Too many open streams |
| 4004 | id missing |
| 4402 | Student access not paid |
If the socket drops, reconnect after a second or two. Keep your old polling as a fallback.
Batch operations (Pro)
Send up to 50 actions in one call. They run in order. One failing action does not stop the rest.
POST /v1/batch
{ "id": "acc_...",
"operations": [
{ "op": "trade", "symbol": "XAUUSD", "side": "buy", "volume": 0.01 },
{ "op": "modify", "ticket": 100001, "sl": 2650 },
{ "op": "close", "ticket": 100002 } ] }
# -> { "requested": 3, "succeeded": 3, "failed": 0, "results": [ {n, op, ok, status, result|error} ] }
Each operation may carry its own id to act on a different account. Starter accounts get 403 PLAN_REQUIRED.
Webhooks (Pro)
WireMT calls your server when something happens. Create them with POST /api/pro/webhooks ({"url":"https://...","events":["trade.opened","trade.closed"]}). The secret is shown once.
Events: trade.opened, trade.closed, trade.modified, account.connected, account.disconnected, or "*" for all. Each call is a JSON POST {id, event, created_at, data} with the header X-WireMT-Signature: t=<unix>,v1=<hex>, where v1 = HMAC-SHA256(secret, t + "." + raw_body). Check it and ignore calls where t is more than 5 minutes old.
Answer with any 2xx status. Failed calls are retried (now, +10 s, +60 s). After 20 failed deliveries in a row the webhook is switched off; switch it back on from your dashboard. URLs must be https and public.
Student UUID (for other platforms)
A trading platform can let its own users trade through WireMT without running anything. The user signs up on WireMT, pays, connects their MT5 account and gets a UUID (stu_...) for that account. They paste it into your platform. Your server sends it in the x-student-uuid header.
One UUID = one MT5 account. A UUID only works on its own account. The account id is filled in for you, so id can be left out. If you send a different account id you get 403 UUID_ACCOUNT_MISMATCH. Pro and Enterprise users have one UUID per account. Starter users have one account and its UUID is permanent.
Send only the UUID to trade as that student. Add your developer key (x-api-key) to run in platform mode: calls are counted under your key and the student shows in your Students list.
| Call | |
|---|---|
GET /v1/whoami[?email=] | Is this UUID real, paid, and which account it is on (login and server). With ?email= you also get email_match (the email itself is never returned). No key needed. |
GET /v1/student/verify[?email=] | Same check, with your developer key. |
GET /v1/student/accounts | The account this UUID belongs to. |
POST /v1/connect | Test or refresh the connection. With a UUID, login and server must match the UUID's account (403 UUID_ACCOUNT_MISMATCH if not). This also checks the password. |
| all trading calls above | Work on that UUID's account. |
{"valid":true,"student_id":"stu_...","uuid_status":"active","plan":"starter","paid":true,"status":"active","paid_until":"2026-12-05T...","days_left":30,"account":{"login":"1234567","server":"Broker-Live","status":"linked"},"email_match":true}
status is active, expired or unpaid. Access is monthly and per person: if it runs out, every UUID of that person gets 402 NOT_PAID. uuid_status is active, dormant (account paused because the plan has fewer slots now; upgrading wakes it up with the same UUID) or unused (no account connected yet).
Platforms on the Enterprise plan can list their students (full email, masked MT5 login, plan, paid status, last used) in the dashboard or with GET /api/enterprise/students.
Errors
Errors are JSON: {"error":"text","code":"CODE"}. Always check the HTTP status first.
| HTTP | code | Meaning |
|---|---|---|
| 400 | COUNT_INVALID | count must be a whole number from 1 to 20 |
| 400 | NO_ACCOUNT, ACCOUNT_REQUIRED | This UUID has no connected account yet (call /v1/connect first), or you have more than one account (send id) |
| 400 | - | Broker refused (wrong password, market closed, bad volume...). The text says why. |
| 401 | - | Missing or wrong key / ID |
| 402 | NOT_PAID | Student access unpaid or expired |
| 403 | ACCOUNT_LIMIT | Plan account limit reached (limit, used in reply). Starter is 1 account |
| 403 | ACCOUNT_LOCKED | Starter accounts cannot be disconnected. Upgrade to Pro |
| 403 | UUID_LOCKED | Starter UUIDs are permanent and cannot be regenerated |
| 403 | UUID_ACCOUNT_MISMATCH | This UUID belongs to a different MT5 account |
| 403 | ACCOUNT_DORMANT | Account paused because the plan has fewer slots now. Upgrade to wake it up |
| 403 | PLAN_REQUIRED | Needs the Pro plan (batch, webhooks, developer keys) |
| 403 | EMAIL_NOT_VERIFIED | Confirm your email first |
| 403 | DEVELOPER_ONLY | A Student ID can only be combined with a developer key |
| 403 | - | That account is not yours |
| 404 | STUDENT_ID_UNKNOWN | No such UUID, or it was disconnected / regenerated and is dead |
| 429 | - | Too many requests. Wait the Retry-After seconds. |
| 501 | - | Not supported by the connection engine |
| 502 | - | WireMT could not reach its engine. Retry shortly. |
Limits and plans
| Plan | MT5 accounts | Requests per minute |
|---|---|---|
| Starter | 1 (locked) | 30 |
| Pro | 50 (+ R20 per extra, per 30 days) | 600 |
| Enterprise | unlimited | 3000, or your own custom limit |
Pro and Enterprise have no monthly request cap. The per-minute rate only protects the servers.
Live prices on the WireMT website itself use a separate, larger allowance and do not use up your API requests. Current prices: GET /api/plans.
Status page
Is WireMT up? /status for people, GET /api/status for code.
WireMT is a bridge to your broker. It does not give financial advice. Trading carries risk.