Forma de un error
Toda respuesta de error (salvo el token endpoint, que usa el formato RFC 6749) lleva data: null y un elemento en errors:
{
"data": null,
"meta": { "api_version": "1", "request_id": "req_…" },
"errors": [
{
"code": "VALIDATION_ERROR",
"message": "El campo owner_uid no forma parte del contrato v1.",
"field": "owner_uid",
"retryable": false
}
]
}- Decide siempre por
code; elmessagees diagnóstico y puede cambiar. fieldseñala el campo, cabecera o parámetro rechazado (jewel.stones.0.quantity,Idempotency-Key,cursor).diagnostic_idaparece en fallos técnicos para que Zafirox localice la causa sin exponerla.- Guarda
meta.request_id(también en la cabeceraX-Request-Id) en tus registros: es la referencia para soporte.
Catálogo
| Código | HTTP | Reintentable | Causa |
|---|---|---|---|
AUTHENTICATION_REQUIRED | 401 | no | Token ausente, mal formado, con firma inválida o vencido |
TOKEN_AUDIENCE_MISMATCH | 401 | no | Token emitido para otro recurso |
CLIENT_CREDENTIALS_INVALID | 401 | no | Credenciales incorrectas al pedir el token |
INVALID_GRANT | 400 | no | code o refresh_token inválido, expirado, ya usado, de otro cliente o con code_verifier/redirect_uri distintos (token endpoint, error: invalid_grant) |
ACCOUNT_LOGIN_REJECTED | 401 | no | La persona no pudo iniciar sesión en «Acceder con Zafirox» (field: INVALID_CREDENTIALS, ACCOUNT_SUSPENDED, ACCOUNT_BLOCKED); sólo lo ve la pantalla de cuentas |
GATEWAY_KEY_INVALID | 403 | no | Paso reservado a la pantalla de cuentas invocado sin su llave; una integración nunca debería recibirlo |
SCOPE_REQUIRED | 403 | no | El token no tiene el scope de la operación |
CLIENT_SCOPE_INVALID | 403 | no | Actor fuera de la empresa, master inactivo o sujeto de escritura fuera del alcance |
CLIENT_ORIGIN_NOT_ALLOWED | 403 | no | Origin no registrado para el cliente |
RESOURCE_NOT_FOUND | 404 | no | El recurso no existe o no pertenece al alcance |
VALIDATION_ERROR | 422 | no | Payload, parámetro, cursor o cabecera inválidos |
BUSINESS_RULE_VIOLATION | 422 | no | Regla de negocio de órdenes (fecha no hábil, urgente sin autorización…) |
IDEMPOTENCY_CONFLICT | 409 | no | Misma Idempotency-Key con otro payload |
CREATION_IN_PROGRESS | 409 | sí | La misma creación sigue en curso |
ORDER_CREATE_VERSION_RETIRED | 410 | no | Creación v1 retirada al publicar v2; cambia al contrato v2 |
order_policy.version | 409 | no | Versión o SHA-256 de política no reconocido |
order_policy.field, order_policy.required | 422 | no | Campo fuera del perfil o dato requerido ausente |
order_policy.weight, order_policy.measurement, order_policy.design | 422 | no | Peso, medida o referencia de diseño inválidos |
order_policy.catalog, order_policy.text, order_policy.delivery | 422 | no | Opción de catálogo, límite de texto o entrega inválida |
RATE_LIMITED | 429 | sí | Límite por cliente superado; respeta Retry-After |
CLIENT_API_DISABLED | 503 | no | La API está apagada por mantenimiento; no reintentes automáticamente, vuelve a intentarlo más tarde |
UPSTREAM_UNAVAILABLE | 503 | sí | Dependencia técnica no disponible; lleva diagnostic_id |
Qué reintentar
- Reintenta sólo errores
retryable: true, timeouts y fallos de red, y únicamente en operaciones idempotentes: todas las lecturas yPOST /api/v2/client/orders**con la mismaIdempotency-Key**. - Espera
Retry-Aftersegundos cuando el servidor lo envía (429, 503); si no, usa una espera creciente. - Nunca reintentes 401, 403, 404, 409
IDEMPOTENCY_CONFLICTni 422: el resultado será el mismo.
Cómo lo hace el SDK
Cada clase de error extiende ZafiroxApiError y conserva code, status, requestId, retryable, field, diagnosticId y retryAfterSeconds:
| Clase | HTTP |
|---|---|
AuthenticationError | 401 |
AuthorizationError | 403 |
NotFoundError | 404 |
ConflictError | 409 |
ValidationError | 422 |
RateLimitError | 429 |
UpstreamError | 5xx |
TransportError | red (NETWORK_ERROR), timeout (TIMEOUT) o envelope inválido (INVALID_ENVELOPE) |
import { ValidationError, RateLimitError, ZafiroxApiError } from '@zafirox/client-sdk';
try {
await client.orders.create(entradaV2, { idempotencyKey: 'pedido-77' }); // SDK v2, pendiente de publicación
} catch (error) {
if (error instanceof ValidationError) {
console.error('Corrige el campo', error.field, error.message);
} else if (error instanceof RateLimitError) {
console.warn('Espera', error.retryAfterSeconds, 's');
} else if (error instanceof ZafiroxApiError) {
console.error(error.code, error.status, error.requestId);
} else {
throw error;
}
}Por defecto el SDK hace dos intentos con 250 ms de espera (o el Retry-After del servidor, tope 5 s). Ajusta retry: { maxAttempts, backoffMs, maxRetryAfterMs } en las opciones del cliente; maxAttempts: 1 desactiva los reintentos.