WireMT API

Connect MetaTrader 5 accounts and trade them over plain HTTPS. No MT5 software, no VPS, no Expert Advisor.

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}'
Base URL: . Use the trading password of the MT5 account, not the investor (read-only) password.

Authentication

HeaderUse
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
loginMT5 account number
passwordTrading password
serverBroker 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
idAccount id
symbole.g. XAUUSD. Broker suffixes like m or .r are found for you.
sidebuy or sell
volumeLots, e.g. 0.01
sl, tpPrice levels. 0 or leave out for none.
commentOptional text on the trade
countOptional. 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
4001Not logged in
4002Account not found or not yours
4003Too many open streams
4004id missing
4402Student 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/accountsThe account this UUID belongs to.
POST /v1/connectTest 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 aboveWork 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.

HTTPcodeMeaning
400COUNT_INVALIDcount must be a whole number from 1 to 20
400NO_ACCOUNT, ACCOUNT_REQUIREDThis 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
402NOT_PAIDStudent access unpaid or expired
403ACCOUNT_LIMITPlan account limit reached (limit, used in reply). Starter is 1 account
403ACCOUNT_LOCKEDStarter accounts cannot be disconnected. Upgrade to Pro
403UUID_LOCKEDStarter UUIDs are permanent and cannot be regenerated
403UUID_ACCOUNT_MISMATCHThis UUID belongs to a different MT5 account
403ACCOUNT_DORMANTAccount paused because the plan has fewer slots now. Upgrade to wake it up
403PLAN_REQUIREDNeeds the Pro plan (batch, webhooks, developer keys)
403EMAIL_NOT_VERIFIEDConfirm your email first
403DEVELOPER_ONLYA Student ID can only be combined with a developer key
403-That account is not yours
404STUDENT_ID_UNKNOWNNo 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

PlanMT5 accountsRequests per minute
Starter1 (locked)30
Pro50 (+ R20 per extra, per 30 days)600
Enterpriseunlimited3000, 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.