> ## Documentation Index
> Fetch the complete documentation index at: https://www.emissa.com.ar/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Todos los errores, y qué hacer con cada uno

> De quién es el problema y si se reintenta. La tabla de consulta para cuando tenés un errorCode delante.

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

## La regla de oro

> [!WARNING]
>
> **Un `4xx` de validación nunca deja nada colgado. Un `409`, un `500` o un
> `502` al emitir, sí.** Ante los segundos, consultá los [comprobantes sin
> resolver](https://www.emissa.com.ar/docs/guias/cae-rechazado.md) antes de reintentar.

> [!TIP]
>
> Y la red de seguridad que sirve siempre: **reintentar con la misma clave de
> idempotencia no puede duplicar nada.**

## La forma de todos los errores

Todos tienen la misma, y el id del pedido es el dato que conviene loguear:
identifica el pedido exacto si hay que reportar algo.

```json theme={null}
{
  "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"
}
```

> [!TIP]
>
> `message` es estable y apto para mostrar; **`details` es el que dice la causa
> concreta** y puede cambiar. **No parsees `details`; ramificá por
> `errorCode`.**
>
> En **producción**, `details` no viaja cuando es material de diagnóstico: contá
> con `errorCode` y con lo que la guía de cada error dice cómo recuperar.

> [!NOTE]
>
> **Qué está medido y qué no.** Los códigos marcados con ✅ 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 estado HTTP y el mensaje 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.

## Credenciales y permisos

Son todos tuyos, y ninguno se arregla reintentando — salvo el último.

| Código | HTTP | Qué pasa | Qué hacer |
| - | - | - | - |
| `INVALID_API_KEY` ✅ | 401 | No existe o fue revocada | Revisá que sea entera y siga activa |
| `API_KEY_WRONG_HEADER` ✅ | 401 | La mandaste en `Authorization` | Va en `X-API-Key` |
| `API_KEY_INSUFFICIENT_SCOPE` ✅ | 403 | Le falta un scope | `details` dice cuál. Se crea otra clave |
| `API_KEY_WRONG_MODE` ✅ | 403 | Clave y ambiente no coinciden | Usá la clave del ambiente correcto |
| `API_KEY_INSUFFICIENT_PERMISSIONS` | 403 | La key está restringida a ciertos contribuyentes y quiso dar de alta otro | Usá una key sin restricción. Ver [el reparto](https://www.emissa.com.ar/docs/guias/integracion.md) |
| `API_KEY_PRODUCTO_DISTINTO` | 403 | La key está atada a un producto y `X-Emissa-Producto` es un producto **bien formado pero otro**. Si el valor está mal formado (`INMOS!`) es `400 INVALID_INPUT`: el formato se valida primero | Mandá el producto de la key, o no mandes la cabecera |
| `INSUFFICIENT_TAXPAYER_PERMISSIONS` | 403 | El contribuyente no es de tu organización **o sus productos no incluyen el tuyo** (o no tiene ninguno). Responde igual en los tres casos, a propósito | Revisá el id. Para listar los tuyos: `GET /v1/taxpayers` |
| `API_KEY_NOT_ALLOWED_HERE` ✅ | 403 | La operación exige sesión (webhooks, por ejemplo). **No** es el caso del alta de contribuyentes ni de la carga de credenciales: con key se pueden | Se hace desde el panel. Ver [el reparto](https://www.emissa.com.ar/docs/guias/integracion.md) |
| `RATE_LIMIT_EXCEEDED` ✅ | 429 | Demasiados pedidos | **Éste sí se reintenta**: esperá lo que dice `Retry-After` |

> [!TIP]
>
> **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 cuánto te queda podés bajar el ritmo antes de chocar.

> [accordion] El rate limit, medido
>
> Es el único límite **duro** que vas a encontrar operando normalmente. Sobre la
> búsqueda de comprobantes, con 135 pedidos seguidos:
>
> ```
> 120 respuestas 200
>  15 respuestas 429
> ```
>
> Y el `429` trae todo lo que hace falta para reintentar bien:
>
> ```json theme={null}
> {
>   "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
> ```
>
> 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.

### El alta de un contribuyente que ya existe

`POST /v1/taxpayers` con un CUIT que ya está dado de alta en ese ambiente devuelve
`409 RESOURCE_ALREADY_EXISTS`. **Si el contribuyente incluye tu producto entre los suyos
(puede ser de varios), la respuesta trae su id en `details.taxpayerId`, también en
producción** —es un dato contractual, no de diagnóstico—:

```json theme={null}
{
  "statusCode": 409,
  "errorCode": "RESOURCE_ALREADY_EXISTS",
  "details": { "taxpayerId": "cmt42x6jb000curi4sz1gyeij" }
}
```

Si el contribuyente existe pero **no incluye tu producto**, no tiene ninguno o es de otra
organización, el `409` viene **sin id**: el CUIT está tomado pero no es uno que tu key
alcance, y el id de un contribuyente ajeno no se informa. **El `409` tampoco te suma a ese
contribuyente**: sumar un producto a un contribuyente existente lo hace el dueño de la cuenta
desde el panel. Con una key **sin** producto, el id viaja para los contribuyentes de tu
organización. Ver la sección «Varios productos en una organización» de
[la guía de integración](https://www.emissa.com.ar/docs/guias/integracion.md).

## La cuenta

Dos códigos, los dos `402`, y **ninguno se reintenta**.

| Código | HTTP | Qué pasa | Qué hacer |
| - | - | - | - |
| `BILLING_PAST_DUE` | 402 | Suspendida por falta de pago | Regularizar desde **Facturación**. No reintentar |
| `BILLING_PLAN_WITHOUT_API` | 402 | El plan no incluye API | Cambiar de plan. Ver [los planes](https://www.emissa.com.ar/docs/guias/planes-y-produccion.md) |

> [!NOTE]
>
> Un `402` **no es transitorio**: no describe un pedido que salió mal sino una
> condición de la cuenta, así que reintentarlo en bucle sólo gasta cuota de rate
> limit. Los dos traen `details` con el motivo y cómo resolverlo, justamente
> para que se pueda distinguir eso sin parsear texto.

### La mora es la única causal de bloqueo que existe

> [!TIP]
>
> **Excederse de la cuota no bloquea nada** — ver la regla 3 de [los
> planes](https://www.emissa.com.ar/docs/guias/planes-y-produccion.md). Lo único que bloquea es la mora
> sostenida, y llega con **15 días de aviso** por correo. El ciclo completo está
> en [cómo se te cobra](https://www.emissa.com.ar/docs/guias/como-se-te-cobra.md).

Y bloquea poco: alcanza a **emitir y anular**, nada más. Consultar comprobantes,
descargar PDF y leer el consumo siguen funcionando — lo que ya se facturó es
evidencia del cliente, no una función premium que se apague por falta de pago.

> [accordion] Por qué el del plan llega antes de que la key exista
>
> No lo devuelve `/v1`: lo devuelve el panel, al **crear** la API key. Está puesto
> ahí a propósito.
>
> Una key se muestra una sola vez y se guarda; dejarla crear para después rechazar
> cada llamada haría descubrir el límite recién cuando la integración ya está
> escrita, que es el peor momento posible.
>
> Por eso lo vas a ver en el panel y no en una respuesta de la API: si llegaste
> hasta acá con una key en la mano, no es tu caso.

## Antes de llegar a ARCA: lo que Emissa rechaza

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

| Código | HTTP | Qué pasa | Qué hacer |
| - | - | - | - |
| `IDEMPOTENCY_KEY_REQUIRED` ✅ | 400 | Falta el header al emitir | Mandalo. Ver [numeración](https://www.emissa.com.ar/docs/guias/numeracion.md) |
| `IDEMPOTENCY_KEY_REUSED` | 409 | Esa clave se usó para un pedido **distinto** | Clave nueva. Y revisá cómo la derivás |
| `INVALID_INPUT` ✅ | 400 | El cuerpo no valida | `details` trae la lista de campos |
| `INCOMPATIBLE_INVOICE_TYPE` ✅ | 400 | La letra no corresponde | Ver [A, B y C](https://www.emissa.com.ar/docs/guias/tipos-de-comprobante.md) |
| `INVALID_RECEIVER_DOCUMENT` ✅ | 400 | El documento no es válido para su tipo | Revisá el dígito verificador |
| `MISSING_RECEIVER_BUSINESS_NAME` ✅ | 400 | Falta la razón social en una A | Poné el nombre real |
| `INVOICE_DATE_OUT_OF_WINDOW` | 400 | Fecha fuera de la ventana que ARCA acepta | Emití con fecha de hoy |
| `INVOICE_DATE_NOT_MONOTONIC` | 400 | Fecha anterior a la del comprobante previo | La serie no puede ir hacia atrás |
| `CREDENTIALS_REQUIRED` ✅ | 400 | No hay certificado cargado | Cargalo desde el panel |
| `ARCA_SALE_POINT_NOT_ENABLED` | 400 | El punto de venta no está habilitado | Es un alta en ARCA. Ver [punto de venta](https://www.emissa.com.ar/docs/guias/punto-de-venta.md) |
| `TAXPAYER_NOT_FOUND` | 404 | No existe o no es tuyo | Revisá el id |
| `INVOICE_NOT_FOUND` | 404 | No existe o no es tuyo | Revisá el id |

## Estado del comprobante

| Código | HTTP | Qué pasa | Qué hacer |
| - | - | - | - |
| `INVOICE_ALREADY_CANCELLED` | 400 | Ya se anuló | Nada. Es idempotente en la práctica |
| `INVOICE_NOTHING_TO_RECONCILE` ✅ | 409 | Ya tiene estado definitivo | Nada. No había nada que resolver |
| `INVOICE_NOT_AUTHORIZED` | 422 | Se pidió el PDF de uno sin CAE | Reconciliá primero: sin CAE no hay qué imprimir |
| `EXTERNAL_REFERENCE_ALREADY_USED` | 409 | Ya hay un comprobante con esa `externalReference` | Usá el que existe: su id viaja en `details`. Si estaba `REJECTED`, la referencia **no se puede reusar**: mandá otra |

## ARCA

Acá está el que importa. La tabla completa y ejecutada está en
[qué hacer cuando el CAE viene rechazado](https://www.emissa.com.ar/docs/guias/cae-rechazado.md); ésta es la
versión corta.

| Código | HTTP | ¿De quién? | ¿Reintentar? |
| - | - | - | - |
| `ARCA_WSFEV1_REJECTED` ✅ | 422 | Tuyo, casi siempre | Sí, **corrigiendo**. El motivo viaja en `details.arca`, también en producción |
| **`ARCA_CAE_UNKNOWN`** ✅ | **409** | **De nadie: se perdió la respuesta** | **No. Reconciliá primero** |
| `ARCA_WSAA_UNAVAILABLE` | 502 | De ARCA o de la red | Sí, con la misma clave |
| `ARCA_WSFEV1_UNAVAILABLE` | 502 | De ARCA o de la red | Sí, con la misma clave |
| `ARCA_WSAA_REJECTED` | 502 | Del certificado o de la delegación | No sin revisar. `details` trae el motivo |
| `ARCA_TICKET_ALREADY_ISSUED` | 409 | De ARCA | Sí, **esperando unos minutos** |
| `ARCA_INVALID_RESPONSE` | 502 | De ARCA | Mirá los sin resolver antes |
| `ARCA_CATALOG_MISMATCH` | 500 | Nuestro, y es fatal a propósito | Reportalo. No se emite hasta resolverlo |

> [!WARNING]
>
> **`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](https://www.emissa.com.ar/docs/guias/cae-rechazado.md).
>
> La salida es reconciliar, que le pregunta al organismo.

**Cómo encontrás el comprobante si `details` no viaja.** En producción este `409`
llega **sin `details`**: no trae el id del comprobante que quedó sin resolver. Hay
dos caminos, y los dos funcionan sin ese dato:

1. **Si mandaste `externalReference`** (recomendado): buscalo con
   `GET /v1/invoices/search?externalReference=…` y reconciliá con
   `POST /v1/invoices/{id}/reconcile`.
2. **Si no la mandaste:** listá los irresueltos con
   `GET /v1/invoices/unresolved?taxpayerId=…` y reconciliá el que corresponda.

> [!NOTE]
>
> **Una `externalReference` de un comprobante `REJECTED` no se puede reusar.**
> Un rechazo fiscal libera el número, pero el comprobante rechazado sigue
> registrado con su referencia, así que mandarla de nuevo devuelve `409
>     EXTERNAL_REFERENCE_ALREADY_USED`. Para reemitir corregido, mandá una
> referencia nueva —por ejemplo, la original con un sufijo de intento— y una
> `Idempotency-Key` nueva.

### El motivo de un rechazo fiscal viaja siempre

Un `422 ARCA_WSFEV1_REJECTED` **no es un error técnico**: ARCA contestó y dijo que no, y
por qué es información tuya para corregir y reintentar. Por eso, a diferencia del resto
de `details`, **viaja también en producción** (los textos del ejemplo son ilustrativos; los reales son los que devuelve ARCA):

```json theme={null}
{
  "statusCode": 422,
  "errorCode": "ARCA_WSFEV1_REJECTED",
  "message": "ARCA rechazó el comprobante",
  "details": {
    "arca": {
      "errores": [
        { "codigo": 10016, "mensaje": "El campo DocNro es incorrecto." }
      ],
      "observaciones": [
        {
          "codigo": 10048,
          "mensaje": "La condición frente al IVA del receptor está observada."
        }
      ]
    }
  }
}
```

* **El texto es el de ARCA, literal.** Emissa no lo traduce ni lo reescribe: sólo lo
  recorta a 500 caracteres por mensaje y a 20 ítems por lista. Ramificá por `codigo`;
  el `mensaje` es para mostrárselo a quien tiene que corregir.
* **`errores` y `observaciones` son distintas.** Un error es lo que impidió autorizar. Una
  observación es lo que ARCA marcó, y cuando no manda errores suele ser el único motivo:
  por eso a veces `errores` viene vacío.
* **No hay nada de Emissa adentro:** ni el pedido, ni el XML, ni un stack.
* **El mismo motivo** queda en el comprobante (`rechazoArca` en `GET /v1/invoices/{id}` y
  en la búsqueda) y llega en el webhook `invoice.resolved` cuando el estado final es
  `REJECTED` (`data.rechazoArca`). Con la misma forma.
* **No aplica a los demás errores.** `ARCA_CAE_UNKNOWN`, los errores de validación de
  Emissa y los técnicos siguen sin `details` de diagnóstico en producción.

## 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: dice «Error interno del servidor» y nada más.

> [!WARNING]
>
> Medido: el comprobante quedó sin resolver, apareció en la lista de irresueltos
> y se destrabó reconciliando. Así que **ante un `500` al emitir, mirá los sin
> resolver** en vez de reintentar. Es la misma precaución que el `409`, con un
> mensaje que no la sugiere.

## Qué sigue

> [card] [Cuando el CAE viene rechazado](https://www.emissa.com.ar/docs/guias/cae-rechazado.md)
>
> Los cuatro desenlaces, ejecutados.

> [card] [Referencia de la API](https://www.emissa.com.ar/docs/api-reference)
>
> Qué código de error declara cada operación.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.