Connect MT5 accounts by login, password and server
How to connect a MetaTrader 5 account to the fxapis API: finding the exact server name, trading versus investor password, two-factor sign-in, handling credentials safely in your app, checking them immediately, needs-attention states, and disconnecting.
Connecting an MT5 account takes three things from its owner — the login, the trading password and the server name — and one API call. Getting those three right, and handling the password with care on the way, is most of what makes a connect screen work. This guide covers both.
curl -sS -X POST "https://api.fxapis.com/v1/accounts" \
-H "Authorization: Bearer $FXAPIS_KEY" \
-H "Content-Type: application/json" \
-d '{
"login": "81234567",
"server": "VantageMarkets-Live",
"password": "the-trading-password",
"mode": "warm_on_demand",
"label": "member_4821"
}'201 returns the account with its id and state: "created". It does not
log in yet — that happens when the account is first brought online, which is
why you should check the credentials straight away.
Reference: Connect an MT5 account.
The three things you need
Login
The MT5 account number, digits only, sent as a string: "81234567". A
login with anything other than digits is refused with 400
INVALID_REQUEST. It is not an email address and not the user's name at the
broker's client portal — many brokers have both, and people confuse them.
Password: trading, not investor
Every MT5 account has two passwords:
| Password | What it allows | Works with fxapis? |
|---|---|---|
| Trading (master) password | Log in, read, and trade | Yes — this is the one to send |
| Investor password | Log in and read only | No — the login succeeds but trading is refused |
The investor password is the classic mistake, because nothing fails at first.
The account reaches ready and its first order is rejected. Ask for
the trading password by that name on your connect screen, and say why.
Server: exactly as MetaTrader shows it
The server name identifies the broker's trade server the account lives on —
VantageMarkets-Demo, VantageMarkets-Live, ICMarkets-Live02. It must match
exactly, including capitals, hyphens and any number at the end.
Where the account's owner can find it:
- MetaTrader 5 desktop: the Navigator window lists each account with its server; the login dialog (File → Login to Trade Account) shows it too.
- MetaTrader 5 mobile: the account screen in the app's settings shows the server under the account number.
- The broker's account email: brokers send the login and server when an account is opened.
Naming tips worth putting on your connect screen:
- Live and demo are different servers.
…-Demoand…-Liveaccounts cannot be swapped. - Numbered servers are separate servers.
…-Live02is not…-Live, and an account exists on exactly one of them. - One broker can run several brands and regions, each with its own servers. The account's server is the one it was opened on, not the one on the broker's homepage.
- Trim what the user types. A trailing space from copy-paste is a different server name. We store the value exactly as sent.
- Prefer a free-text field with examples over a fixed dropdown; brokers add and rename servers.
Test with demo accounts first
API keys labelled fx_test_ still reach real brokers. Build your connect flow against broker
demo accounts before connecting anybody's real money.
Choosing a mode
mode decides when the account is online. The default is cold, so set it:
| Mode | Use it for |
|---|---|
warm_on_demand | Most integrations. Comes online for an order (or when you prepare it) and goes offline after 15 idle minutes. |
always_on | Accounts that must act instantly at any time — masters of a copier, accounts under live risk monitoring. A plan feature. |
cold | Accounts you bring online yourself, on a schedule. |
You can change it later with
POST /v1/accounts/{id}/mode.
See Accounts → Modes.
Handling credentials in your app
The MT5 password is the key to someone's money. fxapis encrypts it on arrival with a key unique to that account, never returns it from any endpoint, and erases it when the account is disconnected — see Security. Your side of the job is to make sure it passes through your systems without leaving a trace:
- Send it from your backend, straight to fxapis, in the same request that received it. Your
API key must never be in a browser or mobile app, so the form posts to your server and your
server calls
POST /v1/accounts. - Never store it — not in your database, a cache, a queue job, an analytics event or a support
ticket. Store the fxapis account
idinstead; it is all you need from then on. - Never log it. Turn off request-body logging for the connect route, and make sure error reporting tools do not capture the body when the call fails.
- Only over HTTPS, and never in a URL or query string, where proxies and browsers keep copies.
- Do not retry the connect call from a background job. That would mean storing the password to
retry later. If fxapis answers 503
SECRET_STORE_UNAVAILABLE, nothing was created: retry a couple of times in the same request, then ask the user to try again.
# fxapis = httpx.Client(base_url="https://api.fxapis.com", headers={"Authorization": f"Bearer {KEY}"})
@app.post("/connect-mt5")
def connect_mt5(form: ConnectForm, user: User):
response = fxapis.post("/v1/accounts", json={
"login": form.login.strip(),
"server": form.server.strip(),
"password": form.password, # used once, here, and never kept
"mode": "warm_on_demand",
"label": f"user_{user.id}",
}, timeout=30)
if response.status_code == 409: # ACCOUNT_EXISTS: already connected in your workspace
return {"error": "This account is already connected."}
response.raise_for_status()
account = response.json()["data"]
user.fxapis_account_id = account["id"] # the id, not the password
fxapis.post(f"/v1/accounts/{account['id']}/warm")
return {"accountId": account["id"]}A login and server can be connected once per workspace. A second attempt
returns 409 ACCOUNT_EXISTS: two connections would mean two places able to
trade the same money. If two of your users claim the same MT5 account, that is
a question for your support team, not a retry.
Connecting more accounts than your plan allows returns 402
QUOTA_EXCEEDED.
Check the credentials immediately
A new account has not logged in yet. If you wait for its first trade to find out that the password is wrong, the failure arrives at the worst moment. Bring it online while the user is still on the connect screen:
POST /v1/accounts/{id}/warm— answers 202 at once.- Poll
GET /v1/accounts/{id}/statusevery two seconds untilstateisreadyor a needs-attention state. About 10 seconds in our measurement; allow up to two minutes. - Show the result.
const NEEDS_ATTENTION = ["invalid_credentials", "trading_disabled", "needs_2fa", "needs_certificate"];
async function checkCredentials(accountId: string): Promise<string> {
const deadline = Date.now() + 120_000;
while (Date.now() < deadline) {
const res = await fetch(`${API}/v1/accounts/${accountId}/status`, { headers: { Authorization: `Bearer ${KEY}` } });
const { data } = await res.json();
if (data.state === "ready" || NEEDS_ATTENTION.includes(data.state)) return data.state;
await new Promise((r) => setTimeout(r, 2000));
}
return "timeout";
}In your UI, poll your own backend from the browser, and let the backend call
fxapis. Once the check is done, a warm_on_demand account goes offline again
by itself after 15 minutes; nothing else is needed.
The needs-attention states
| State | What it means | Tell the user |
|---|---|---|
invalid_credentials | The broker rejected the login. | The login, password or server is wrong. Check the trading password and the exact server name. |
trading_disabled | The broker has disabled trading for this login. | Ask the broker to enable trading. (An investor password instead reaches ready and its orders are rejected.) |
needs_2fa | The account requires a second factor at login. | Two-factor sign-in must be turned off for this account; it cannot be completed by an API. |
needs_certificate | The broker requires a client certificate. | Contact support. |
error | Something temporary went wrong. | Try again; bringing the account online again is safe. |
The first four will not fix themselves, and repeated failed logins are how a
broker locks an account. So fxapis stops trying: bringing such an account
online returns 409 NEEDS_OPERATOR, and prepare reports it as
needs_operator, without contacting the broker. Do not put these in a retry
loop. All states are listed in Accounts → States.
Correcting credentials
When a password was wrong, or the member changed it at the broker, replace it on the existing account — its id, history and settings stay:
curl -sS -X POST "https://api.fxapis.com/v1/accounts/$ACCOUNT_ID/password" \
-H "Authorization: Bearer $FXAPIS_KEY" \
-H "Content-Type: application/json" \
-d '{ "password": "the-members-corrected-password" }'Add "server" to correct the server name at the same time. The account is taken offline first
(refused with 409 ACCOUNT_EXECUTING while an order is in flight), the new password is stored,
and only then is the old one erased. The account lands in created: bring it online straight away
and poll its status, exactly as on the connect screen, so the member learns at once whether the new
password works.
A login that was disconnected can also simply be connected again with POST /v1/accounts: the
same account comes back with the new password, and the answer is 200 instead of 201.
Disconnecting
curl -sS -X POST "https://api.fxapis.com/v1/accounts/$ACCOUNT_ID/disconnect" \
-H "Authorization: Bearer $FXAPIS_KEY"disconnect takes the account offline and erases the stored password at
once; the response says "credentialsRemoved": true. The account record and
its whole trading history remain, in state offline, for your records and any
dispute. Call it when a user removes their account or leaves your product: a
password you no longer need is one nobody should keep holding.
If you only want the account offline for now, use
POST /v1/accounts/{id}/cool instead — it keeps
the password so the account can come back. Open positions are untouched either
way; stop losses and take profits live at the broker and keep working.
Connecting many accounts
- Connect accounts one call each, as users sign up.
- Bring up to 200 online in one call with
POST /v1/accounts/prepare; each gets its own result (starting,already_running,needs_operator…). GET /v1/accountslists every account with itsstate, so a nightly job can find those needing attention and prompt their owners.
Related
Use the MetaTrader 5 API on Linux and macOS
Why the official MetaTrader5 Python package only works on Windows next to a running terminal, the Wine, Docker and VPS workarounds people use on Linux and macOS, and how to trade MT5 accounts over plain HTTP instead — from any OS and any language.
Place one order across many MT5 accounts
Send the same MetaTrader 5 trade to many accounts in one API call — up to 500 on Enterprise (Starter 10, Scale 100): per-account volumes, barrier policies for accounts that are not online, scheduled execution with executeAt and expiresAt, per-account results, cancelling, and dispatch spread.