Langsung ke konten
Sursa Developers

Error

Sursa memakai kode status HTTP untuk menyatakan apakah permintaan berhasil, dan kode error yang stabil untuk menyatakan mengapa permintaan tidak berhasil. Setiap respons error memiliki bentuk yang sama:

{
  "detail": "the cursor is malformed or was issued for different filters",
  "error": {
    "code": "api.cursor_invalid",
    "message": "the cursor is malformed or was issued for different filters",
    "details": {"parameter": "cursor"},
    "request_id": "01JB7Q2M4X9V3K8T5N6P0R1S2A",
    "doc_url": "https://developers.sursa.com/errors/api.cursor_invalid"
  }
}
FieldArtinya
error.codeKode stabil dalam bentuk <area>.<reason>. Buat percabangan kode Anda berdasarkan kode ini.
error.messagePenjelasan bahasa Inggris yang mudah dibaca. Susunan katanya dapat berubah kapan saja; jangan menguraikannya.
error.detailsFakta terstruktur tentang error, seperti parameter, batas, atau kapan harus mencoba ulang. Field-nya bergantung pada kode.
error.request_idID permintaan ini, sama dengan header respons X-Request-Id.
error.doc_urlHalaman tentang kode ini di portal ini.
detailBentuk error yang lebih lama, dipertahankan untuk integrasi yang sudah ada. Kode baru sebaiknya membaca error.

Setiap kode memiliki halamannya sendiri di Kode error, dengan status HTTP-nya, field details, dan endpoint yang mengembalikannya. Halaman setiap endpoint di referensi API mencantumkan kode yang dapat dikembalikan endpoint itu.

Status HTTP

StatusArtinya
200, 201, 202, 204Permintaan berhasil. 202 berarti permintaan diterima dan masih diproses.
400Permintaan salah bentuk: parameter, kursor, metadata, atau Idempotency-Key yang tidak benar. Perbaiki permintaannya.
401Tidak ada kunci yang valid. Lihat Autentikasi.
402Batas paket organisasi tercapai, seperti jumlah kartu atau penyimpanan.
403Kunci valid tetapi tidak diizinkan melakukan hal ini: peran, cakupan, atau fitur paket tidak ada.
404Objek tidak ada, atau kunci tidak boleh melihatnya.
409Permintaan bertentangan dengan keadaan saat ini: external_id duplikat, sinkronisasi yang masih terbuka, permintaan dengan Idempotency-Key yang sama masih berjalan.
410Objek sudah kedaluwarsa, seperti unggahan setelah 24 jam, atau rute sudah dihentikan.
413Isi permintaan atau file terlalu besar.
415Jenis file tidak didukung, atau isinya tidak sesuai dengan namanya.
422Permintaan berbentuk benar tetapi tidak valid: field yang tidak ada atau nilai di luar rentang.
429Terlalu banyak permintaan atau kuota sudah habis. Lihat Batas laju dan kuota.
500, 502, 503, 504Masalah di sisi Sursa. Coba lagi nanti.

Error validasi

Untuk 422 dengan kode validation.failed, detail mencantumkan setiap field yang gagal, masing-masing dengan lokasinya:

{
  "detail": [
    {"loc": ["body", "title"], "msg": "String should have at least 1 character", "type": "string_too_short"}
  ],
  "error": {"code": "validation.failed", "message": "request validation failed", "request_id": "01JB7…"}
}

Error mana yang perlu dicoba ulang

ErrorCoba ulang?
Error jaringan atau timeout, tanpa responsYa, dengan Idempotency-Key yang sama.
429Ya, setelah jumlah detik di Retry-After.
500, 502, 503, 504Ya, dengan backoff eksponensial (jeda yang makin panjang): 1 detik, 2 detik, 4 detik… hingga satu menit, dengan jitter (variasi acak).
409 api.idempotency_in_progressYa, setelah Retry-After: permintaan pertama dengan kunci ini masih berjalan.
4xx lainnyaTidak. Permintaan yang sama akan gagal lagi; perbaiki dulu.

Coba ulang permintaan POST dan PATCH hanya dengan Idempotency-Key, agar percobaan ulang setelah respons yang hilang tidak dapat membuat objek kedua. GET, PUT, dan DELETE aman untuk dicoba ulang apa adanya.

// Retries a request on network errors, 429 and 5xx. The same Idempotency-Key is sent on every attempt.
async function withRetries(send, attempts = 5) {
  for (let attempt = 1; ; attempt++) {
    let response;
    try {
      response = await send();
    } catch (error) {
      if (attempt >= attempts) throw error;
    }
    if (response && response.status !== 429 && response.status < 500) return response;
    if (attempt >= attempts) return response;
    const retryAfter = Number(response?.headers.get("Retry-After"));
    const backoff = Math.min(60, 2 ** (attempt - 1)) * (0.8 + Math.random() * 0.4);
    await new Promise((resolve) => setTimeout(resolve, 1000 * (retryAfter || backoff)));
  }
}

const key = crypto.randomUUID();
const response = await withRetries(() =>
  fetch("https://api.sursa.com/v1/cards/text", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SURSA_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": key,
    },
    body: JSON.stringify({ title: "Refund policy", body_markdown: "Refunds take 14 days." }),
  }),
);

Melaporkan masalah

Setiap respons, berhasil atau tidak, memiliki header X-Request-Id, dan setiap error memiliki nilai yang sama di error.request_id. Catat nilai itu bersama catatan permintaan Anda sendiri. Saat Anda menghubungi dukungan tentang sebuah permintaan, kirim ID permintaannya: ID itu langsung mengarah ke catatan permintaan tersebut.

Menangani kode yang tidak Anda kenal

Kode error baru dapat muncul di versi API mana pun. Tangani kode yang tidak dikenal menurut status HTTP-nya: 4xx yang tidak dikenal sebagai permintaan yang tidak akan berhasil apa adanya, 5xx yang tidak dikenal sebagai masalah sementara.