> ## Documentation Index
> Fetch the complete documentation index at: https://developers.fhsc.com.vn/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limits

> Giới hạn request per API key và chiến lược retry khi bị throttled.

API có rate limit theo API key để bảo vệ hạ tầng. Khi vượt giới hạn,
server trả về HTTP `429 Too Many Requests` kèm header
`X-RateLimit-Reset` cho biết thời điểm có thể retry.

<Note>
  Hạn mức (request / phút) phụ thuộc vào loại tài khoản —
  **Free**, **Pro**, hoặc **Enterprise**. Mỗi tier có một hạn mức riêng.
</Note>

## Response khi bị throttled

```http theme={null}
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Reset: 1714464000

{
  "error_code": "RATE_LIMIT_EXCEEDED",
  "message": "Too many requests"
}
```

`X-RateLimit-Reset` là Unix timestamp (giây) tại thời điểm cửa sổ rate
limit reset.

## Header tham chiếu

| Header              | Ý nghĩa                                                                      |
| ------------------- | ---------------------------------------------------------------------------- |
| `X-RateLimit-Reset` | Unix timestamp (giây) khi rate limit reset. Chờ đến thời điểm này rồi retry. |

## Chiến lược retry

<Steps>
  <Step title="Đọc X-RateLimit-Reset">
    Ngay khi nhận `429`, parse header `X-RateLimit-Reset`. Tính thời gian
    chờ:

    ```typescript theme={null}
    const resetAt = Number(res.headers.get("X-RateLimit-Reset")) * 1000;
    const waitMs = Math.max(0, resetAt - Date.now());
    ```
  </Step>

  <Step title="Tạm dừng đến reset, tránh vòng lặp chặt">
    KHÔNG retry ngay lập tức — sẽ tiếp tục bị reject với `429` và làm
    tình trạng tệ hơn. Tạm dừng đến `resetAt` cộng thêm jitter ngẫu
    nhiên (50–500ms) để tránh hiện tượng thundering herd khi nhiều
    client đồng thời được đánh thức.

    ```typescript theme={null}
    const jitter = Math.random() * 450 + 50;
    await new Promise(r => setTimeout(r, waitMs + jitter));
    ```
  </Step>

  <Step title="Retry với cap">
    Sau khi tạm dừng, retry request. Nếu vẫn `429` lần thứ 2 → chứng tỏ
    key đã bị giới hạn dài hạn. Cap retry tối đa 2–3 lần, nếu vẫn fail
    thì đẩy lỗi lên tầng application thay vì retry vô tận.
  </Step>
</Steps>

## Best practices

* **Cache aggressive** cho các endpoint dữ liệu thị trường ít đổi: bank
  interest rates, fund list, gold/silver chart history. TTL 1–5 phút là
  hợp lý cho hầu hết use case UI.
* **Batch query** khi có thể: `GET /market/stock-realtime?symbols=VNM,FPT,VIC`
  trả về 3 stock trong 1 call thay vì 3 call riêng.
* **Tránh polling tight**: dùng adaptive polling (1s khi có activity,
  giãn lên 30s khi idle) thay vì polling cố định 1s mọi lúc.
* **Xếp ưu tiên**: với rate limit thấp, ưu tiên gọi endpoint user-scoped
  (Tier 2) trước, dữ liệu thị trường có thể chậm trễ vài giây không vấn
  đề.

## Khi nào cần nâng hạn mức

* Production traffic vượt 70% hạn mức ổn định trong > 1 giờ.
* Có batch job daily / weekly cần burst traffic ngắn.
* Triển khai tính năng mới có gọi API trong luồng UX quan trọng.
