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"
}
}
| Campo | Significado |
|---|---|
error.code | Código estable con la forma <area>.<reason>. Use este campo en las condiciones de su código. |
error.message | Una explicación legible en inglés. Su redacción puede cambiar en cualquier momento; no la analice. |
error.details | Datos estructurados sobre el error, como el parámetro, un límite o cuándo reintentar. Sus campos dependen del código. |
error.request_id | El ID de esta solicitud, el mismo que el encabezado de respuesta X-Request-Id. |
error.doc_url | La página de este código en este portal. |
detail | La 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
| Estado | Significado |
|---|---|
200, 201, 202, 204 | La solicitud se ha completado correctamente. 202 significa que se ha aceptado y todavía se está procesando. |
400 | La solicitud está mal formada: un parámetro, un cursor, metadata o Idempotency-Key incorrectos. Corrija la solicitud. |
401 | No hay una clave válida. Consulte Autenticación. |
402 | Se ha alcanzado un límite del plan de la organización, como el número de tarjetas o el almacenamiento. |
403 | La clave es válida, pero no tiene permiso para hacer esto: falta un rol, un ámbito o una función del plan. |
404 | El objeto no existe o la clave no tiene permiso para verlo. |
409 | La 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. |
410 | El objeto ha caducado, como una subida pasadas 24 horas, o la ruta se ha retirado. |
413 | El cuerpo o el archivo es demasiado grande. |
415 | El tipo de archivo no es compatible o su contenido no coincide con su nombre. |
422 | La solicitud está bien formada, pero no es válida: falta un campo o un valor está fuera de rango. |
429 | Demasiadas solicitudes, o se ha agotado una cuota. Consulte Límites de frecuencia y cuotas. |
500, 502, 503, 504 | Un 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 respuesta | Sí, con la misma Idempotency-Key. |
429 | Sí, después del número de segundos de Retry-After. |
500, 502, 503, 504 | Sí, con espera exponencial: 1 s, 2 s, 4 s… hasta un minuto, con variación aleatoria. |
409 api.idempotency_in_progress | Sí, después de Retry-After: la primera solicitud con esta clave sigue en curso. |
Cualquier otro 4xx | No. 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.