# MT5 API rate limits: back off without losing orders

> Tickwire's MT5 and MT4 API uses plain token buckets per key and per account. Here are the limits, the headers, and how to back off without placing a second order.

Source: https://tickwire.io/blog/mt5-api-rate-limits/

Tickwire blog, published 2026-11-01. General information, not investment advice.

Tickwire's MT5 and MT4 API limits requests with token buckets: each key, account and address has a bucket that holds a burst and refills every second. When a bucket is empty you get `429` with a `Retry-After` header, and a refused trade says `"sent": false`, so waiting and repeating it with the same idempotency key is always safe. This post lists the limits and shows a backoff that never places a second order.

The numbers below come from the [rate limits page](https://tickwire.io/docs/rate-limits/), which is the place to check if they change.

## The buckets

| Bucket | Burst | Refill per second |
|---|---|---|
| Per API key | 100 | 50 |
| Per account | 40 | 20 |
| Per account, trades | 20 | 10 |
| Per address, anonymous | 20 | 5 |
| Per address, failed sign-ins | 20 | 0.5 |
| Per address, MCP | 200 | 50 |
| Per address, agent keys | 200 | 50 |
| Per signal webhook | 30 | 1 |

A request takes tokens from every bucket it touches. A trade on one account uses the key bucket, the account bucket and the trade bucket.

## Not every call costs the same

| Call | Weight |
|---|---|
| Most reads | 1 |
| History | 5 |
| A trade | 1 |
| A batch order | 10 |
| Opening a stream | 5 |

On top of the buckets, one key may have 16 requests and 16 trades in flight at once. A key may hold 50 WebSockets. Over those limits the answer is an immediate `429`.

## What is free

- WebSocket frames, once the stream is open;
- webhook deliveries to you;
- health checks.

That is why streaming beats polling. A bot that polls positions ten times a second spends its whole bucket on reads. A bot that opens one stream gets every change and spends nothing more. See [Webhooks vs polling](https://tickwire.io/blog/webhooks-vs-polling/) and [Stream MT5 prices with WebSocket](https://tickwire.io/blog/stream-mt5-prices-websocket/).

## The headers

Every answer says where you stand:

```http
RateLimit-Limit: 100
RateLimit-Remaining: 37
RateLimit-Reset: 2
RateLimit-Policy: 100;w=2;name="key"
```

The same values come as `X-RateLimit-*` too. Read `RateLimit-Remaining` and slow down before you hit zero.

## What a 429 looks like

```json
{ "error": "rate_limited", "message": "too many requests; retry after the time in Retry-After",
  "sent": false, "outcome": "not_sent",
  "metadata": { "recommendedRetryTime": "2026-09-25T11:02:20.000Z", "exceededConfig": "perAccountTrades",
                "resourceId": "account:acc_7Qx", "limit": 20, "bucket": "account-trades", "weight": 1 } }
```

`metadata.bucket` says which bucket ran out, here the trade bucket of one account. `"sent": false` is the important part. A refused trade never left Tickwire. Nothing reached the broker. On the `/users/current/…` routes the error is `TooManyRequestsError`, with `rate_limited` in `code`.

## Back off without a second order

The rule is short: wait at least `Retry-After`, then repeat the **same** request with the **same** `Idempotency-Key`. Never make a new key for a retry.

```python
import random, time, uuid, requests

API = "https://api.tickwire.io"

def send_trade(session, account_id, order, reason, max_wait=30):
    key = str(uuid.uuid4())          # one key per decision, reused on every retry
    delay = 1.0
    while True:
        r = session.post(f"{API}/users/current/accounts/{account_id}/trade", json=order,
                         headers={"Idempotency-Key": key, "X-Actor": "bot", "X-Reason": reason},
                         timeout=30)
        if r.status_code != 429:
            return r.json()
        wait = max(float(r.headers.get("Retry-After", 1)), delay)
        time.sleep(wait + random.uniform(0, wait / 2))   # jitter
        delay = min(delay * 2, max_wait)
```

Set the `auth-token` header on the session. Why the same key matters: if an earlier attempt did reach the terminal and only the answer was lost, the repeat returns that first answer instead of placing a new order. Our post on [retries that never trade twice](https://tickwire.io/blog/retries-never-trade-twice/) walks through it.

## Other answers to handle

- `too_many_connections`: you hold 50 WebSockets on one key. Close some, or share one stream across symbols.
- `503`: the service is busy for a moment. Back off the same way.
- `409 idempotency_in_flight`: an earlier request with the same key is still running. Wait for `Retry-After` and repeat with the same key.

## Habits that keep you under the limits

1. Stream instead of polling.
2. Ask for history in pages, not all at once, and cache what you already have.
3. Use one batch order for many accounts instead of many single calls.
4. Read `RateLimit-Remaining` and pace yourself.
5. Spread background jobs over time, not all at the top of the minute.

Need more? Higher limits are available on request.

## Frequently asked questions

### What are the MT5 API rate limits on Tickwire?

Each API key has a bucket of 100 that refills at 50 per second. Each account has 40 refilling at 20, and trades on an account have 20 refilling at 10. The full table is on the rate limits page.

### Is a trade refused with 429 safe to retry?

Yes. A 429 trade answer says sent false and outcome not_sent: nothing reached the broker. Wait for Retry-After and send it again with the same Idempotency-Key.

### Do WebSocket messages count toward the limits?

No. Opening a stream costs 5 tokens. The frames you receive after that are free, and so are webhook deliveries and health checks.

### Are the limits the same on MT4?

Yes. MT4 and MT5 accounts share the same API and the same buckets.

### How do I get higher limits?

Ask us. Higher limits are available on request. See [pricing](https://tickwire.io/pricing/) for plans, and the [MT5 API page](https://tickwire.io/mt5-api/) for the full API.
