# Authentication

> MetaTrader API docs for developers and coding agents. Last updated: 2026-10-14. Index: https://www.metatraderapi.net/llms.txt
>
> © 2026 Apex Vanguard Dynamics LLC. You, and the software tools and AI agents working for you, may read and use this documentation to build, run and support integrations with MetaTrader API; its code examples may be copied into your own software. Republishing or redistributing the documentation, in whole or in substantial part, is not permitted. Terms: https://www.metatraderapi.net/en/terms/

## The two values every request needs

| What | Where it goes | Example |
|---|---|---|
| API key (`mt5api_...`) | header `x-api-key` | `x-api-key: mt5api_...` |
| Account id (UUID) | query `?id=` (alias `?accountId=`) | `?id=3f0c...` |

```bash
curl -s -H "x-api-key: $MTAPI_KEY" "https://api.metatraderapi.net/AccountSummary?id=$MTAPI_ID"
```

- On the trading and market-data endpoints the key is accepted **only** as the `x-api-key` header. (The connection endpoints such as `/ConnectEx` and `/news` also accept `Authorization: Bearer`.) Always sending `x-api-key` works everywhere except the provisioning endpoints.
- On the WebSocket the key may also be passed as `?apiKey=` (browsers cannot set headers on a WebSocket). From a server, prefer the header so the key stays out of URLs and logs.
- Keys are stored only as a hash. The full key is shown once, when it is created; if it is lost, create a new one and revoke the old one.

## Key types

Every API key is created for one account, but **unless it is `accountScoped`, it works for every trading account in your dashboard login**: the `?id=` you send picks the account. Two optional flags narrow it:

| Flag | Effect |
|---|---|
| `readOnly` | Data and streaming only. Every trading call (`/OrderSend`, `/OrderModify`, `/OrderClose`, `/OrderDelete`, `/OrderCloseBy`) answers `403`. |
| `accountScoped` | Works only for its own account. `?id=` of any other account answers `403`. |

A key without `accountScoped` can address **any** account of the same customer through `?id=`. To give a client or a front end access to exactly one account, create a key with `accountScoped: true` (and `readOnly: true` if it must not trade).

Create keys:
- in the dashboard, on the account's card ("Generate key"): a full-access key, not account-scoped;
- from your backend with a management key, with or without the flags: `POST /v1/seats/{id}/keys` with `{"label": "...", "readOnly": true, "accountScoped": true}` (see https://www.metatraderapi.net/docs/provisioning.md). This is the only way to create a read-only or account-scoped key.

## Management keys (provisioning)

A management key (`mt5mgmt_...`) creates and removes seats and their API keys from your own backend. It is created in the dashboard's Settings ("Create management key") and sent as `Authorization: Bearer mt5mgmt_...` (or the `x-management-key` header). It does not work as an `x-api-key` on the trading endpoints.

## Auth errors

| HTTP | Body | Meaning |
|---|---|---|
| 401 | `{"error":"missing x-api-key header"}` | no key sent |
| 401 | `{"error":"invalid api key"}` | unknown or revoked key |
| 400 | `{"error":"missing account id -- pass ?id=<accountUUID>"}` | no `?id=` |
| 404 | `{"error":"account not found"}` | the id does not exist, was removed, or belongs to someone else |
| 403 | `{"error":"this key is scoped to a single account"}` | account-scoped key used with another account's id |
| 403 | `{"error":"read-only key: trading is not permitted"}` | read-only key on a trading call |
| 402 | `{"error":"NO_SUBSCRIPTION", ...}` | the subscription is not active |
| 429 | `{"error":"too many failed auth attempts -- slow down"}` | 40 failed authentications (401: missing or invalid key) from one IP within 5 minutes; that IP is blocked for 10 minutes (`retry-after: 600`) |

The `/v1/*` endpoints word some of these differently (for example `{"error":"API key required"}`); match on the HTTP status, not on the text.

## Rules

- Never put an API key in client-side code, a mobile app, or a public repository. For a browser, issue an `accountScoped`, `readOnly` key.
- Never retry a `401` or `403` in a loop: each `401` counts toward the failed-auth block above, and a `403` will not succeed on a retry either.
