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"
}
}
| Campo | Significato |
|---|---|
error.code | Codice stabile nella forma <area>.<reason>. Basa su di esso le diramazioni del tuo codice. |
error.message | Una spiegazione leggibile in inglese. Può essere riformulata in qualsiasi momento; non analizzarla. |
error.details | Dati strutturati sull’errore, come il parametro, un limite o quando ritentare. I suoi campi dipendono dal codice. |
error.request_id | L’ID di questa richiesta, uguale all’intestazione di risposta X-Request-Id. |
error.doc_url | La pagina di questo codice su questo portale. |
detail | La 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
| Stato | Significato |
|---|---|
200, 201, 202, 204 | La richiesta è riuscita. 202 significa che è stata accettata ed è ancora in elaborazione. |
400 | La richiesta è malformata: un parametro, un cursore, metadata o una Idempotency-Key non validi. Correggi la richiesta. |
401 | Nessuna chiave valida. Vedi Autenticazione. |
402 | È stato raggiunto un limite del piano dell’organizzazione, come il numero di schede o lo spazio di archiviazione. |
403 | La chiave è valida ma non può fare questa operazione: manca un ruolo, un ambito o una funzione del piano. |
404 | L’oggetto non esiste, oppure la chiave non può vederlo. |
409 | La richiesta è in conflitto con lo stato attuale: un external_id duplicato, una sincronizzazione aperta, una richiesta con la stessa Idempotency-Key ancora in corso. |
410 | L’oggetto è scaduto, come un caricamento dopo 24 ore, oppure l’endpoint è stato dismesso. |
413 | Il corpo o il file è troppo grande. |
415 | Il tipo di file non è supportato, oppure il suo contenuto non corrisponde al nome. |
422 | La richiesta è ben formata ma non valida: un campo mancante o un valore fuori intervallo. |
429 | Troppe richieste, oppure una quota è esaurita. Vedi Limiti di frequenza e quote. |
500, 502, 503, 504 | Un 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
| Errore | Ritentare? |
|---|---|
| Errore di rete o timeout, nessuna risposta | Sì, con la stessa Idempotency-Key. |
429 | Sì, dopo il numero di secondi indicato in Retry-After. |
500, 502, 503, 504 | Sì, con backoff esponenziale: 1 s, 2 s, 4 s… fino a un minuto, con jitter casuale. |
409 api.idempotency_in_progress | Sì, dopo Retry-After: la prima richiesta con questa chiave è ancora in corso. |
Qualsiasi altro 4xx | No. 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.