Skip to main content
El quickstart muestra que se puede emitir en cuatro pedidos. Esta guía es lo otro: el recorrido entero de un producto que factura a sus clientes, en orden, con la decisión que hay que tomar en cada paso.
Todas las respuestas de esta guía se ejecutaron contra la API.

Antes de escribir código: el reparto

Hay una división que conviene entender primero porque determina la arquitectura de tu integración, y no se deduce leyendo la lista de endpoints.
En el panel, con sesión y segundo factor: crear API keys, registrar webhooks y mover miembros. Con API key: dar de alta contribuyentes, cargar certificados, emitir, consultar, anular y bajar el PDF.

Qué se hace sólo en el panel y qué con una API key

El reparto es de seguridad, no de capacidad. Con una API key se puede dar de alta un contribuyente y cargar un certificado —el primero desde la 5.33, el segundo desde la 5.35—, siempre que la key tenga el scope que corresponde. Lo que sólo se hace desde el panel, con sesión y segundo factor, es lo que reconstruye o amplía el acceso: crear otras keys, mover miembros y registrar webhooks.
La consecuencia de diseño: si tu producto factura en nombre de muchos contribuyentes, el alta de cada CUIT lo puede hacer tu backend como parte del onboarding de cada cliente. No hace falta que una persona entre al panel por cada uno. El certificado propio es opcional. Un contribuyente que autoriza a Emissa en ARCA (la delegación del servicio de facturación a la CUIT de Emissa) emite firmando con el certificado de la plataforma, sin que cargues ninguno. Si cargás uno propio, ése gana y no depende de la delegación. Lo que no se automatiza desde Emissa es la autorización en sí: es un trámite que hace el contribuyente con su clave fiscal, en ARCA, una vez por CUIT. El diagnóstico de conexión te devuelve en cuitAAutorizar cuál es la CUIT a autorizar.
Una key restringida no puede dar de alta contribuyentes. Si pudiera, el contribuyente nuevo quedaría fuera de su lista y lo podría operar igual, escapándose de su propia restricción. Recibe 403 API_KEY_INSUFFICIENT_PERMISSIONS. Para el alta por API, creá una key sin restricción de contribuyentes.
Sin el scope taxpayer:write, el alta devuelve el scope que falta:
Con el scope pero con la key restringida a algunos contribuyentes, el código es API_KEY_INSUFFICIENT_PERMISSIONS. Y lo que sí es del panel —registrar un webhook, por ejemplo— devuelve 403 API_KEY_NOT_ALLOWED_HERE, con el mensaje «Esta operación no se puede hacer con API key: requiere una sesión de usuario».

1 · El contribuyente

Se da de alta desde el panel o con POST /v1/taxpayers y una key con taxpayer:write. Los datos son los que van impresos en el comprobante, así que salen de la constancia de inscripción del CUIT, no de lo que uno recuerda. Las tres decisiones de este paso:
Empezá en homologación: da CAE real y no tiene consecuencia fiscal.

2 · El certificado

Desde el panel o con POST /v1/arca/credentials y una key con credential:write: el .crt que te dio ARCA y su clave privada. Es opcional si el contribuyente autorizó a Emissa en ARCA. Emissa los guarda cifrados y los usa para firmar cada pedido; la clave privada no vuelve a salir.
La credencial es por contribuyente y por ambiente. El certificado de homologación y el productivo son dos cargas distintas sobre el mismo CUIT, y cargar uno no reemplaza al otro.
Al consultar las credenciales, la API devuelve sólo metadatos —sujeto, emisor, número de serie, huella, vigencia y estado—. Y revocar una credencial no la borra: el rastro de qué certificado estuvo activo y hasta cuándo es lo que permite reconstruir con qué se firmó cada comprobante.

3 · La API key

Acá se toman las dos decisiones que más se arrepienten después.

El modo

test opera contra homologación, live contra producción.
La respuesta trae X-Emissa-Mode en cada pedido: logueá esa cabecera desde el primer día. Es la forma de darte cuenta de que estás en el ambiente equivocado antes de que lo note tu cliente.

