> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# APIレート制限：上限、ヘッダー、429エラー時のバックオフ

> DiditのAPIレート制限について、X-RateLimitヘッダー、Retry-Afterによるバックオフ、エンドポイントごとのスコープ、429エラーへの対処法を解説します。本番環境のトラフィックを安心して計画できます。

Didit は、正常なトラフィックの急増には対応しつつAPIの安定性を保つため、複数の層でレート制限を適用しています。制限は**識別子ごと**に適用されます。識別子は`x-api-key`で、APIキーが送信されない場合はクライアントのIPアドレスです。各スコープでは、60秒のスライディングウィンドウを使用して独立したカウンターが維持されます。

## 識別子と適用除外

ミドルウェアは、次の順序でレート制限の識別子を選択します。

1. `x-api-key`ヘッダー → キー単位のカウンター。
2. `X-Forwarded-For`の最初のホップ → IP単位のカウンター。
3. `REMOTE_ADDR` → IP単位のカウンター。

次の呼び出しには、レート制限が一切**適用されません**。

* 内部用の`DIDIT_WEBAPP_API_KEY`(Didit コンソールのみが使用)。
* `IsValidSession`権限で保護されたエンドポイント(埋め込み/SDKのセッショントラフィック)。
* `GET /system/healthcheck`(このスタックより前に`HealthMiddleware`が処理)。
* プロバイダーのWebhook: Stripe、AMLスクリーニング、顔認証のコールバック、KYCリストの変更。

## グローバル制限

認証済みのリクエストはすべて、HTTPメソッドごとに汎用スコープにも振り分けられます。そのため、新しいルートにも妥当なデフォルト値が自動的に適用されます。

| スコープ | HTTPメソッド | 制限 | ウィンドウ |
| - | - | - | - |
| `generic-get` | `GET` | 600 / min | 60 s |
| `generic-write` | `POST`, `PATCH`, `DELETE` | 300 / min | 60 s |

エンドポイント固有の制限（次のセクション）は、グローバル制限に**加えて**適用されます。最初にカウンターの上限を超えたスコープが`429`を返します。

## エンドポイント固有の制限

ミドルウェアは、影響の大きいルートに対してより厳しいスコープを定義しています。

| スコープ | エンドポイント | 制限 | 定義元の定数 |
| - | - | - | - |
| `session-v2-create` | `POST /v2/session/`, `POST /v3/session/` | 600 / min | `SESSION_CREATE_RATE_LIMIT` |
| `session-decision` | `GET /v1/session/<id>/decision/`, `GET /v2/session/<id>/decision/` | 100 / min | `SESSION_DECISION_RATE_LIMIT` |
| `session-generate-pdf` | `GET /v1/session/<id>/generate-pdf/`, `GET /v3/session/<id>/generate-pdf/` | 50 / min | `SESSION_PDF_RATE_LIMIT` |
| `session-add-images` | `POST`/`PATCH /session/<id>/add-images/` | 10 / min | `SESSION_ADD_IMAGES_RATE_LIMIT` |
| `session-update-kyc` | `POST`/`PATCH /session/<id>/update-data/` | 10 / min | `SESSION_UPDATE_KYC_RATE_LIMIT` |
| `session-update-poa` | `POST`/`PATCH /session/<id>/update-poa-data/` | 10 / min | `SESSION_UPDATE_POA_RATE_LIMIT` |

> [!NOTE]
>
> `GET /v3/session/<id>/decision/`は`SessionV3RetrieveView`が処理しており、`session-decision`スコープには**含まれません**。このエンドポイントには`generic-get`の上限である600/minのみが適用されます。100/minの判定スロットルは、v1とv2の判定パスに適用されます。

> [!WARNING]
>
> コードベースには`FREE_SESSION_RATE_LIMIT = 10`と`PAID_SESSION_RATE_LIMIT = 600`も定義されています。これらの定数は現在`POST /v3/session/`には**適用されていません**。このエンドポイントでは、すべてのアプリケーションに対して`session-v2-create`の単一の制限である600/minが使用されます。ワークフロー単位の無料枠スロットルが稼働中であることがドキュメントに記載されるまでは、それを前提にキャパシティを計画しないでください。

## 429レスポンスの形式

いずれかのスコープの上限を超えると、次のボディとヘッダーを含むHTTP`429`が返されます。

