Aller au contenu
Sursa Developers

Erreurs

Sursa indique par le statut HTTP si une requête a réussi et, par un code d’erreur stable, pourquoi elle a échoué. Toutes les réponses d’erreur ont la même forme :

{
  "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"
  }
}
ChampSignification
error.codeCode stable de la forme <area>.<reason>. Faites reposer la logique de votre code sur lui.
error.messageExplication lisible en anglais. Sa formulation peut changer à tout moment : ne l’analysez pas.
error.detailsInformations structurées sur l’erreur, par exemple le paramètre, une limite ou le moment où réessayer. Ses champs dépendent du code.
error.request_idL’identifiant de cette requête, identique à l’en-tête de réponse X-Request-Id.
error.doc_urlLa page consacrée à ce code sur ce portail.
detailL’ancienne forme de l’erreur, conservée pour les intégrations existantes. Le nouveau code doit lire error.

Chaque code a sa propre page dans Codes d’erreur, avec son statut HTTP, les champs de details et les points de terminaison qui le renvoient. La page de chaque point de terminaison dans la référence de l’API liste les codes que ce point de terminaison peut renvoyer.

Statuts HTTP

StatutSignification
200, 201, 202, 204La requête a réussi. 202 signifie qu’elle a été acceptée et qu’elle est encore en cours de traitement.
400La requête est mal formée : paramètre, curseur, metadata ou Idempotency-Key incorrect. Corrigez la requête.
401Pas de clé valide. Voir Authentification.
402Une limite de l’offre de l’organisation est atteinte, par exemple le nombre de fiches ou l’espace de stockage.
403La clé est valide, mais elle n’a pas le droit de faire cela : il manque un rôle, une portée ou une fonctionnalité de l’offre.
404L’objet n’existe pas, ou la clé n’a pas le droit de le voir.
409La requête entre en conflit avec l’état actuel : external_id en double, synchronisation ouverte, requête avec la même clé Idempotency-Key encore en cours.
410L’objet a expiré, par exemple un téléversement après 24 heures, ou la route a été retirée.
413Le corps ou le fichier est trop volumineux.
415Le type de fichier n’est pas pris en charge, ou son contenu ne correspond pas à son nom.
422La requête est bien formée, mais invalide : champ manquant ou valeur hors limites.
429Trop de requêtes, ou un quota est épuisé. Voir Limites de débit et quotas.
500, 502, 503, 504Un problème du côté de Sursa. Réessayez plus tard.

Erreurs de validation

Pour 422 avec le code validation.failed, detail liste chaque champ en erreur, avec son emplacement :

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

Erreurs à réessayer

ErreurRéessayer ?
Erreur réseau ou délai dépassé, sans réponseOui, avec la même clé Idempotency-Key.
429Oui, après le nombre de secondes indiqué dans Retry-After.
500, 502, 503, 504Oui, avec une attente exponentielle : 1 s, 2 s, 4 s… jusqu’à une minute, avec une variation aléatoire (jitter).
409 api.idempotency_in_progressOui, après Retry-After : la première requête avec cette clé est encore en cours.
Tout autre 4xxNon. La même requête échouera de nouveau ; corrigez-la d’abord.

Ne réessayez les requêtes POST et PATCH qu’avec une clé d’idempotence : ainsi, une nouvelle tentative après une réponse perdue ne peut pas créer un second objet. Les requêtes GET, PUT et DELETE peuvent être réessayées telles quelles sans risque.

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

Signaler un problème

Chaque réponse, réussie ou non, contient un en-tête X-Request-Id, et chaque erreur porte la même valeur dans error.request_id. Journalisez-le avec votre propre trace de la requête. Quand vous contactez le support au sujet d’une requête, transmettez son identifiant de requête : il mène directement à la trace de cette requête.

Traiter les codes inconnus

De nouveaux codes d’erreur peuvent apparaître dans n’importe quelle version de l’API. Traitez un code inconnu selon son statut HTTP : un 4xx inconnu comme une requête qui ne réussira pas telle quelle, un 5xx inconnu comme un problème temporaire.