Error dan batas permintaan
Setiap endpoint melaporkan kegagalan dalam bentuk yang sama, dengan kode yang dapat dibaca mesin dan ID permintaan.
Respons error
Panggilan yang gagal mengembalikan success: false. code bersifat stabil dan ditujukan untuk program, error adalah pesan singkat berbahasa Inggris yang ditujukan untuk manusia, dan request_id mengidentifikasi panggilan tersebut di log kami. param menyebutkan parameter yang bermasalah jika penyebabnya adalah input.
Contoh nyata
Ini adalah respons langsung, diambil dari API saat halaman ini dirender.
{
"success": false,
"error": "coin required",
"code": "INVALID_PARAM",
"request_id": "cb-mwefrq9z-dd537078fe"
}{
"success": false,
"code": "NOT_FOUND",
"error": "unknown endpoint: GET /api/this-endpoint-does-not-exist",
"request_id": "cb-mwefrq9z-bde83eef11"
}Kode error
| Kode | HTTP | Arti | Tindakan |
|---|---|---|---|
| INVALID_PARAM | 400 | Parameter wajib tidak ada atau suatu nilai tidak diterima. `param` menyebutkan nama parameternya jika diketahui. | Jangan mengulang tanpa perubahan; perbaiki permintaannya. |
| UNAUTHORIZED | 401 | Header `CB-API-KEY` dikirim tetapi kuncinya tidak dikenal atau sudah dicabut. Data publik tidak memerlukan kunci — hapus header tersebut atau gunakan kunci yang valid. | Jangan mengulang tanpa perubahan. |
| FORBIDDEN | 403 | Rute ini bukan bagian dari API publik (internal atau khusus akun). | Jangan mengulang. |
| NOT_FOUND | 404 | Rute tidak dikenal, atau koin / bursa / dana yang diminta tidak ada. | Jangan mengulang; periksa path dan pengenal terhadap katalog. |
| RATE_LIMITED | 429 | Jumlah permintaan melebihi batas per menit. `Retry-After` memberikan jumlah detik untuk menunggu. | Tunggu selama `Retry-After`, lalu ulangi dengan backoff. |
| INTERNAL | 500 | Error server yang tidak terduga. Pesannya sengaja dibuat generik; sertakan `request_id` saat melaporkannya. | Ulangi sekali setelah beberapa detik; laporkan beserta ID permintaan jika masih terjadi. |
| UPSTREAM_FAILED | 503 | Sumber data di balik endpoint ini tidak menjawab tepat waktu. Tidak ada angka usang atau angka pengganti yang dikembalikan sebagai gantinya. | Ulangi dengan backoff; periksa halaman status. |
| UNAVAILABLE | 501 / 503 | Dataset untuk sementara belum siap (cache sedang diisi) atau endpoint belum memiliki sumber publik yang sah. | Ulangi nanti; katalog menandai endpoint yang memang tidak tersedia secara desain. |
| REQUEST_FAILED | 200 | Beberapa endpoint lama menjawab HTTP 200 dengan `success: false`. Selalu periksa `success`, bukan hanya status HTTP. | Bergantung pada pesannya; perlakukan sebagai permintaan yang gagal. |
ID permintaan
Setiap respons membawa header X-Request-Id. Respons yang gagal mengulanginya di body sebagai request_id. Respons yang dilayani dari cache edge singkat mengulangi ID permintaan yang menghasilkannya, sehingga ID yang identik pada panggilan berturut-turut berarti Anda menerima salinan dari cache.
Batas permintaan
Batas berlaku per menit, per alamat IP untuk panggilan anonim dan per kunci jika header CB-API-KEY yang valid dikirim. Batasnya adalah 1200 permintaan per menit. Permintaan ikon di bawah /api/coin-icon tidak dihitung.
Header batas permintaan
| Nama | Deskripsi |
|---|---|
| X-Request-Id | Pengidentifikasi permintaan ini. Sertakan dalam laporan bug. |
| X-RateLimit-Limit | Jumlah permintaan yang diizinkan dalam jendela satu menit saat ini. |
| X-RateLimit-Remaining | Sisa permintaan dalam jendela saat ini. |
| X-RateLimit-Reset | Waktu Unix dalam detik saat jendela direset. |
| Retry-After | Dikirim bersama HTTP 429: jumlah detik yang harus ditunggu sebelum mencoba lagi. |
| X-Cache | HIT, STALE, atau MISS untuk cache respons di sisi server. |
Saat Anda melampaui batas
API menjawab HTTP 429 dengan kode RATE_LIMITED. Tunggu selama jumlah detik yang tertera di Retry-After, lalu coba lagi. Polling yang lebih cepat daripada TTL cache suatu endpoint mengembalikan respons cache yang sama, jadi sesuaikan interval polling Anda dengan TTL yang tertera di setiap halaman referensi.
Coba lagi dengan backoff
async function getJson(url, tries = 4) {
for (let i = 0; i < tries; i++) {
const res = await fetch(url);
if (res.status === 429 || res.status >= 500) {
const wait = Number(res.headers.get("Retry-After")) || 2 ** i;
await new Promise((r) => setTimeout(r, wait * 1000));
continue;
}
const body = await res.json();
if (body.success === false) {
throw new Error(body.code + ": " + body.error + " (" + body.request_id + ")");
}
return body;
}
throw new Error("gave up after " + tries + " attempts");
}Tidak ada data bukanlah error
Jika parameternya valid tetapi tidak ada sumber publik yang sah untuk data tersebut, panggilan berhasil dengan HTTP 200: kolom nilainya null, meta.quality bernilai UNAVAILABLE, dan coverage.unavailable mencantumkan alasannya. Tampilkan sebagai tanda pisah. Jangan mengubahnya menjadi 0.
Data usang
Jika kolektor tertinggal, endpoint tetap menyajikan nilai terakhir yang tersimpan dengan meta.is_stale: true sampai nilai itu melewati jendela layak pakai; setelah itu nilainya dikeluarkan dari agregat dan dicantumkan di coverage.stale_excluded.