# Autentikasi

Setiap panggilan yang menjalankan model atau membaca permintaan Anda memerlukan kunci API. Katalog (`GET /models`,
`GET /categories`), `POST /quote`, dan dokumen OpenAPI bersifat publik.

## Kunci API

Buat dan cabut kunci di [https://doitong.com/developers/dashboard#keys](https://doitong.com/developers/dashboard#keys). Kunci berbentuk `doitong_`
diikuti 64 karakter heksadesimal dan hanya ditampilkan sekali, saat Anda membuatnya. Kirim kunci di header
`Authorization`:

```bash
curl https://api.doitong.com/v1/account -H "Authorization: Bearer $DOITONG_API_KEY"
```

`X-API-Key: <key>` juga dapat digunakan.

> [!WARNING]
> Simpan kunci di server Anda: siapa pun yang memiliki kunci dapat membelanjakan kredit API yang diizinkan untuk kunci tersebut. Jika kunci bocor,
> cabut kunci itu dan buat yang baru.

Permintaan tanpa kunci mendapatkan `401` dengan kode `missing_api_key`; kunci yang tidak dikenal, telah dicabut, atau kedaluwarsa juga mendapatkan `401`.

## Scope

Setiap kunci memiliki scope. API model memeriksa scope berikut:

| Tindakan | Scope yang diperlukan |
|---|---|
| Menjalankan model, membatalkan permintaan, menghapus file permintaan, mengubah pengaturan penyimpanan | `models:run` (kunci dengan `images:create` atau `videos:create` versi lama juga berfungsi) |
| Membuat URL unggahan | `models:run` atau `media:upload` |
| Membaca permintaan, akun | `models:read` (kunci yang dapat menjalankan model juga dapat membaca) |

Kunci baru mendapatkan `models:read` dan `models:run` secara bawaan. Panggilan tanpa scope yang tepat mendapatkan `403` dengan kode
`insufficient_scope`.

## Anggaran kredit

Sebuah kunci dapat memiliki anggarannya sendiri dalam kredit API (1.000 kredit API = $1), yang ditetapkan oleh pemilik akun: anggaran total,
anggaran harian (24 jam terakhir), atau keduanya. Sebelum pembuatan dikenai biaya, biaya diperiksa terhadap jumlah yang telah dibelanjakan
kunci melalui API ini (setelah dikurangi pengembalian dana). Pembuatan yang akan melampauinya ditolak dengan `402 budget_exceeded` dan tidak
dikenai biaya.

> [!IMPORTANT]
> Penolakan karena anggaran bersifat final: mencoba lagi tidak akan membantu sampai pemilik menaikkan anggaran.

 Kunci tanpa anggaran dapat
membelanjakan hingga saldo API. Secara terpisah, pembuatan yang tidak dapat ditanggung oleh saldo API mendapatkan `402 insufficient_credits`
dengan `top_up_url`.

`GET https://api.doitong.com/v1/account` menampilkan saldo API dan sisa anggaran kunci (keduanya dalam kredit API):

```json 200 OK · akun
{
  "object": "account",
  "credits": 125000,
  "balance": { "credits": 125000, "usd": "125.00" },
  "top_up_url": "https://doitong.com/developers/dashboard#balance",
  "key": {
    "name": "Production server",
    "prefix": "doitong_3fa9c1e...",
    "scopes": ["models:read", "models:run"],
    "budget_remaining": 50000,
    "rate_limit": 3600,
    "rate_limit_remaining": 3571
  },
  "webhook_signing_secret": "whsec_..."
}
```

`budget_remaining` bernilai `null` jika kunci tidak memiliki anggaran sendiri.

## Batas laju

Setiap kunci dapat membuat 3600 permintaan per jam, kecuali batasnya ditetapkan berbeda. Setiap respons terautentikasi menyertakan
status saat ini:

| Header | Arti |
|---|---|
| `X-RateLimit-Limit` | Permintaan yang diizinkan dalam jendela saat ini |
| `X-RateLimit-Remaining` | Permintaan yang tersisa dalam jendela saat ini |
| `X-RateLimit-Reset` | Waktu Unix saat jendela diatur ulang |

Jika melampaui batas, Anda mendapatkan `429` dengan header `Retry-After` (detik). Polling lama dengan `?wait=` dihitung sebagai satu permintaan
per panggilan, sehingga menunggu lebih hemat daripada melakukan polling dengan cepat.

Ada juga batas 10 permintaan yang sedang berlangsung (`queued` atau `running`) per akun. Memulai satu permintaan lagi mengembalikan
`429 too_many_inflight`; mulai lagi setelah salah satunya selesai.
