# cTrader API Errors & Rate Limits

> Index of every docs page as Markdown: [llms.txt](https://fxsocket.com/docs/llms.txt). All pages in one file: [llms-full.txt](https://fxsocket.com/llms-full.txt).

Source: https://fxsocket.com/docs/ctrader/errors

Every error from the cTrader API is machine-readable: one envelope with a fixed code you can branch on, and codes that tell a trade that never ran from one that may have. The codes are the ones MetaTrader accounts answer, plus a few that only the cTrader bridge sends.

## Errors

A wrong or missing API key returns HTTP 401 with `UNAUTHORIZED` (see [Authentication](https://fxsocket.com/docs/ctrader/authentication.md)). A read-only `fxs_ro_` key returns HTTP 403 with `READ_ONLY_KEY` on the trading routes and on any method other than GET or HEAD. An unknown path returns a plain 404 from the edge. Everything else comes back in the same envelope: an `error` code, a `message`, and a `command_id` for log correlation. The code is fixed, so branch on it, never on the message:

```json
{
  "error": "MRPC_UNKNOWN_SYMBOL",
  "message": "unknown symbol: EURUSDX",
  "command_id": 19
}
```

| Code | HTTP | Meaning |
| --- | --- | --- |
| `UNAUTHORIZED` | 401 | Missing or wrong API key. |
| `READ_ONLY_KEY` | 403 | A read-only key on a route that trades or changes the terminal. |
| `MRPC_VALIDATION` | 400 | A parameter is missing or malformed, or the order is one cTrader can't take (a stop-limit order, execution Manual). Nothing was sent. |
| `MRPC_UNKNOWN_TICKET` | 400 | No order or position with that ticket. |
| `MRPC_UNKNOWN_SYMBOL` | 400 | The broker has no symbol by that name. Check /symbols for the exact spelling. |
| `MRPC_BAD_TIMEFRAME` | 400 | The timeframe isn't one of the nine the API serves. |
| `MRPC_CLIENT_ORDER_ID_REUSED` | 409 | The clientOrderId was already used for a different order in the last 10 minutes. Nothing was sent. |
| `MRPC_SYMBOL_NOT_QUOTING` | 400 | cTrader has no price for the symbol yet, for example while its market is closed. Retry shortly. |
| `MRPC_TRADE_EA_NOT_READY` | 503 | The account is still signing in to cTrader, typically for a few seconds after linking or a restart. Nothing was executed; retry. |
| `MRPC_ABANDONED` | 504 | The request timed out before the account's trade engine took it. Not executed, safe to resend. |
| `MRPC_TIMEOUT` | 504 | A read timed out. |
| `MRPC_TRADE_OUTCOME_UNKNOWN` | 504 | A trade went to cTrader and no answer came back, even after the bridge looked the order up, so it may have executed. Check /OpenedOrders before you send it again, or resend it with the same clientOrderId. |
| `MRPC_CALC_FAILED` | 400 | cTrader couldn't compute the margin or profit, for example without a conversion rate to the account currency. Retry later. |
| `ACCOUNT_NOT_FOUND` | 404 | The bridge doesn't serve this account right now: it was removed, is suspended, or its cTrader sign-in was revoked. Check the account with GET /v1/accounts/{account_id}. |
| `BROKER_UNAVAILABLE` | 503 | The connection to cTrader is down or being rebuilt. Nothing was sent; retry shortly. |
| `BROKER_TIMEOUT` | 504 | cTrader didn't answer a read in time. Retry. |
| `CTRADER_<code>` | 500 | cTrader refused a request for a reason that isn't a trade result, for example an expired sign-in (CTRADER_CH_ACCESS_TOKEN_INVALID). The message is cTrader's. |
| `MRPC_INTERNAL / MRPC_UNKNOWN_COMMAND` | 500 | A fault in the bridge. Quote the command_id when you report it. |

Two of these tell you whether a trade ran. `MRPC_ABANDONED` means it didn't, so sending it again is safe. `MRPC_TRADE_OUTCOME_UNKNOWN` means it may have, so never resend that order blindly. Send every order with a `clientOrderId` and the question goes away: a repeat with the same id never trades twice and returns the first reply instead (see [Trading](https://fxsocket.com/docs/ctrader/trading.md)).

## cTrader Trade Errors and Their Retcodes

A rejected order is not an error response: the request worked, the broker said no. It comes back as HTTP 200 with `success: false`. cTrader names its refusals with codes such as `NOT_ENOUGH_MONEY`, so the bridge translates each into the matching MT5 `retcode` and puts cTrader's message in `comment`. Your code can branch on the same retcodes for cTrader, MT4 and MT5 accounts:

Rejected order on cTrader:

```
{
  "success": false,
  "outcome": "rejected",
  "retcode": 10014,
  "retcodeDescription": "Invalid volume",
  "deal": 0,
  "order": 0,
  "comment": "volume 0.015 is not a multiple of 0.01 lots from 0.01 to 100",
  ...
}
```

| cTrader error | retcode |
| --- | --- |
| `MARKET_CLOSED, SYMBOL_HAS_HOLIDAY` | `10018` Market closed |
| `NOT_ENOUGH_MONEY` | `10019` No money |
| `TRADING_BAD_VOLUME, TRADING_BAD_STAKE` | `10014` Invalid volume |
| `TRADING_BAD_PRICES` | `10015` Invalid price |
| `TRADING_BAD_STOPS, PROTECTION_IS_TOO_CLOSE_TO_MARKET` | `10016` Invalid stops |
| `TRADING_BAD_EXPIRATION_DATE` | `10022` Invalid expiration |
| `TRADING_DISABLED, TRADING_NOT_ALLOWED` | `10017` Trade disabled |
| `SHORT_SELLING_NOT_ALLOWED` | `10042` Long only |
| `NO_QUOTES` | `10021` No prices |
| `MAX_EXPOSURE_REACHED` | `10034` Volume limit |
| `TOO_MANY_POSITIONS` | `10040` Positions limit |
| `POSITION_LOCKED, PENDING_EXECUTION` | `10028` Locked |
| `POSITION_NOT_FOUND, POSITION_NOT_OPEN` | `10036` Position closed |
| `ORDER_NOT_FOUND` | `10035` Invalid order |
| `REQUEST_FREQUENCY_EXCEEDED` | `10024` Too many requests |
| `CANT_ROUTE_REQUEST, SERVER_IS_UNDER_MAINTENANCE` | `10031` No connection |

A successful market order reports `10009` (Done), a placed pending order `10008` (Placed). `outcome` sums the result up as `applied`, `no_change` (retcode `10025`, safe to treat as applied), `partial` or `rejected`. A volume off the symbol's step (`10014`), a pending price on the wrong side of the market (`10015`) and a modify that changes nothing (`10025`) are answered by the bridge before anything goes to cTrader.

Orders cTrader cannot take the way MetaTrader means them never reach the broker: a stop-limit order (`BuyStopLimit`, `SellStopLimit`) and `execution: "Manual"` are answered with HTTP 400 and `MRPC_VALIDATION`, with the reason in `message`.

## Rate Limits

cTrader accounts reach Spotware through FxSocket's connections to the Open API, which limits requests per connection, history requests most tightly. The bridge paces requests within those limits, so a burst waits a little rather than failing, and it keeps closed bars, so asking for the same price history again costs nothing. A trade that cTrader still refuses for frequency comes back as retcode `10024`. Platform routes under `/v1` are rate limited per API key: if you exceed a limit you get a `429` with a `Retry-After` header, so wait that long and retry. For live prices, positions, or account changes, prefer the [WebSocket streams](https://fxsocket.com/docs/ctrader/websocket.md) over polling: you get pushed updates without burning round-trips.

## Related

- [Authentication](https://fxsocket.com/docs/ctrader/authentication.md)
- [Trading](https://fxsocket.com/docs/ctrader/trading.md)
- [WebSocket streams](https://fxsocket.com/docs/ctrader/websocket.md)
