Guide

MT4 / MT5 brokers

Your clients trade on MetaTrader 4 or 5; Octolit gives you the CRM, the client dashboard and trader, sign-in, and the Partner API and webhooks around them. This guide covers the broker side: how MT logins are tied to clients, what MT accounts look like in the API, what money posting does for them, and which trading calls do not apply.

#Overview

Platforms
MetaTrader 4 and MetaTrader 5
Links
POST …/users/{external_id}/mt_links, scope mt:link, up to 20 per user
MT accounts
type.provider = "mt", mt_login set
Execution
stays on your MT server (409 mt_account on the platform's order path)

The platform does not replace your MetaTrader server. It records which MT login belongs to which client, lists the client's accounts, books deposits and withdrawals through the CRM's transaction service, and keeps your own systems in the loop with webhooks and the Partner API.

#Two ways to run

Link only

  • The client already has an MT login on your server; you tell the platform about it with one call.
  • The MT side itself is not touched.
  • The platform records the link (platform, server, login, label); the Partner API returns it.
  • Execution stays on your MT server.

Connected MT server

  • Trading accounts whose type has provider = "mt"; such accounts carry an mt_login.
  • Balance and the other figures are the last ones the connector reported.
  • A deposit or withdrawal booked through the CRM or the Partner API includes the balance call to the MT server.
  • Without a connected MT server, orders for a MetaTrader account are placed in MetaTrader (409 mt_account).

Both can run side by side: a client may have accounts the platform executes (provider = "internal"), MT accounts, and plain links.

#Before you start

  • A Partner API key with the mt:link scope (CRM Settings > API & Webhooks); accounts:read to read accounts and balances, users:write to create clients, sso:issue for sign-in links.
  • The client exists in the platform with your external_id - create it with PUT …/users/{external_id} (see Provision users and accounts).
  • The MT server name as you call it; one login per server belongs to one user.

POST …/users/{external_id}/mt_links records that the login on the named server belongs to this client. One login per server belongs to one client; a user may have at most 20 links.

FieldRuleMeaning
platformrequiredmt4 or mt5.
serverrequired, up to 120 charsThe MT server name as you, the broker, call it (for example YourBrand-Live).
loginrequired, up to 64 charsThe MT account login, as a string.
labelup to 64 charsA free label for the link (optional).
trading_account_idintegerOne of the user's trading accounts (optional).
POST /api/external/v1/users/cust_10042/mt_links
curl -X POST "https://api.your-brand.com/api/external/v1/users/cust_10042/mt_links" \
  -H "X-Api-Key: $OCTOLIT_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "platform": "mt5",
  "server": "YourBrand-Live",
  "login": "5012345",
  "label": "Main MT5",
  "trading_account_id": 88213
}'
201 Created
{
  "mt_link": {
    "id": 417,
    "platform": "mt5",
    "server": "YourBrand-Live",
    "login": "5012345",
    "label": "Main MT5",
    "trading_account_id": 88213,
    "created_at": "2026-11-11T10:02:14Z",
    "updated_at": "2026-11-11T10:02:14Z"
  }
}

The answer carries the link's id - keep it, the remove call needs it. The full mt_link object (including its status string) is in the reference; label and trading_account_id are null when not given.

StatusCodeMeaning
403insufficient_scopeThe key does not carry mt:link.
403brand_disabledThe brand has the "Partner API" switch off.
404user_not_foundNo client with that external_id in your company.
409already_linkedThat MT login on that server is already linked. Remove the old link first.
422invalid_requestA field is missing, unknown or invalid; details.errors names it.
409 Conflict
{
  "error": {
    "code": "already_linked",
    "message": "That MT login on that server is already linked.",
    "details": {}
  }
}
Link only
Linking records that the login belongs to this user; the MT side itself is not touched. If the client has no MT login yet, create it on your MT server first, then link it.

#List and remove links

GET …/users/{external_id}/mt_links returns every link of the client; DELETE …/users/{external_id}/mt_links/{link_id} removes one. After the removal the same login on that server can be linked to another user; the MT side is not touched.

GET /api/external/v1/users/cust_10042/mt_links
curl "https://api.your-brand.com/api/external/v1/users/cust_10042/mt_links" \
  -H "X-Api-Key: $OCTOLIT_PARTNER_KEY"
200 OK
{
  "mt_links": [
    {
      "id": 417,
      "platform": "mt5",
      "server": "YourBrand-Live",
      "login": "5012345",
      "label": "Main MT5",
      "trading_account_id": 88213,
      "created_at": "2026-11-11T10:02:14Z",
      "updated_at": "2026-11-11T10:02:14Z"
    },
    {
      "id": 418,
      "platform": "mt4",
      "server": "YourBrand-Demo",
      "login": "880231",
      "label": null,
      "trading_account_id": null,
      "created_at": "2026-11-11T10:05:40Z",
      "updated_at": "2026-11-11T10:05:40Z"
    }
  ]
}
DELETE /api/external/v1/users/cust_10042/mt_links/417
curl -X DELETE "https://api.your-brand.com/api/external/v1/users/cust_10042/mt_links/417" \
  -H "X-Api-Key: $OCTOLIT_PARTNER_KEY"
