Docs

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:

PasswordWhat it allowsWorks with fxapis?
Trading (master) passwordLog in, read, and tradeYes — this is the one to send
Investor passwordLog in and read onlyNo — 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. …-Demo and …-Live accounts cannot be swapped.
  • Numbered servers are separate servers. …-Live02 is 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:

ModeUse it for
warm_on_demandMost integrations. Comes online for an order (or when you prepare it) and goes offline after 15 idle minutes.
always_onAccounts that must act instantly at any time — masters of a copier, accounts under live risk monitoring. A plan feature.
coldAccounts 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 id instead; 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:

  1. POST /v1/accounts/{id}/warm — answers 202 at once.
  2. Poll GET /v1/accounts/{id}/status every two seconds until state is ready or a needs-attention state. About 10 seconds in our measurement; allow up to two minutes.
  3. 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

StateWhat it meansTell the user
invalid_credentialsThe broker rejected the login.The login, password or server is wrong. Check the trading password and the exact server name.
trading_disabledThe 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_2faThe 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_certificateThe broker requires a client certificate.Contact support.
errorSomething 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/accounts lists every account with its state, so a nightly job can find those needing attention and prompt their owners.

On this page