Direct naar de inhoud
Sursa Developers

Fouten

Sursa gebruikt HTTP-statuscodes om aan te geven of een request is geslaagd, en een stabiele foutcode om aan te geven waarom niet. Elke foutresponse heeft dezelfde vorm:

{
  "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"
  }
}
VeldBetekenis
error.codeStabiele code in de vorm <area>.<reason>. Laat je code hierop vertakken.
error.messageEen leesbare Engelse uitleg. Die kan op elk moment anders worden geformuleerd; parseer hem niet.
error.detailsGestructureerde gegevens over de fout, zoals de parameter, een limiet of wanneer je het opnieuw kunt proberen. De velden hangen af van de code.
error.request_idDe ID van dit request, gelijk aan de responseheader X-Request-Id.
error.doc_urlDe pagina over deze code op dit portaal.
detailDe eerdere vorm van de fout, behouden voor bestaande integraties. Nieuwe code leest beter error.

Elke code heeft een eigen pagina onder Foutcodes, met de HTTP-status, de velden van details en de endpoints die de code teruggeven. Op de pagina van elk endpoint in de API-referentie staan de codes die dat endpoint kan teruggeven.

HTTP-statussen

StatusBetekenis
200, 201, 202, 204Het request is geslaagd. 202 betekent dat het is geaccepteerd en nog wordt verwerkt.
400Het request is onjuist opgebouwd: een ongeldige parameter, cursor, metadata of Idempotency-Key. Corrigeer het request.
401Geen geldige sleutel. Zie Authenticatie.
402Een limiet van het abonnement van de organisatie is bereikt, zoals het aantal kaarten of de opslag.
403De sleutel is geldig, maar mag dit niet doen: er ontbreekt een rol, een scope of een functie van het abonnement.
404Het object bestaat niet, of de sleutel mag het niet zien.
409Het request is in strijd met de huidige toestand: een dubbele external_id, een open synchronisatie, een request met dezelfde Idempotency-Key dat nog loopt.
410Het object is verlopen, zoals een upload na 24 uur, of de route is buiten gebruik gesteld.
413De body of het bestand is te groot.
415Het bestandstype wordt niet ondersteund, of de inhoud past niet bij de naam.
422Het request is goed opgebouwd, maar ongeldig: een ontbrekend veld of een waarde buiten het bereik.
429Te veel requests, of een quotum is op. Zie Snelheidslimieten en quota.
500, 502, 503, 504Een probleem aan de kant van Sursa. Probeer het later opnieuw.

Validatiefouten

Bij 422 met de code validation.failed somt detail elk veld op dat niet door de validatie kwam, elk met zijn locatie:

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

Welke fouten je opnieuw probeert

FoutOpnieuw proberen?
Netwerkfout of time-out, geen responseJa, met dezelfde Idempotency-Key.
429Ja, na het aantal seconden in Retry-After.
500, 502, 503, 504Ja, met exponentiële backoff: 1 s, 2 s, 4 s… tot een minuut, met willekeurige jitter.
409 api.idempotency_in_progressJa, na Retry-After: het eerste request met deze sleutel loopt nog.
Elke andere 4xxNee. Hetzelfde request mislukt opnieuw; corrigeer het eerst.

Probeer POST- en PATCH-requests alleen opnieuw met een Idempotency-Key, zodat een nieuwe poging na een verloren response geen tweede object kan maken. GET, PUT en DELETE kun je zonder meer opnieuw proberen.

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

Een probleem melden

Elke response, geslaagd of niet, heeft een header X-Request-Id, en elke fout heeft dezelfde waarde in error.request_id. Log die samen met je eigen gegevens over het request. Neem je over een request contact op met de support, stuur dan de request-ID mee: daarmee is het record van dat request direct te vinden.

Omgaan met codes die je niet kent

Er kunnen in elke versie van de API nieuwe foutcodes verschijnen. Behandel een onbekende code op basis van zijn HTTP-status: een onbekende 4xx als een request dat in deze vorm niet zal slagen, een onbekende 5xx als een tijdelijk probleem.