> ## 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.

# Batas Laju API Didit: Limit, Header & Backoff 429

> Batas laju API Didit, header X-RateLimit, backoff Retry-After, cakupan per endpoint, dan penanganan 429. Rencanakan trafik produksi dengan yakin.

## Identifier dan pengecualian

Didit menerapkan beberapa lapisan batas laju untuk menjaga API tetap stabil sekaligus tetap mengizinkan lonjakan lalu lintas yang wajar. Batas diterapkan **per pengidentifikasi**, yaitu `x-api-key` Anda atau, jika tidak ada kunci API yang dikirim, IP klien Anda. Setiap cakupan memiliki penghitung independen dengan jendela geser 60 detik.

Middleware memilih pengidentifikasi batas laju dalam urutan berikut:

1. Header `x-api-key` → penghitung berbasis kunci.
2. Hop pertama `X-Forwarded-For` → penghitung berbasis IP.
3. `REMOTE_ADDR` → penghitung berbasis IP.

Panggilan berikut **melewati** batas laju sepenuhnya:

* Kunci internal `DIDIT_WEBAPP_API_KEY` (hanya digunakan oleh konsol Didit).
* Endpoint yang dilindungi oleh izin `IsValidSession` (lalu lintas sesi embedded/SDK).
* `GET /system/healthcheck` (dilayani oleh `HealthMiddleware` sebelum tumpukan ini).
* Webhook penyedia: Stripe, skrining AML, callback verifikasi wajah, perubahan daftar KYC.

## Batas global

Setiap permintaan yang terautentikasi juga dikelompokkan berdasarkan metode HTTP ke dalam cakupan umum, sehingga setiap rute baru mewarisi batas default yang wajar:

| Cakupan | Metode HTTP | Batas | Jendela |
| - | - | - | - |
| `generic-get` | `GET` | 600 / menit | 60 dtk |
| `generic-write` | `POST`, `PATCH`, `DELETE` | 300 / menit | 60 dtk |
| `ingest-write` | `POST /v3/transactions/`, `POST /v3/events/`, `POST /v3/events/batch/` | 600 / menit | 60 dtk |

Pembuatan transaksi dan ingesti event dihitung ke `ingest-write` **alih-alih** `generic-write`: integrasi dengan ingesti volume tinggi mendapatkan 600 permintaan per menit per kunci API tanpa menghabiskan kuota penulisan lainnya.

Batas khusus endpoint (bagian berikutnya) berlaku **selain** batas global. Cakupan pertama yang melampaui penghitungnya adalah yang mengembalikan `429`.

## Batas khusus endpoint

Middleware mendefinisikan cakupan yang lebih ketat untuk rute dengan dampak terbesar:

| Cakupan | Endpoint | Batas | Konstanta sumber |
| - | - | - | - |
| `session-v2-create` | `POST /v2/session/`, `POST /v3/session/` | 600 / menit | `SESSION_CREATE_RATE_LIMIT` |
| `session-decision` | `GET /v1/session/<id>/decision/`, `GET /v2/session/<id>/decision/` | 100 / menit | `SESSION_DECISION_RATE_LIMIT` |
| `session-generate-pdf` | `GET /v1/session/<id>/generate-pdf/`, `GET /v3/session/<id>/generate-pdf/` | 50 / menit | `SESSION_PDF_RATE_LIMIT` |
| `session-add-images` | `POST`/`PATCH /session/<id>/add-images/` | 10 / menit | `SESSION_ADD_IMAGES_RATE_LIMIT` |
| `session-update-kyc` | `POST`/`PATCH /session/<id>/update-data/` | 10 / menit | `SESSION_UPDATE_KYC_RATE_LIMIT` |
| `session-update-poa` | `POST`/`PATCH /session/<id>/update-poa-data/` | 10 / menit | `SESSION_UPDATE_POA_RATE_LIMIT` |