Los scopes

Pedí sólo los que tu proceso usa.
Recomendación concreta: si tu proceso de facturación no anula, no le pongas invoice:cancel. Y si tenés un proceso de reportes aparte, dale su propia key con invoice:read nada más.
Hay scopes que no se pueden pedir nunca: crear otras keys y mover miembros. Una key con eso sería una credencial de alcance ilimitado disfrazada de integración: alcanzaría con filtrarla una vez para tener acceso permanente.
Esa respuesta es de una clave con invoice:read solamente, intentando anular. La misma clave intentando emitir devuelve La API key no declara invoice:write.

De dónde sale el id del contribuyente

Todas las operaciones de emisión lo piden, y no es el CUIT. Con la clave ya creada, GET /v1/taxpayers lista tus contribuyentes con su id (alcanza con taxpayer:read), y ?cuit= encuentra el de un CUIT puntual, con o sin guiones. Si justo lo estás dando de alta y ya existía, el 409 del alta trae el id: mirá la sección «Varios productos en una organización», más abajo.
Guardalo junto a tu configuración: es estable y lo vas a usar en cada emisión.

Identificá tu producto

Si tu cuenta de Emissa sirve a más de un producto —o querés separar el consumo de cada integración—, mandá en cada pedido la cabecera X-Emissa-Producto con el nombre de tu producto:
  • Es opcional y sólo vale con API key. Sin ella, o vacía, el producto queda en null.
  • Formato: de 1 a 32 caracteres entre minúsculas, números y guiones (^[a-z0-9-]{1,32}$). Cualquier otra cosa devuelve 400 INVALID_INPUT, con el formato esperado en el mensaje.
  • Se estampa al emitir y no cambia. Un reintento con la misma Idempotency-Key devuelve el comprobante original aunque mandes otra etiqueta.
  • Dónde la leés después: el comprobante trae producto; GET /v1/invoices/search?producto=inmos filtra; GET /v1/consumo suma porProducto ([{ producto, total, billable }]) y acepta ?producto=; el evento invoice.resolved trae producto en data; y el registro de pedidos del panel se puede filtrar por producto.
Con una key sin producto, es atribución y no autorización. No cambia lo que la key puede hacer, y cualquiera con la key puede mandar cualquier valor: no lo uses para decidir quién puede qué. Con una key atada a un producto sí restringe, y la cabecera deja de ser opcional en un sentido: ver la sección de abajo.

Varios productos en una organización

Si más de un producto tuyo (inmos, define…) opera dentro de una sola organización de Emissa, la cabecera sola no alcanza: cualquier key llega a todos los contribuyentes de la organización. Para que el de un producto no vea ni opere los de otro, atá la key al producto. 1. Atá la key. En el panel, al crear la key, completá Producto (inmos). Una key que ya existía se puede atar una sola vez, desde la misma pantalla; después no se cambia. Si te equivocás, creás otra. 2. Qué cambia para esa key:
  • Cada pedido queda etiquetado con ese producto, mandes o no X-Emissa-Producto. Si mandás otro valor, la respuesta es 403 API_KEY_PRODUCTO_DISTINTO y no se hace nada. Antes se mira el formato: una cabecera mal formada (INMOS!, con mayúsculas, con espacios, de más de 32 caracteres) es 400 INVALID_INPUT, no 403. Un valor que no es un producto no es «otro producto»: el 403 mandaría a revisar la key cuando lo que está mal es la cabecera. Gana el formato; la comparación con la key viene después.
  • Sólo ve y opera los contribuyentes que incluyen su producto: emitir, anular, reconciliar, buscar, exportar, el PDF, verificar la conexión, las credenciales, el logo y el consumo. Un contribuyente sin tu producto entre los suyos, o sin ninguno, responde 403 INSUFFICIENT_TAXPAYER_PERMISSIONS: igual que uno de otra organización, a propósito. Decir «es de otro producto» confirmaría que ese id existe.
  • Se combina con la restricción por contribuyentes: si además la key está acotada a una lista, la lista sigue valiendo.
