Cómo se numera una serie
La numeración de comprobantes es correlativa y sin huecos, por punto de venta y
por tipo. No es una convención administrativa: ARCA rechaza el comprobante N+1 si
el N nunca existió, y una serie trabada no se destraba reintentando.
Esta guía es sobre lo que Emissa hace por vos y sobre la única cosa que tenés que
hacer bien: mandar Idempotency-Key.
Una serie por punto de venta y por tipo
Cada combinación de punto de venta y tipo de comprobante lleva su propio contador
independiente. Está desarrollado en
qué es un punto de venta: tres emisiones desde el
mismo punto de venta 0001 quedaron en 0001-00000131 (Factura B),
0001-00000033 (nota de crédito B) y 0001-00000003 (Factura A).
Por qué un hueco no es un detalle
Una serie fiscal es una sucesión, y ARCA la valida como tal. Si tu sistema pide el número 7 cuando ARCA registró hasta el 5, el organismo rechaza con el error 10016 —el número no es el que corresponde— y el rechazo no arregla nada: al siguiente intento el desfasaje sigue igual, o peor.
Ese modo de falla se midió en este proyecto: contando los comprobantes rechazados como si ocuparan número, cada intento empeoraba el desfasaje en uno y la serie de homologación se fue de 4 a 521 sin volver a emitir. Es la razón por la que las reglas de abajo existen y no son celo de más.
Quién decide el número
ARCA, no Emissa. Antes de cada emisión se consulta FECompUltimoAutorizado,
que es el último número que el organismo tiene autorizado en esa serie, y se sigue
desde ahí.
Es deliberado y tiene una consecuencia útil: si alguien emitió desde otro sistema con el mismo punto de venta, ARCA está adelante, y seguir por la cuenta local produciría un rechazo. Preguntándole al organismo, la serie converge sola.
Adentro se toma el mayor entre el número de ARCA y el último local, así que ninguna de las dos fuentes puede hacerte retroceder.
Dos pedidos al mismo tiempo
Ésta es la parte que un integrador necesita saber para no escribir un lock propio: no hace falta. Emissa serializa la asignación del número.
Tres emisiones lanzadas en paralelo contra el mismo contribuyente y la misma
serie, con tres Idempotency-Key distintas:
concurrente-1 [HTTP 201] [0,22 s] 0001-00000133 cae 86300697123075
concurrente-2 [HTTP 201] [2,21 s] 0001-00000134 cae 86300697123135
concurrente-3 [HTTP 201] [2,49 s] 0001-00000135 cae 86300697123148
Tres números consecutivos, tres CAE distintos, ninguna colisión. Y contando en la base después:
number | status | cae
132 | AUTHORIZED | 86300697121691
133 | AUTHORIZED | 86300697123075
134 | AUTHORIZED | 86300697123135
135 | AUTHORIZED | 86300697123148
números repetidos: 0 filas
CAE repetidos: 0 filas
Los tiempos cuentan la historia: el primero entró y salió en 0,22 s, los otros dos esperaron su turno. Eso es el lock funcionando, y es lo que garantiza que la serie no tenga ni saltos ni repetidos.
Lo que se serializa es más chico de lo que parece
Sólo resolver el número y escribir la fila ocurre dentro del lock. La consulta a ARCA y el pedido de CAE quedan afuera:
[ afuera ] FECompUltimoAutorizado
[ ADENTRO ] lock → último local → número → INSERT → commit
[ afuera ] FECAESolicitar y guardado del CAE
Por qué importa para vos: si el pedido de CAE —que puede tardar segundos— estuviera
adentro, dos clientes del mismo contribuyente emitiendo a la vez se esperarían
uno al otro todo ese tiempo. Con la sección crítica acotada, el segundo espera lo
que tarda un INSERT.
El estado del comprobante decide si su número se libera
Acá hay una asimetría que conviene entender, porque explica qué pasa después de un fallo:
| Estado | ¿Ocupa número? | Por qué |
|---|---|---|
AUTHORIZED | Sí | ARCA lo registró. Es definitivo |
REJECTED | No | ARCA nunca lo registró: del otro lado ese número sigue libre |
PENDING | Sí | No se sabe si ARCA lo registró |
UNKNOWN | Sí | No se sabe si ARCA lo registró |
Un REJECTED no cuenta y su fila se borra para liberar el número. Si contara,
sería exactamente el caso del 4 al 521 de más arriba.
PENDING y UNKNOWN sí cuentan, y es la regla más importante de esta guía. De
esos no se sabe si el organismo los registró, así que reutilizar su número podría
duplicar un comprobante fiscal. Se resuelven preguntándole a ARCA con
POST /v1/invoices/{id}/reconcile; si la respuesta es que no existe, pasan a
REJECTED y recién entonces su número vuelve a estar disponible.
Los que quedaron en ese limbo se listan con GET /v1/invoices/unresolved:
curl "https://api.emissa.com.ar/v1/invoices/unresolved?taxpayerId=TU_TAXPAYER_ID" \
-H "X-API-Key: $EMISSA_API_KEY"
[]
Vacío es lo que querés ver. Qué hacer cuando no lo está está en qué hacer cuando el CAE viene rechazado.
Idempotency-Key es obligatorio, y por qué
Es el único requisito que la numeración te impone. Sin el header, el pedido no entra:
{
"statusCode": 400,
"errorCode": "IDEMPOTENCY_KEY_REQUIRED",
"message": "Falta el header Idempotency-Key. Es obligatorio en las operaciones que emiten un comprobante."
}
No es burocracia y no es opcional por una razón concreta: un comprobante fiscal
duplicado no se deshace. No hay DELETE. Lo único que se puede hacer es emitir
una nota de crédito que lo anule, y las dos cosas —la factura de más y su nota—
quedan en tu historia y en la de ARCA para siempre.
Con la clave, repetir el mismo pedido devuelve el mismo comprobante:
HTTP 201 · Idempotent-Replay: true · 0,02 segundos
id devuelto: cms6l4gnq0007ur04xl1dcqf0 | cae: 86300696468093 | number: 131
Mismo id, mismo CAE, mismo número, y no se emitió un segundo: verificado contando en la base, siguió habiendo uno con ese CAE.
Cómo elegir la clave
La clave tiene que identificar la intención de facturar, no el intento. La regla práctica: derivala de algo que ya sea único en tu dominio y que no cambie al reintentar.
- Bien: el id de la suscripción más el período —
sub_8123-2026-07. Si tu proceso corre dos veces, la clave es la misma y el segundo pedido no emite nada. - Mal: un UUID nuevo por intento. Es lo mismo que no mandar nada: cada reintento se ve como una factura distinta.
- Mal: el timestamp. Mismo problema.
Un reintento con una clave distinta es una emisión nueva, y es correcto que lo sea: la API no puede saber que quisiste decir lo mismo.
Qué sigue
- Qué hacer cuando el CAE viene rechazado — los estados
PENDINGyUNKNOWN, y qué se reintenta. - Cómo se arma una integración — el recorrido completo, en orden.