```http theme={null}
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1762534870
Retry-After: 37

{
  "detail": "Session creation rate limit exceeded. You can make up to 600 requests per minute."
}
```

| ヘッダー | 意味 |
| - | - |
| `X-RateLimit-Limit` | 上限超過となったスコープについて、現在のウィンドウ内で許可される最大リクエスト数。 |
| `X-RateLimit-Remaining` | ウィンドウがリセットされるまでの残りリクエスト数。上限を超えると`0`に固定されます。 |
| `X-RateLimit-Reset` | カウンターがゼロにリセットされる時刻(Unixエポック秒)。 |
| `Retry-After` | 次の試行までに待機する秒数。**`429`レスポンスにのみ**含まれ、すべてのリクエストに含まれるわけではありません。 |

`X-RateLimit-*`ヘッダーは`429`レスポンスでのみ出力されます。現時点では、成功したレスポンスには含まれません。次の試行までの待機時間には、`Retry-After`の値(または`X-RateLimit-Reset - now`)を使用してください。

## クライアント実装のガイダンス

* **`Retry-After`を守ってください。**これをバックオフの最小値とし、その上にジッター付きの指数バックオフ(`5s → 10s → 20s → 40s ± random`)を重ねることで、同時に`429`を受けた2つのクライアントが同期して再試行しないようにします。
* **再試行は少ない上限回数で打ち切ってください**(例: 5回)。エラーを呼び出し元に返し、チームにアラートを通知してください。429が継続的に発生する場合、一時的なスパイクではなく、制御不能なループが原因であることがほとんどです。
* **ワークロードごとに1つの識別子を使用してください。**1つの`x-api-key`を多数のバックエンドで共有すると、それらが同じカウンターにまとめられ、1つの負荷の高いバックエンドが他のバックエンドのリクエスト枠を使い果たす可能性があります。環境、ブランド、顧客ごとに別のアプリケーション(つまり別の`api_key`)を発行してください。詳しくは[プログラムによる登録](https://docs.didit.me/ja/integration/programmatic-registration.md#アプリケーションの管理)を参照してください。
* **判定の読み取り結果をキャッシュしてください。**`/decision/`エンドポイントは、短い間隔でのポーリングループを想定して設計されていません。リアルタイムの更新が必要な場合は[Webhook](https://docs.didit.me/ja/integration/webhooks.md)を使用し、`GET /v3/session/<id>/decision/`はバックフィルや監査の目的でのみ呼び出してください。
* **PDFはオフラインで生成してください。**PDFのレンダリングはCPU負荷が高い処理です(上限50/min)。ページが表示されるたびに生成するのではなく、セッションが終了ステータスに達した後にキューを介してトリガーしてください。

## 429に対応したクライアントのサンプル

```javascript theme={null}
async function postSession(body) {
  for (let attempt = 0; attempt < 5; attempt++) {
    const res = await fetch("https://verification.didit.me/v3/session/", {
      method: "POST",
      headers: {
        "x-api-key": process.env.DIDIT_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });

    if (res.status !== 429) return res;

    const retryAfter = Number(res.headers.get("Retry-After") ?? "1");
    const jitter = Math.random() * 1000;
    await new Promise((r) => setTimeout(r, retryAfter * 1000 + jitter));
  }
  throw new Error("Didit: too many 429s, giving up");
}
```

```python theme={null}
import os
import random
import time

import httpx

def post_session(body: dict) -> httpx.Response:
    with httpx.Client(timeout=15) as client:
        for _ in range(5):
            resp = client.post(
                "https://verification.didit.me/v3/session/",
                headers={
                    "x-api-key": os.environ["DIDIT_API_KEY"],
                    "Content-Type": "application/json",
                },
                json=body,
            )
            if resp.status_code != 429:
                return resp
            wait_s = float(resp.headers.get("Retry-After", "1")) + random.random()
            time.sleep(wait_s)
    raise RuntimeError("Didit: too many 429s, giving up")
```

## より大きな上限が必要な場合

マーケティング施策の開始やバックフィルなどで1分あたり600セッションでは足りない場合は、`application`のUUIDと、想定される継続的なレートおよびバーストレートを添えて[support@didit.me](mailto:support@didit.me)までメールでご連絡ください。上限の変更はアプリケーションごとに設定されます。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.