3. Un contribuyente puede ser de varios productos. Si el mismo CUIT lo facturan inmos y define, el contribuyente tiene productos: ["inmos", "define"] y las keys de los dos lo operan. Una key de un tercer producto no. Los productos de un contribuyente:
  • Los crea el alta: POST /v1/taxpayers de un CUIT nuevo lo crea con productos = [el producto de tu key] o, si la key no está atada, [el de X-Emissa-Producto].
  • No cambian por API. Sumar o quitar productos lo hace el dueño de la cuenta desde el panel, con auditoría de la lista de antes y la de después. Es también la forma de migrar los contribuyentes que ya existían, que quedaron sin producto.
4. Un CUIT que ya existe. El alta responde 409 y, si el contribuyente incluye tu producto entre los suyos, trae su id en details.taxpayerId —también en producción—:
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 un contribuyente que tu key alcance. Y no te suma a él: una key no se apropia de un contribuyente ajeno. Para que tu producto lo opere, pedile al dueño de la cuenta que lo sume desde el panel. 5. Listar los tuyos. GET /v1/taxpayers devuelve los contribuyentes que tu key ve, paginados como el resto de las listas (pagination.nextCursor), con ?producto=, ?cuit= y ?environment=. Cada fila es la misma que devuelve el alta, más productos. ?producto= filtra por «contiene»: un contribuyente de inmos y define aparece bajo los dos. Una key atada a un producto sólo ve los suyos, aunque pidas otro ?producto=.
producto (singular) está deprecado. La API lo sigue devolviendo un tiempo, con el primer valor de productos, para el cliente que ya lo leía. Con más de un producto no dice cuáles son los demás: leé productos.
6. Un contribuyente compartido, y lo que cada key ve. Los comprobantes quedan con el producto de quien los emitió (producto en el comprobante), no con el del contribuyente. Dos cosas a tener presentes:
  • El acceso es por contribuyente, no por comprobante. Si el mismo contribuyente es de inmos y de define, la key de cada uno puede buscar, ver, anular y exportar todos sus comprobantes, también los que emitió el otro producto. Es lo que significa compartir el contribuyente: comparten también la numeración de la serie. Para filtrar lo tuyo, usá ?producto= en la búsqueda.
  • El consumo sí se separa. GET /v1/consumo de una key atada devuelve sólo el consumo de su producto, también sobre un contribuyente compartido; un ?producto= de otro devuelve vacío. La cuota de la organización (organization) sigue siendo una sola.
7. Los webhooks. Cada producto registra su propio endpoint en el panel y le pone su producto. Un comprobante le llega al endpoint del producto que lo emitió, sea cual sea el contribuyente; lo que es del contribuyente (credential.expiring, connection.established) llega a los endpoints de todos sus productos; y lo de la organización (quota.exceeded, api_key.expiring) llega a todos. Un endpoint sin producto es general y recibe todo, como siempre. El detalle, en los webhooks. 8. La Idempotency-Key es única por organización, no por producto. Dos productos que comparten organización comparten también el espacio de claves: si inmos y define mandan la misma clave, el segundo recibe 409 IDEMPOTENCY_KEY_REUSED aunque sean pedidos distintos. No se filtra ningún dato, pero el pedido no se hace. Cada producto tiene que usar un UUID por intento o prefijar la clave con su producto —inmos-sub_8841-2026-10, no sub_8841-2026-10—. Si derivás la clave de tu dominio, el prefijo es lo que la mantiene distinta de la de tu vecino.
Antes de atar una key que ya existe, asignale producto a sus contribuyentes. Desde que se ata, la key deja de ver los que no incluyen ese producto —incluidos los que no tienen ninguno—. Una key sin producto sigue comportándose como siempre y alcanza a toda la organización.

4 · Emitir

