Vai al contenuto
Sursa Developers

Errori

Sursa usa i codici di stato HTTP per dire se una richiesta è riuscita e un codice di errore stabile per dire perché non lo è. Ogni risposta di errore ha la stessa forma:

{
  "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"
  }
}
CampoSignificato
error.codeCodice stabile nella forma <area>.<reason>. Basa su di esso le diramazioni del tuo codice.
error.messageUna spiegazione leggibile in inglese. Può essere riformulata in qualsiasi momento; non analizzarla.
error.detailsDati strutturati sull’errore, come il parametro, un limite o quando ritentare. I suoi campi dipendono dal codice.
error.request_idL’ID di questa richiesta, uguale all’intestazione di risposta X-Request-Id.
error.doc_urlLa pagina di questo codice su questo portale.
detailLa forma precedente dell’errore, mantenuta per le integrazioni esistenti. Il codice nuovo dovrebbe leggere error.

Ogni codice ha la propria pagina in Codici di errore, con il suo stato HTTP, i campi di details e gli endpoint che lo restituiscono. La pagina di ogni endpoint nel riferimento API elenca i codici che quell’endpoint può restituire.

Stati HTTP

StatoSignificato
200, 201, 202, 204La richiesta è riuscita. 202 significa che è stata accettata ed è ancora in elaborazione.
400La richiesta è malformata: un parametro, un cursore, metadata o una Idempotency-Key non validi. Correggi la richiesta.
401Nessuna chiave valida. Vedi Autenticazione.
402È stato raggiunto un limite del piano dell’organizzazione, come il numero di schede o lo spazio di archiviazione.
403La chiave è valida ma non può fare questa operazione: manca un ruolo, un ambito o una funzione del piano.
404L’oggetto non esiste, oppure la chiave non può vederlo.
409La richiesta è in conflitto con lo stato attuale: un external_id duplicato, una sincronizzazione aperta, una richiesta con la stessa Idempotency-Key ancora in corso.
410L’oggetto è scaduto, come un caricamento dopo 24 ore, oppure l’endpoint è stato dismesso.
413Il corpo o il file è troppo grande.
415Il tipo di file non è supportato, oppure il suo contenuto non corrisponde al nome.
422La richiesta è ben formata ma non valida: un campo mancante o un valore fuori intervallo.
429Troppe richieste, oppure una quota è esaurita. Vedi Limiti di frequenza e quote.
500, 502, 503, 504Un problema dal lato di Sursa. Riprova più tardi.

Errori di validazione

Per un 422 con il codice validation.failed, detail elenca ogni campo non valido, ciascuno con la sua posizione:

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

Quali errori ritentare

ErroreRitentare?
Errore di rete o timeout, nessuna rispostaSì, con la stessa Idempotency-Key.
429Sì, dopo il numero di secondi indicato in Retry-After.
500, 502, 503, 504Sì, con backoff esponenziale: 1 s, 2 s, 4 s… fino a un minuto, con jitter casuale.
409 api.idempotency_in_progressSì, dopo Retry-After: la prima richiesta con questa chiave è ancora in corso.
Qualsiasi altro 4xxNo. La stessa richiesta non riuscirà di nuovo; prima correggila.

Ritenta le richieste POST e PATCH solo con una Idempotency-Key, così un nuovo tentativo dopo una risposta persa non può creare un secondo oggetto. GET, PUT e DELETE si possono ritentare così come sono.

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

Segnalare un problema

Ogni risposta, riuscita o no, ha un’intestazione X-Request-Id, e ogni errore ha lo stesso valore in error.request_id. Registralo insieme ai tuoi dati sulla richiesta. Quando contatti l’assistenza per una richiesta, invia il suo ID: porta direttamente al registro di quella richiesta.

Gestire codici che non conosci

Nuovi codici di errore possono comparire in qualsiasi versione dell’API. Tratta un codice sconosciuto in base al suo stato HTTP: un 4xx sconosciuto come una richiesta che così com’è non riuscirà, un 5xx sconosciuto come un problema temporaneo.