> [!NOTE]
>
> `GET /v3/session/<id>/decision/` dilayani oleh `SessionV3RetrieveView` dan **tidak** termasuk dalam cakupan `session-decision`. Endpoint ini hanya dibatasi oleh batas maksimum `generic-get` sebesar 600/menit. Pembatasan keputusan 100/menit hanya berlaku pada jalur keputusan v1 dan v2.

> [!WARNING]
>
> Basis kode juga mendefinisikan `FREE_SESSION_RATE_LIMIT = 10` dan `PAID_SESSION_RATE_LIMIT = 600`. Konstanta ini **belum diterapkan** pada `POST /v3/session/`: endpoint tersebut menggunakan satu batas `session-v2-create` sebesar 600/menit untuk setiap aplikasi. Jangan merencanakan kapasitas berdasarkan pembatasan paket gratis per alur kerja sampai hal itu didokumentasikan sebagai aktif.

## Bentuk respons 429

Saat Anda melampaui cakupan mana pun, Anda menerima HTTP `429` dengan isi dan header berikut:

```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."
}
```

| Header | Arti |
| - | - |
| `X-RateLimit-Limit` | Jumlah maksimum permintaan yang diizinkan dalam jendela saat ini untuk cakupan yang terpicu. |
| `X-RateLimit-Remaining` | Sisa permintaan sebelum jendela direset. Dibatasi ke `0` begitu Anda melampaui batas. |
| `X-RateLimit-Reset` | Jumlah detik sejak epoch Unix saat penghitung direset ke nol. |
| `Retry-After` | Jumlah detik untuk menunggu sebelum percobaan berikutnya, dibulatkan ke atas agar setelah menunggu, percobaan selalu berada di jendela berikutnya. Hanya ada di **respons `429`**, tidak di setiap permintaan. |

Header `X-RateLimit-*` hanya dikirim pada respons `429`: respons sukses saat ini tidak menyertakannya. Gunakan nilai `Retry-After` (atau `X-RateLimit-Reset - now`) sebagai jeda sebelum percobaan berikutnya.

## Panduan untuk klien

* **Hormati `Retry-After`** sebagai batas minimum backoff Anda. Di atasnya, terapkan exponential backoff dengan jitter (`5s → 10s → 20s → 40s ± random`) agar dua klien yang menerima `429` pada waktu yang sama tidak tersinkron.
* **Hentikan percobaan ulang** setelah mencapai batas maksimum yang rendah (misalnya 5 percobaan). Teruskan error ke pemanggil dan beri tahu tim Anda. 429 yang terus-menerus biasanya berarti loop yang tidak terkendali, bukan lonjakan sesaat.
* **Gunakan satu pengidentifikasi per beban kerja.** Berbagi `x-api-key` di banyak backend menggabungkannya ke penghitung yang sama, yang dapat membuat satu backend yang ramai dapat membuat yang lainnya kehabisan jatah. Buat aplikasi terpisah (dan karenanya `api_key` terpisah) untuk setiap lingkungan, merek, atau pelanggan. Lihat [Pendaftaran terprogram](https://docs.didit.me/id/integration/programmatic-registration.md#mengelola-aplikasi).
* **Simpan hasil baca keputusan dalam cache.** Endpoint `/decision/` tidak dirancang untuk loop polling yang rapat. Jika Anda memerlukan pembaruan real-time, gunakan [Webhook](https://docs.didit.me/id/integration/webhooks.md) dan hanya panggil `GET /v3/session/<id>/decision/` untuk pengisian data susulan atau audit.
* **Buat PDF secara offline.** Rendering PDF bersifat intensif CPU (batas 50/menit). Picu pembuatan PDF dari antrean setelah sesi mencapai status terminal, bukan pada setiap tampilan halaman.

## Contoh klien yang menangani 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")
```

## Butuh kapasitas tambahan?

Jika 600 sesi per menit tidak cukup, misalnya untuk peluncuran pemasaran atau pengisian data susulan, kirim email ke [support@didit.me](mailto:support@didit.me) dengan UUID `application` Anda serta perkiraan laju berkelanjutan dan laju lonjakan. Pengecualian dikonfigurasi per aplikasi.


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