La decisión más importante de toda la integración es la clave de idempotencia, y no es la que parece. Derivala de la intención de facturar —el id de la suscripción más el período, por ejemplo— y no de un UUID por intento. Un comprobante fiscal duplicado no se borra. Está desarrollado en cómo se numera una serie.
Si ARCA rechaza el comprobante recibís un 422 ARCA_WSFEV1_REJECTED —un rechazo fiscal, no una falla de Emissa— y el motivo viaja en details.arca, también en producción: { errores: [{ codigo, mensaje }], observaciones: [{ codigo, mensaje }] }. Es el texto literal de ARCA (recortado a 500 caracteres y 20 ítems), pensado para que tu cliente corrija el dato —el receptor, la condición de IVA, la fecha— y reintente. El mismo motivo queda en el comprobante (rechazoArca) y en el webhook invoice.resolved. El detalle está en los errores de la API. Lo que no tenés que hacer: llevar tu propia numeración, ni tomar un lock, ni reservar números. La serie la resuelve Emissa contra ARCA, y está medido que tres emisiones simultáneas salen consecutivas.

5 · Consultar

Tres formas, para tres propósitos distintos:
No uses la exportación para una pantalla ni la búsqueda para conciliar el mes. La primera no pagina y la segunda te haría recorrer cientos de páginas.
La búsqueda devuelve un envelope de dos claves: data, con los comprobantes completos, y pagination. Ésta es la pagination textual de una corrida con limit=2:
Se pagina pasando ese valor como cursor. Verificado: la primera página trajo los comprobantes 135 y 134, y la segunda el 133 y el 132. El orden es descendente por fecha de creación.Un cursor no se desordena cuando entran comprobantes nuevos mientras recorrés, que es lo que sí le pasa a un offset.
NDJSON es un JSON por línea, así que se procesa en streaming sin cargar todo en memoria.

6 · Anular

Un comprobante autorizado no se borra: se anula con una nota de crédito que lo referencia, y Emissa la emite por vos eligiendo el tipo correcto. La nota tiene su propio CAE —es un comprobante fiscal por derecho propio— y la factura original queda anulada conservando el suyo.
La anulación también lleva clave de idempotencia, y tiene que ser distinta de la de la emisión. Si reusás la misma, estás pidiendo «lo mismo que antes», que era emitir.

7 · El PDF

Se genera al pedirlo, así que no hay nada que almacenar de tu lado. Trae el bloque del emisor, el detalle, las leyendas de transparencia fiscal y el QR de la RG 4892.
Pedilo cuando lo necesites, no al emitir. Guardar el PDF te obliga a regenerarlo si algo del formato cambia; guardar el id no.

8 · Lo que puede salir mal y no es culpa tuya

Un pedido a ARCA puede quedarse sin respuesta. Cuando eso pasa, el comprobante no queda ni autorizado ni rechazado: queda en un estado que hay que resolver preguntándole al organismo.
La regla que más importa de toda la integración: ante un comprobante en ese limbo, no reintentes la emisión a ciegas. Reconciliá primero. Reintentar puede duplicar un comprobante fiscal, y eso no se deshace.El detalle de qué error se reintenta y cuál no está en qué hacer cuando el CAE viene rechazado.

El orden, de principio a fin

1

Dar de alta el contribuyente, en el panel

Decidí la condición frente al IVA, el punto de venta y el ambiente.
2

Cargar el certificado, en el panel

Uno por ambiente.
3

Crear la API key

Decidí el modo y los scopes mínimos.
4

Guardar el id de tu contribuyente

Sale del endpoint de consumo. Va con tu configuración.
5

Emitir con una clave de idempotencia derivada de tu dominio

No de un UUID por intento.
6

Guardar el id que devuelve la emisión

Es lo único que necesitás para todo lo demás.
7

Loguear el request id y el modo de cada respuesta

Es lo que hace reportable un problema, y lo que te avisa si estás en el ambiente equivocado.
8

Consultar por id, paginar con cursor, exportar con NDJSON

Cada una para lo suyo.
9

Anular con una clave de idempotencia propia

Distinta de la de la emisión.
10

Revisar los comprobantes sin resolver de forma periódica

Y reconciliar en vez de reintentar.

Qué sigue

Cómo se numera una serie

La idempotencia en detalle.

Cuando el CAE viene rechazado

El árbol de decisión de los errores.