# Error

> Setiap kode error yang dikembalikan Ikiform, beserta status HTTP, penyebab, dan solusinya.

Kiriman formulir dan REST API memakai satu envelope error yang sama. Request JSON mendapatkannya dengan status HTTP yang sesuai; kiriman formulir dari browser mendapat halaman error hosted dengan pesan dan status yang sama.

## Envelope error

`Error`:

```json
{
  "ok": false,
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please slow down."
  },
  "request_id": "req_01k7v2c9t3e8m5q4x6z0a1b2c3"
}
```

- `error.code` stabil; jadikan acuan percabangan. `error.message` berupa bahasa Inggris biasa untuk manusia dan bisa berubah.
- `error.fields` ada pada error validasi, diberi key berdasarkan ID field, masing-masing dengan daftar pesan. Error tentang seluruh body memakai key `_form`.
- `error.challenge_url` ada pada `challenge_required`.
- `request_id` sama dengan header `X-Request-Id` yang dibawa setiap respons.
- Respons yang terkena rate limit membawa `Retry-After` dalam detik. Kedua header bisa dibaca dari kode browser.

## Kode

| Status | Kode | Tempat |
| --- | --- | --- |
| 400 | [`invalid_body`](#invalid-body) | Kirim |
| 400 | [`invalid_request`](#invalid-request) | API |
| 401 | [`unauthorized`](#unauthorized) | API |
| 402 | [`plan_required`](#plan-required) | Kirim |
| 403 | [`forbidden`](#forbidden) | Keduanya |
| 403 | [`origin_not_allowed`](#origin-not-allowed) | Kirim |
| 403 | [`form_paused`](#form-paused) | Kirim |
| 403 | [`captcha_failed`](#captcha-failed) | Kirim |
| 403 | [`challenge_required`](#challenge-required) | Kirim |
| 404 | [`not_found`](#not-found) | Keduanya |
| 405 | [`method_not_allowed`](#method-not-allowed) | API |
| 409 | [`idempotency_in_progress`](#idempotency-in-progress) | Kirim |
| 413 | [`payload_too_large`](#payload-too-large) | Kirim |
| 415 | [`unsupported_media_type`](#unsupported-media-type) | Kirim |
| 415 | [`unsupported_charset`](#unsupported-charset) | Kirim |
| 422 | [`validation_failed`](#validation-failed) | Kirim |
| 422 | [`files_not_supported`](#files-not-supported) | Kirim |
| 422 | [`too_deep`](#too-deep) | Kirim |
| 422 | [`idempotency_mismatch`](#idempotency-mismatch) | Kirim |
| 429 | [`rate_limited`](#rate-limited) | Keduanya |
| 429 | [`quota_exceeded`](#quota-exceeded) | Kirim |
| 500 | [`server_error`](#server-error) | Keduanya |

### 400 invalid_body

|   |   |
| --- | --- |
| Pesan | `The request body could not be read.` |
| Penyebab | JSON atau multipart yang rusak, array atau string JSON alih-alih objek, atau idempotency key lebih dari 255 karakter. |
| Solusi | Kirim satu objek JSON, atau biarkan browser atau `FormData` yang menyusun body. |

### 400 invalid_request

|   |   |
| --- | --- |
| Pesan | `The request is invalid.` |
| Penyebab | `limit`, `status`, `form_id`, atau `cursor` tidak valid. Pesannya menyebut parameternya. |
| Solusi | Gunakan `limit` 1 sampai 100, `status` `received` atau `spam`, ID `frm_` yang nyata, dan cursor persis seperti yang dikembalikan. |

### 401 unauthorized

|   |   |
| --- | --- |
| Pesan | `A valid API key is required.` |
| Penyebab | Tidak ada header `Authorization`, bukan Bearer token, atau key yang tidak dikenal, dicabut, atau kedaluwarsa. |
| Solusi | Kirim `Authorization: Bearer ik_sk_...` dengan secret key yang aktif. |

### 402 plan_required

|   |   |
| --- | --- |
| Pesan | `This form isn't accepting submissions right now.` |
| Penyebab | Workspace tidak punya paket aktif. Ini hanya bisa terjadi setelah penagihan diaktifkan. |
| Solusi | Pilih paket di dashboard pada **Settings**. |

### 403 forbidden

|   |   |
| --- | --- |
| Pesan | `You do not have access to this resource.` |
| Penyebab | Kunci API salah format, milik workspace lain, berupa publishable key di REST API, atau tidak punya scope yang dibutuhkan. |
| Solusi | Gunakan secret key dari workspace ini dengan scope yang disebut di pesan. |

### 403 origin_not_allowed

|   |   |
| --- | --- |
| Pesan | `This form does not accept submissions from this site.` |
| Penyebab | Kiriman berasal dari situs di luar domain yang diizinkan formulir dan formulir menolak ketidakcocokan, atau publishable key dipakai dari domain yang tidak tercantum di key. |
| Solusi | Tambahkan situs ke **Allowed domains** atau ke domain key. Untuk kiriman dari server, gunakan secret key. |

### 403 form_paused

|   |   |
| --- | --- |
| Pesan | `This form is not accepting submissions right now.` |
| Penyebab | Formulir dijeda di dashboard. |
| Solusi | Lanjutkan formulir. |

### 403 captcha_failed

|   |   |
| --- | --- |
| Pesan | `The captcha check failed. Please try again.` |
| Penyebab | Token Turnstile tidak ada, kedaluwarsa, sudah dipakai, atau gagal diverifikasi. |
| Solusi | Ambil token baru untuk setiap kiriman. Dengan key Anda sendiri, pastikan site key cocok dengan secret-nya. |

### 403 challenge_required

|   |   |
| --- | --- |
| Pesan | `Complete the human check, then send the form again.` |
| Penyebab | Formulir memakai pemeriksaan manusia Ikiform dan kiriman JSON tiba tanpa token. |
| Solusi | Panggil `challenge(formId)` dari SDK dan berikan tokennya, atau gunakan `error.challenge_url`. Kiriman dari server bisa mengirim secret key sebagai gantinya. |

### 404 not_found

|   |   |
| --- | --- |
| Pesan | `Not found.` |
| Penyebab | Formulir tidak ada, sudah dihapus atau dinonaktifkan, atau ID atau route-nya salah. Juga dikembalikan untuk `GET` ke `/f/<formId>`. |
| Solusi | Salin endpoint dari ringkasan formulir, dan kirim POST alih-alih membukanya di tab. |

### 405 method_not_allowed

|   |   |
| --- | --- |
| Pesan | `This method is not allowed here.` |
| Penyebab | Preflight browser pada REST API, yang hanya untuk server ke server. |
| Solusi | Panggil `/api/v1` dari backend Anda. |

### 409 idempotency_in_progress

|   |   |
| --- | --- |
| Pesan | `A request with this idempotency key is still being processed.` |
| Penyebab | Request dengan idempotency key ini masih diproses. |
| Solusi | Tunggu sebentar dan coba ulang dengan key yang sama; Anda akan mendapat respons pertama. |

### 413 payload_too_large

|   |   |
| --- | --- |
| Pesan | `The submission is too large.` |
| Penyebab | Body, nama field, nilai, atau jumlah field melewati batasnya. Pesannya menyebut yang mana. |
| Solusi | Lihat [Batas](https://ikiform.com/id/docs/limits.md#submissions). Pecah teks panjang ke beberapa field atau simpan file di tempat lain dan kirim tautannya. |

### 415 unsupported_media_type

|   |   |
| --- | --- |
| Pesan | `Send the form as urlencoded, multipart or JSON.` |
| Penyebab | `Content-Type` bukan urlencoded, multipart, atau JSON, atau tidak ada. |
| Solusi | Atur `Content-Type: application/json` saat mengirim JSON. |

### 415 unsupported_charset

|   |   |
| --- | --- |
| Pesan | `Only UTF-8 is supported.` |
| Penyebab | Body bukan UTF-8, atau mendeklarasikan charset lain. |
| Solusi | Encode sebagai UTF-8. Tambahkan `accept-charset="utf-8"` ke formulir HTML lama. |

### 422 validation_failed

|   |   |
| --- | --- |
| Pesan | `Some fields are invalid.` |
| Penyebab | Field gagal validasi. `error.fields` memetakan ID field ke pesan. |
| Solusi | Tampilkan pesan di samping field. Lihat [Field](https://ikiform.com/id/docs/fields.md#errors). |

### 422 files_not_supported

|   |   |
| --- | --- |
| Pesan | `File uploads are not supported yet.` |
| Penyebab | Kiriman berisi file. Unggah file belum tersedia. |
| Solusi | Hapus input file, atau unggah file di tempat lain dan kirim tautannya. |

### 422 too_deep

|   |   |
| --- | --- |
| Pesan | `The JSON body is nested too deeply.` |
| Penyebab | Body JSON bertingkat lebih dari 3 level, termasuk objek teratas. |
| Solusi | Ratakan datanya, misalnya `{ "address_city": "London" }`. |

### 422 idempotency_mismatch

|   |   |
| --- | --- |
| Pesan | `This idempotency key was already used with a different payload.` |
| Penyebab | Idempotency key ini sudah dipakai untuk formulir ini dalam 24 jam terakhir dengan field yang berbeda. |
| Solusi | Gunakan key baru untuk data baru. Pakai key yang sama hanya untuk percobaan ulang yang persis sama. |

### 429 rate_limited

|   |   |
| --- | --- |
| Pesan | `Too many requests. Please slow down.` |
| Penyebab | Melewati rate limit. `Retry-After` menyebut berapa detik harus menunggu. |
| Solusi | Tunggu dan coba ulang. Jika pengunjung sungguhan mengalaminya, ubah [rate limit](https://ikiform.com/id/docs/rate-limits.md) formulir. |

### 429 quota_exceeded

|   |   |
| --- | --- |
| Pesan | `This form isn't accepting submissions right now.` |
| Penyebab | Workspace menerima 2 kali batas kiriman bulanannya bulan ini. |
| Solusi | Upgrade, atau tunggu bulan berikutnya. Lihat [Pemakaian bulanan](https://ikiform.com/id/docs/limits.md#monthly-usage). |

### 500 server_error

|   |   |
| --- | --- |
| Pesan | `Something went wrong on our side.` |
| Penyebab | Ada yang gagal di pihak Ikiform. |
| Solusi | Coba ulang dengan backoff dan idempotency key. Jika terus terjadi, sertakan `request_id`. |

## Bukan error

- Spam mendapat `201` atau redirect yang sama seperti kiriman asli. Cari di filter spam di dashboard.
- `_redirect` yang tidak diizinkan akan diabaikan, dan browser mendarat di halaman terima kasih hosted.
- `_replyto` yang bukan satu alamat email valid akan diabaikan.

## Mencoba ulang

- Coba ulang `429` setelah `Retry-After`, dan `500`, `409`, atau error jaringan dengan backoff. Kirim [idempotency key](https://ikiform.com/id/docs/frameworks.md#idempotency) agar percobaan ulang tidak pernah membuat duplikat.
- Jangan coba ulang error `4xx` lain tanpa perubahan. Perbaiki request-nya terlebih dahulu.
