Salt la conținut
Sursa Developers

Erori

Sursa folosește codurile de status HTTP pentru a spune dacă o cerere a reușit și un cod de eroare stabil pentru a spune de ce nu a reușit. Fiecare răspuns de eroare are aceeași formă:

{
  "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"
  }
}
CâmpSemnificație
error.codeCod stabil de forma <area>.<reason>. Ramificați codul după el.
error.messageO explicație lizibilă în engleză. Poate fi reformulată oricând; nu o analizați.
error.detailsDate structurate despre eroare, cum ar fi parametrul, o limită sau momentul reîncercării. Câmpurile depind de cod.
error.request_idIdentificatorul acestei cereri, același ca în antetul de răspuns X-Request-Id.
error.doc_urlPagina despre acest cod din acest portal.
detailForma anterioară a erorii, păstrată pentru integrările existente. Codul nou ar trebui să citească error.

Fiecare cod are propria pagină în Coduri de eroare, cu statusul HTTP, câmpurile din details și endpointurile care îl returnează. Pagina fiecărui endpoint din referința API enumeră codurile pe care le poate returna acel endpoint.

Statusuri HTTP

StatusSemnificație
200, 201, 202, 204Cererea a reușit. 202 înseamnă că a fost acceptată și este încă în curs de procesare.
400Cererea este formată greșit: un parametru, un cursor, metadata sau un Idempotency-Key greșit. Corectați cererea.
401Nu există o cheie validă. Vedeți Autentificare.
402S-a atins o limită a planului organizației, de exemplu numărul de fișe sau spațiul de stocare.
403Cheia este validă, dar nu are voie să facă acest lucru: lipsește un rol, un domeniu de acces sau o funcție a planului.
404Obiectul nu există sau cheia nu are voie să-l vadă.
409Cererea intră în conflict cu starea curentă: un external_id duplicat, o sincronizare deschisă, o cerere cu același Idempotency-Key încă în execuție.
410Obiectul a expirat, de exemplu o încărcare după 24 de ore, sau ruta a fost retrasă.
413Corpul sau fișierul este prea mare.
415Tipul fișierului nu este acceptat sau conținutul lui nu corespunde numelui.
422Cererea este formată corect, dar este invalidă: lipsește un câmp sau o valoare este în afara intervalului.
429Prea multe cereri sau o cotă epuizată. Vedeți Limite de frecvență și cote.
500, 502, 503, 504O problemă din partea Sursa. Reîncercați mai târziu.

Erori de validare

Pentru 422 cu codul validation.failed, detail enumeră fiecare câmp care nu a trecut validarea, fiecare cu locul lui:

{
  "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…"}
}

Ce erori trebuie reîncercate

EroareReîncercați?
Eroare de rețea sau expirare, fără răspunsDa, cu același Idempotency-Key.
429Da, după numărul de secunde din Retry-After.
500, 502, 503, 504Da, cu așteptare exponențială: 1 s, 2 s, 4 s… până la un minut, cu o variație aleatoare (jitter).
409 api.idempotency_in_progressDa, după Retry-After: prima cerere cu această cheie este încă în execuție.
Orice alt 4xxNu. Aceeași cerere va eșua din nou; corectați-o mai întâi.

Reîncercați cererile POST și PATCH doar cu un Idempotency-Key, ca o reîncercare după un răspuns pierdut să nu poată crea un al doilea obiect. GET, PUT și DELETE pot fi reîncercate în siguranță așa cum sunt.

// 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." }),
  }),
);

Raportarea unei probleme

Fiecare răspuns, reușit sau nu, are un antet X-Request-Id, iar fiecare eroare are aceeași valoare în error.request_id. Înregistrați-l în jurnal împreună cu propria evidență a cererii. Când contactați asistența tehnică despre o cerere, trimiteți ID-ul cererii: el duce direct la înregistrarea acelei cereri.

Tratarea codurilor necunoscute

Coduri de eroare noi pot apărea în orice versiune a API-ului. Tratați un cod necunoscut după statusul HTTP: un 4xx necunoscut ca o cerere care nu va reuși așa cum este, un 5xx necunoscut ca o problemă temporară.