> ## 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 / 분 | 60초 |
| `generic-write` | `POST`, `PATCH`, `DELETE` | 300 / 분 | 60초 |
| `ingest-write` | `POST /v3/transactions/`, `POST /v3/events/`, `POST /v3/events/batch/` | 600 / 분 | 60초 |

거래 생성과 이벤트 수집은 `generic-write` **대신** `ingest-write`에 포함되어 계산됩니다. 따라서 대량 수집 연동은 다른 쓰기 작업의 한도를 소모하지 않고 API 키당 분당 600개의 요청을 사용할 수 있습니다.

엔드포인트별 제한(다음 섹션)은 전역 제한에 **추가로** 적용됩니다. 가장 먼저 카운터를 초과한 범위가 `429`를 반환합니다.

## 엔드포인트별 제한

미들웨어는 영향이 가장 큰 라우트에 대해 더 엄격한 범위를 정의합니다.

| 범위 | 엔드포인트 | 제한 | 소스 상수 |
| - | - | - | - |
| `session-v2-create` | `POST /v2/session/`, `POST /v3/session/` | 600 / 분 | `SESSION_CREATE_RATE_LIMIT` |
| `session-decision` | `GET /v1/session/<id>/decision/`, `GET /v2/session/<id>/decision/` | 100 / 분 | `SESSION_DECISION_RATE_LIMIT` |
| `session-generate-pdf` | `GET /v1/session/<id>/generate-pdf/`, `GET /v3/session/<id>/generate-pdf/` | 50 / 분 | `SESSION_PDF_RATE_LIMIT` |
| `session-add-images` | `POST`/`PATCH /session/<id>/add-images/` | 10 / 분 | `SESSION_ADD_IMAGES_RATE_LIMIT` |
| `session-update-kyc` | `POST`/`PATCH /session/<id>/update-data/` | 10 / 분 | `SESSION_UPDATE_KYC_RATE_LIMIT` |
| `session-update-poa` | `POST`/`PATCH /session/<id>/update-poa-data/` | 10 / 분 | `SESSION_UPDATE_POA_RATE_LIMIT` |

> [!NOTE]
>
> `GET /v3/session/<id>/decision/`은 `SessionV3RetrieveView`가 처리하며 `session-decision` 범위에 **포함되지 않습니다**. 이 엔드포인트는 `generic-get`의 분당 600회 상한만 적용받습니다. 분당 100회의 결정 조회 제한은 v1 및 v2 결정 경로에만 적용됩니다.

> [!WARNING]
>
> 코드베이스에는 `FREE_SESSION_RATE_LIMIT = 10`과 `PAID_SESSION_RATE_LIMIT = 600` 상수도 정의되어 있습니다. 이 상수들은 현재 `POST /v3/session/`에 **적용되지 않습니다**. 해당 엔드포인트는 모든 애플리케이션에 대해 단일 `session-v2-create` 제한인 분당 600회를 사용합니다. 이 제한이 문서에서 실제 동작하는 것으로 확인되기 전까지는 워크플로별 무료 요금제 제한을 전제로 용량을 계획하지 마십시오.

## 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` | 카운터가 0으로 초기화되는 Unix 에포크 초 단위 시각입니다. |
| `Retry-After` | 다음 시도 전에 기다려야 하는 초 단위 시간입니다. 대기 후 요청이 항상 다음 윈도우에 도달하도록 올림 처리됩니다. **`429` 응답에만** 포함되며, 모든 요청에 포함되지는 않습니다. |

`X-RateLimit-*` 헤더는 `429` 응답에만 포함됩니다. 현재 성공 응답에는 이 헤더가 포함되지 않습니다. 다음 시도 전 대기 시간으로 `Retry-After` 값(또는 `X-RateLimit-Reset - now`)을 사용하십시오.

## 클라이언트 가이드

* **`Retry-After`를 백오프의 최소 대기 시간으로 사용하십시오.** 여기에 지수 백오프와 지터를 더하십시오(`5s → 10s → 20s → 40s ± random`). 그러면 같은 시점에 `429`를 받은 두 클라이언트가 동시에 재시도하며 동기화되는 일을 막을 수 있습니다.
* **일정 횟수 이후에는 재시도를 중단하십시오.** 소규모 상한(예: 5회)에 도달하면 재시도를 멈추고 오류를 호출한 쪽에 전달한 뒤 팀에 알림을 보내십시오. 지속적인 429 오류는 일시적인 급증이 아니라 보통 제어되지 않는 반복 루프를 의미합니다.
* **작업마다 식별자 하나를 사용하십시오.** 여러 백엔드에서 `x-api-key`를 공유하면 모두 같은 카운터에 합산되어, 요청이 많은 하나의 워크로드가 나머지를 굶길 수 있습니다. 환경, 브랜드 또는 고객별로 별도의 애플리케이션(따라서 별도의 `api_key`)을 발급하십시오. [프로그래밍 방식 등록](https://docs.didit.me/ko/integration/programmatic-registration.md#애플리케이션-관리)을 참고하십시오.
* **결정 조회 결과를 캐시하십시오.** `/decision/` 엔드포인트는 촘촘한 폴링 루프를 위해 설계되지 않았습니다. 실시간 업데이트가 필요하면 [Webhook](https://docs.didit.me/ko/integration/webhooks.md)을 사용하고, `GET /v3/session/<id>/decision/`은 백필이나 감사 목적으로만 호출하십시오.
* **PDF는 오프라인으로 생성하십시오.** PDF 렌더링은 CPU 바운드 작업입니다(분당 50회 상한). 페이지를 조회할 때마다가 아니라, 세션이 최종 상태에 도달한 후 큐에서 실행하십시오.

## 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")
```

## 더 많은 여유가 필요하신가요?

분당 600개 세션으로 충분하지 않다면(예: 마케팅 출시나 백필 작업), [support@didit.me](mailto:support@didit.me)로 이메일을 보내 주십시오. 이메일에는 `application` UUID와 예상 지속 속도 및 순간 속도를 적어 주십시오. 한도 재정의는 애플리케이션 단위로 설정됩니다.


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