Ir al contenido
Sursa Developers

Errores

Sursa usa los códigos de estado HTTP para indicar si una solicitud se ha completado correctamente, y un código de error estable para indicar por qué no. Todas las respuestas de error tienen la misma 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"
  }
}
CampoSignificado
error.codeCódigo estable con la forma <area>.<reason>. Use este campo en las condiciones de su código.
error.messageUna explicación legible en inglés. Su redacción puede cambiar en cualquier momento; no la analice.
error.detailsDatos estructurados sobre el error, como el parámetro, un límite o cuándo reintentar. Sus campos dependen del código.
error.request_idEl ID de esta solicitud, el mismo que el encabezado de respuesta X-Request-Id.
error.doc_urlLa página de este código en este portal.
detailLa forma anterior del error, que se mantiene para las integraciones existentes. El código nuevo debe leer error.

Cada código tiene su propia página en Códigos de error, con su estado HTTP, los campos de details y los endpoints que lo devuelven. La página de cada endpoint en la referencia de la API enumera los códigos que puede devolver ese endpoint.

Estados HTTP

EstadoSignificado
200, 201, 202, 204La solicitud se ha completado correctamente. 202 significa que se ha aceptado y todavía se está procesando.
400La solicitud está mal formada: un parámetro, un cursor, metadata o Idempotency-Key incorrectos. Corrija la solicitud.
401No hay una clave válida. Consulte Autenticación.
402Se ha alcanzado un límite del plan de la organización, como el número de tarjetas o el almacenamiento.
403La clave es válida, pero no tiene permiso para hacer esto: falta un rol, un ámbito o una función del plan.
404El objeto no existe o la clave no tiene permiso para verlo.
409La solicitud entra en conflicto con el estado actual: un external_id duplicado, una sincronización abierta, una solicitud con la misma Idempotency-Key que sigue en curso.
410El objeto ha caducado, como una subida pasadas 24 horas, o la ruta se ha retirado.
413El cuerpo o el archivo es demasiado grande.
415El tipo de archivo no es compatible o su contenido no coincide con su nombre.
422La solicitud está bien formada, pero no es válida: falta un campo o un valor está fuera de rango.
429Demasiadas solicitudes, o se ha agotado una cuota. Consulte Límites de frecuencia y cuotas.
500, 502, 503, 504Un problema en el lado de Sursa. Vuelva a intentarlo más tarde.

Errores de validación

En un 422 con el código validation.failed, detail enumera todos los campos que no superaron la validación, cada uno con su ubicación:

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

Qué errores reintentar

Error¿Reintentar?
Error de red o tiempo de espera agotado, sin respuestaSí, con la misma Idempotency-Key.
429Sí, después del número de segundos de Retry-After.
500, 502, 503, 504Sí, con espera exponencial: 1 s, 2 s, 4 s… hasta un minuto, con variación aleatoria.
409 api.idempotency_in_progressSí, después de Retry-After: la primera solicitud con esta clave sigue en curso.
Cualquier otro 4xxNo. La misma solicitud volverá a fallar; corríjala primero.

Reintente las solicitudes POST y PATCH solo con una Idempotency-Key, para que un reintento después de una respuesta perdida no pueda crear un segundo objeto. Las solicitudes GET, PUT y DELETE se pueden reintentar tal cual sin riesgo.

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

Informar de un problema

Cada respuesta, correcta o no, tiene un encabezado X-Request-Id, y cada error tiene el mismo valor en error.request_id. Regístrelo junto con su propio registro de la solicitud. Cuando se ponga en contacto con el soporte por una solicitud, envíe su ID de solicitud: lleva directamente al registro de esa solicitud.

Tratar códigos que no conoce

En cualquier versión de la API pueden aparecer códigos de error nuevos. Trate un código desconocido según su estado HTTP: un 4xx desconocido, como una solicitud que no se completará tal como está; un 5xx desconocido, como un problema temporal.