Errores y reintentos del SDK
Los métodos rechazan su promesa ante un error. Distingue los errores de API, transporte y validación para decidir qué hacer después.
Captura errores
Sección titulada «Captura errores»import { createFactuCatSdk, FactuCatApiError, FactuCatNetworkError,} from '@factucat/sdk'import { z } from 'zod'
const factucat = createFactuCatSdk({ apiKey: process.env.FACTUCAT_API_KEY!,})
try { const cuenta = await factucat.getMe() console.log(cuenta.scopes)} catch (error) { if (error instanceof FactuCatApiError) { console.error({ code: error.code, status: error.status, requestId: error.requestId, }) } else if (error instanceof FactuCatNetworkError) { console.error({ method: error.method, path: error.path, timedOut: error.timedOut, }) } else if (error instanceof z.ZodError) { console.error(error.issues.map(({ path, message }) => ({ path, message }))) } else { throw error }}El ejemplo usa Zod para reconocer errores de validación. Si lo importas en tu aplicación, declara zod como dependencia directa. No se exporta ZodError desde @factucat/sdk.
FactuCatApiError
Sección titulada «FactuCatApiError»Indica una respuesta HTTP de error. Es una subclase de Error exportada por el SDK.
| Propiedad | Tipo | Significado |
|---|---|---|
name |
string |
FactuCatApiError. |
message |
string |
Mensaje devuelto por la API. |
code |
PublicApiErrorCode |
Código estable de error. |
status |
number |
Estado HTTP. |
requestId |
string |
Identificador para investigar la solicitud. |
retryable |
boolean |
Indica si el servidor considera reintentable el error; el SDK no lo reintenta automáticamente. |
Si la respuesta HTTP de error no cumple el contrato, el SDK usa code: 'internal_error', requestId: 'unknown' y conserva el estado HTTP. En ese caso, retryable es true para estados 500 o superiores.
Códigos de error
Sección titulada «Códigos de error»| Código | Qué revisar |
|---|---|
bad_request, invalid_json, validation_error |
Argumentos, JSON o validaciones de negocio. |
missing_api_key, invalid_api_key |
Llave, ambiente, revocación y autenticación. |
missing_scope |
Permisos de la API key. |
plan_required |
Plan Free, Miau o Miau legacy: activa Miau Pro o FactuCat API. |
not_found |
Recurso inexistente, ajeno a la cuenta o no disponible en ese estado. |
method_not_allowed |
Método HTTP no admitido. |
conflict |
Estado del recurso incompatible con la operación. |
idempotency_conflict |
La clave ya se usó con otro contenido. |
idempotency_in_progress |
La solicitud con esa clave sigue en curso. |
missing_idempotency_key |
Código reconocido por el contrato; las mutaciones actuales admiten omitir la clave. |
rate_limit_exceeded |
Límite de solicitudes alcanzado. |
pac_unavailable |
El PAC no responde temporalmente (HTTP 503, retryable: true). Reintenta más tarde con la misma clave de idempotencia. |
internal_error |
Falla interna o respuesta HTTP de error inválida. |
Plan requerido
Sección titulada «Plan requerido»En producción, GET /me y las demás operaciones autenticadas responden 403 plan_required cuando el plan es Free, Miau o Miau legacy. Esos planes no habilitan la API: necesitas Miau Pro o FactuCat API. En sandbox, una llave fc_test_... no exige plan de pago.
No hay un endpoint público para subir de plan, abrir Checkout ni aplicar cupones. Activa el plan en la webapp, en Configuración → Suscripción, y completa el Checkout de Stripe. El consumo del plan API se explica en Consumo y facturación.
Un 409, 429, 500 o 503 se entrega a tu aplicación sin un segundo intento automático. FactuCatApiError no expone los headers HTTP, incluido Retry-After. Para leerlos, utiliza el transporte personalizado.
FactuCatNetworkError
Sección titulada «FactuCatNetworkError»Indica que no se pudo completar la solicitud por un problema de transporte o una cancelación local.
| Propiedad | Tipo | Significado |
|---|---|---|
name |
string |
FactuCatNetworkError. |
message |
string |
Descripción del fallo. |
method |
'GET' | 'POST' | 'PATCH' | 'DELETE' |
Método HTTP de la solicitud. |
path |
string |
Ruta solicitada, incluyendo los filtros de consulta si existen. |
retryable |
boolean |
El SDK lo establece en true; no implica que repetir una operación nueva sea seguro. |
timedOut |
boolean |
El error final tenía nombre AbortError. También puede ocurrir al cancelar manualmente con AbortController. |
cause |
unknown |
Error original, si está disponible. |
Para distinguir una cancelación iniciada por tu aplicación, conserva el signal y revisa su propiedad aborted. No interpretes timedOut como evidencia de que el servidor rechazó la operación.
Validación con Zod
Sección titulada «Validación con Zod»Un ZodError puede producirse antes de enviar una solicitud, por sus argumentos, o después de recibir una respuesta exitosa que no cumple el contrato. El SDK no reintenta estos errores.
La validación local comprueba la forma de los datos. Las reglas fiscales, la pertenencia de recursos, los permisos y el estado del documento se validan en el servidor.
Política de reintentos
Sección titulada «Política de reintentos»| Situación | Comportamiento automático |
|---|---|
| Fallo de red o timeout | Un reintento, con una espera de 250 ms. |
| Mutación que se reintenta | Misma clave de idempotencia y contenido. |
| Consulta GET | Se puede reintentar; no genera clave. |
| Error HTTP o de validación | No se reintenta. |
signal cancelado |
Se interrumpe la espera; no se inicia un reintento si el signal ya estaba cancelado al decidirlo. |
El timeout predeterminado es de 30 segundos por intento. La cancelación de la espera no deshace una operación que el servidor ya recibió.
Recupera un timbrado ambiguo
Sección titulada «Recupera un timbrado ambiguo»Guarda el ID del borrador y tu clave de timbrado antes de llamar a stampDraft(). Si se pierde la respuesta, consulta getInvoice() con ese ID. No crees otro borrador para evadir el error.
La clave generada automáticamente solo se conserva dentro de una llamada del SDK. Para recuperarte desde otro proceso o después de un reinicio, utiliza tu propia clave persistida. Idempotencia y recuperación.