200 OK
{
  "unlinked": true
}
404 not_found when the link id does not belong to this client.

#MT accounts in the API

MT accounts appear in GET …/users/{external_id}/accounts and GET …/balance next to the platform's own accounts. Tell them apart by type.provider.

GET /api/external/v1/users/cust_10042/accounts
curl "https://api.your-brand.com/api/external/v1/users/cust_10042/accounts" \
  -H "X-Api-Key: $OCTOLIT_PARTNER_KEY"
200 OK
{
  "accounts": [
    {
      "id": 88213,
      "name": "Main MT5",
      "currency": "USD",
      "demo": false,
      "type": {
        "id": 7,
        "name": "MT5 Standard",
        "provider": "mt"
      },
      "balance": "1250.00",
      "equity": "1262.40",
      "margin": "41.20",
      "free_margin": "1221.20",
      "margin_level": "3064.1",
      "open_pl": "12.40",
      "closed_pl": "0",
      "credit": "0",
      "mt_login": "5012345",
      "created_at": "2026-11-11T09:31:00Z"
    },
    {
      "id": 88214,
      "name": "Practice",
      "currency": "USD",
      "demo": true,
      "type": {
        "id": 2,
        "name": "Demo",
        "provider": "internal"
      },
      "balance": "10000.00",
      "equity": "10000.00",
      "margin": "0",
      "free_margin": "10000.00",
      "margin_level": null,
      "open_pl": "0",
      "closed_pl": "0",
      "credit": "0",
      "mt_login": null,
      "created_at": "2026-11-11T09:31:00Z"
    }
  ]
}
  • type.provider is mt for an MT account, internal for an account the platform executes.
  • mt_login is set for MT accounts only.
  • In the balance call, values are the platform's live figures at as_of; MT accounts show the last figures the connector reported.
  • A link (previous section) is a record, not a trading account. Set trading_account_id on the link when the login belongs to one of the user's trading accounts.

#Money

Deposits and withdrawals are booked the same way as for every other account: in the CRM by your staff, or from your backend with POST …/users/{external_id}/transactions (scope balance:write, idempotency key required - see Money posting). The money is booked by the CRM's own transaction service - balance update, first-deposit date, client e-mails, postbacks and, for an MT account, the balance call to the MT server. status: pending waits for approval in the CRM first; deposit.status / withdrawal.status webhooks follow like for any other transaction.

Book money through the CRM
Only money posting moves money, and only through the CRM's own transaction service. Book deposits and withdrawals in the CRM or with the Partner API so that the transaction row, the first-deposit date, the client e-mails and the balance call to the MT server all happen together.

#Trading APIs and MetaTrader accounts

The platform's order path - the Trading API (client keys) and trading on behalf (your Partner key) - answers with a clear code for MetaTrader accounts:

StatusCodeWhen
409mt_accountTrading API: a MetaTrader account without a connected MT server cannot trade through the API - its orders are placed in MetaTrader. Trading on behalf: a MetaTrader account is not traded through the API.
409mt_positionTrading API: a MetaTrader position without a connected MT server cannot be changed through the API.
409 Conflict
{
  "error": {
    "code": "mt_account",
    "message": "A MetaTrader account is not traded through this API.",
    "details": {}
  }
}

Reads are not affected: accounts, balance and positions through the Partner API; quotes and bars through both APIs. The full code lists are in the error reference.

#What the client sees

Clients sign in to https://live.your-brand.com as every other client - with their password, or by single sign-on from your site or app (SSO guide, POST …/sso with target: trader or dashboard).

  • Accounts: the trading accounts the platform holds for the client - MT accounts with their mt_login and the last figures the connector reported, internal accounts with live figures.
  • Money: deposits, withdrawals and credits booked by the CRM's transaction service, with their status.
  • Trading: orders for a MetaTrader account are placed in MetaTrader, not through the platform's order path.

Inside your own app the Embed SDK shows the same trader.

#Webhooks

What the CRM does for an MT client reaches your systems through the webhooks: client.created, client.updated, client.login, client.inactive, client.deleted for the client; account.created for a new trading account; deposit.status and withdrawal.status for money. Use the clients delta (GET …/clients?updated_since=…) for a periodic full reconciliation with your MT user base.

#Checklist

  1. Clients

    Every MT user exists in the platform with your external_id (PUT …/users/{external_id}).

  2. Links

    Every MT login is linked with the right server name, at most 20 per user; 409 already_linked handled by removing the stale link first.

  3. Money

    Deposits and withdrawals go through the CRM or POST …/transactions with an idempotency key.

  4. Trading calls

    Your integration treats 409 mt_account / 409 mt_position as "placed in MetaTrader", not as a failure to retry.

  5. Sign-in

    A "Dashboard" button on your site or app uses a one-time login link (POST …/sso) or your signed JWT.

  6. Webhooks

    Your endpoint verifies the signature and keys events by id; the clients delta runs once a day as the safety net.