Guías11 de 11

Todos los errores, y qué hacer con cada uno

La referencia declara qué errorCode devuelve cada operación. Esto es lo otro: de quién es el problema y si se reintenta.

Todos los errores tienen la misma forma, y requestId es el dato que conviene loguear: identifica el pedido exacto si hay que reportar algo.

{
  "statusCode": 403,
  "errorCode": "API_KEY_INSUFFICIENT_SCOPE",
  "message": "La API key no tiene el scope necesario para esta operación",
  "details": "La API key no declara invoice:cancel (taxpayer cms6n9hxh0008urbk44g07f66)",
  "requestId": "736e2fff-1d9f-4765-af94-59ee6de84acb",
  "timestamp": "2026-07-29T22:25:10.972Z",
  "path": "/v1/invoices/cms6nk3i2000sur8kk9l20yw6/cancel"
}

message es estable y apto para mostrar; details es el que dice la causa concreta y puede cambiar. No parsees details; parseá errorCode.

Qué está medido y qué no. Los códigos marcados con ✅ en las tablas se provocaron contra la API y la respuesta publicada es la que devolvió. El resto sale del catálogo de errores del código —el statusCode y el message son los declarados— pero no se ejecutaron: varios necesitan que ARCA se caiga o que venza un certificado, y no se pueden forzar a voluntad. La columna "qué hacer" es, en esos casos, la conducta que el propio código documenta.

La regla de oro, en una línea

Un 4xx de validación nunca deja nada colgado. Un 409, un 500 o un 502 al emitir, sí. Ante los segundos, consultá unresolved antes de reintentar.

Y la red de seguridad que sirve siempre: reintentar con la misma Idempotency-Key no puede duplicar nada.

Credenciales y permisos

Son todos tuyos, y ninguno se arregla reintentando.

errorCodeHTTPQué pasaQué hacer
INVALID_API_KEY401La clave no existe o fue revocadaRevisá que sea la clave entera y que siga activa
API_KEY_WRONG_HEADER401La mandaste en AuthorizationVa en X-API-Key
API_KEY_INSUFFICIENT_SCOPE403Le falta un scopedetails dice cuál. Se corrige creando otra clave
API_KEY_WRONG_MODE403Clave test contra contribuyente PRODUCCION, o al revésUsá la clave del ambiente correcto
API_KEY_NOT_ALLOWED_HERE403La operación exige sesión de usuarioSe hace desde el panel. Ver el reparto
RATE_LIMIT_EXCEEDED429Demasiados pedidosÉste sí se reintenta: esperá lo que dice Retry-After

El rate limit, medido

Es el único límite duro que vas a encontrar operando normalmente. Sobre GET /v1/invoices/search, con 135 pedidos seguidos:

120 respuestas 200
 15 respuestas 429

Y el 429 trae todo lo que hace falta para reintentar bien:

{
  "statusCode": 429,
  "errorCode": "RATE_LIMIT_EXCEEDED",
  "message": "Demasiadas peticiones. Reintentá más tarde.",
  "details": { "limite": 120, "reintentarEnSegundos": 60 }
}
Retry-After: 60
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 60

Usá Retry-After, no un backoff inventado. Y las tres cabeceras X-RateLimit-* vienen en todas las respuestas, no sólo en el 429: mirando X-RateLimit-Remaining podés bajar el ritmo antes de chocar.

(El límite exacto depende de la operación: las de emisión tienen el suyo. El valor de X-RateLimit-Limit es el que rige para el pedido que acabás de hacer.)

Antes de llegar a ARCA: lo que Emissa rechaza

Todos 4xx, y todos tienen la misma virtud: no consumen número de comprobante. Es más barato equivocarse acá que en ARCA.

errorCodeHTTPQué pasaQué hacer
IDEMPOTENCY_KEY_REQUIRED400Falta el header al emitirMandalo. Ver numeración
IDEMPOTENCY_KEY_REUSED409Esa clave se usó para un pedido distintoClave nueva. Y revisá cómo la derivás
INVALID_INPUT400El cuerpo no validadetails trae la lista de campos
INCOMPATIBLE_INVOICE_TYPE400La letra no corresponde al emisor o al receptorVer A, B y C
INVALID_RECEIVER_DOCUMENT400El documento no es válido para su tipoRevisá el dígito verificador del CUIT
MISSING_RECEIVER_BUSINESS_NAME400Falta la razón social en una A, o es un marcadorPoné el nombre real
INVOICE_DATE_OUT_OF_WINDOW400La fecha está fuera de la ventana que ARCA aceptaEmití con fecha de hoy
INVOICE_DATE_NOT_MONOTONIC400La fecha es anterior a la del comprobante previo de la serieLa serie no puede ir hacia atrás
CREDENTIALS_REQUIRED400El contribuyente no tiene certificado cargadoCargalo desde el panel
ARCA_SALE_POINT_NOT_ENABLED400El punto de venta no está dado de alta para webserviceEs un alta en ARCA, no un cambio de código. Ver punto de venta
TAXPAYER_NOT_FOUND404El taxpayerId no existe o no es tuyoRevisá el id
INVOICE_NOT_FOUND404El comprobante no existe o no es tuyoRevisá el id

Estado del comprobante

errorCodeHTTPQué pasaQué hacer
INVOICE_ALREADY_CANCELLED400Ya se anulóNada. Es idempotente en la práctica
INVOICE_NOTHING_TO_RECONCILE409Ya tiene estado definitivoNada. No había nada que resolver
INVOICE_NOT_AUTHORIZED422Se pidió el PDF de un comprobante sin CAEReconciliá primero: sin CAE no hay comprobante que imprimir

ARCA

Acá está el que importa. La tabla completa y ejecutada está en qué hacer cuando el CAE viene rechazado; ésta es la versión corta.

errorCodeHTTP¿De quién?¿Reintentar?
ARCA_WSFEV1_REJECTED422Tuyo, casi siempreSí, corrigiendo. El número se liberó
ARCA_CAE_UNKNOWN409De nadie: se perdió la respuestaNO. Reconciliá primero
ARCA_WSAA_UNAVAILABLE502De ARCA o de la redSí, con la misma clave
ARCA_WSFEV1_UNAVAILABLE502De ARCA o de la redSí, con la misma clave
ARCA_WSAA_REJECTED502Del certificado o de la delegaciónNo sin revisar. details trae el faultcode
ARCA_TICKET_ALREADY_ISSUED409De ARCASí, esperando unos minutos. No hay forma de forzarlo
ARCA_INVALID_RESPONSE502De ARCAMirá unresolved antes
ARCA_CATALOG_MISMATCH500Nuestro, y es fatal a propósitoReportalo. No se emite hasta resolverlo

ARCA_CAE_UNKNOWN en dos frases

La respuesta de ARCA se perdió y no se sabe si el comprobante quedó autorizado. Reintentar con una clave nueva puede emitir un segundo comprobante fiscal por la misma venta — está demostrado, con la serie resultante, en la guía del CAE rechazado.

La salida es POST /v1/invoices/{id}/reconcile, que le pregunta al organismo.

Y el que no dice lo que pasa

Un 500 INTERNAL_ERROR al emitir puede dejar un comprobante tomando número, y el mensaje no lo menciona:

{
  "statusCode": 500,
  "errorCode": "INTERNAL_ERROR",
  "message": "Error interno del servidor"
}

Medido: el comprobante quedó en PENDING, apareció en unresolved y se destrabó con reconcile. Así que ante un 500 al emitir, mirá unresolved en vez de reintentar. Es la misma precaución que el 409, con un mensaje que no la sugiere.

Qué sigue