Emitir comprobantes por API
Una sola API para emitir facturas, notas de crédito y notas de débito electrónicas en Argentina (ARCA) y Paraguay (SIFEN / e-Kuatia). La emisión es siempre asíncrona: la API responde al instante y el comprobante se autoriza en segundos; te enterás por webhook firmado, por polling o por el link público.
1. Autenticación
Todas las llamadas a /api/v1/* llevan el header X-Api-Key.
Las keys se emiten por integración y tienen una o dos audiencias:
| Audiencia | Permite |
|---|---|
facturauno.issue | Emitir, cancelar, suscribir webhooks — y también todo lo de lectura. |
facturauno.read | Solo consultar (detalle, listado, XML, catálogo). |
Auth inválida o ausente responde 401/403 con cuerpo genérico.
Los errores de negocio tienen siempre la forma
{ "error": "<código>", "detail": "…" }.
curl -s https://api.facturauno.com/api/v1/invoices \
-H "X-Api-Key: $FACTURAUNO_KEY"
2. Emitir un comprobante issue
POST /api/v1/invoices encola la emisión y responde
202 de inmediato. El modelo es NETO: los
unitPrice van sin IVA; el impuesto se calcula por ítem según su
taxRateCode.
curl -s -X POST https://api.facturauno.com/api/v1/invoices \
-H "X-Api-Key: $FACTURAUNO_KEY" -H "Content-Type: application/json" \
-d '{
"issuerId": "0b0e8a1e-1111-2222-3333-444455556666",
"docClass": "INVOICE",
"idempotencyKey": "pedido-84512",
"currency": "PES",
"recipient": {
"docType": "CUIT",
"docNumber": "30123456789",
"name": "Cliente SRL",
"email": "facturas@cliente.com",
"fiscalProfile": { "condicionIVAReceptorId": 1 }
},
"items": [
{ "description": "Servicio de plataforma — julio", "qty": 1,
"unitPrice": 100000.00, "taxRateCode": "IVA_21" }
],
"ar": { "concepto": 2, "servicioDesde": "2026-07-01",
"servicioHasta": "2026-07-31", "vtoPago": "2026-08-15" },
"notifyEmail": "facturas@cliente.com",
"webhookUrl": "https://miapp.com/hooks/facturauno"
}'
Campos del body
| Campo | Detalle |
|---|---|
issuerId | Obligatorio. El emisor (empresa) por el que se factura. |
emissionPointId | Opcional; si el emisor tiene un solo punto de emisión activo, se resuelve solo. |
docClass | INVOICE · CREDIT_NOTE · DEBIT_NOTE. |
docTypeLocal | Opcional. Override del tipo local (AR: CbteTipo "1"/"6"/"11"…). Sin él, el tipo se deriva de la condición fiscal emisor × receptor. |
relatedInvoiceId | Obligatorio en NC/ND: el comprobante que se ajusta (ver §4). |
idempotencyKey | Obligatorio, único por emisor. Reintentá con la misma key sin miedo (abajo). |
externalRef | Opcional. Tu referencia (id de pedido/cobro); vuelve en consultas y webhooks. |
currency | Código de moneda del WS: PES (pesos AR) o DOL (dólares; requiere exchangeRate). |
recipient | Por referencia (recipientId ya validado) o inline: docType (AR: CUIT|CUIL|DNI|CF · PY: RUC con DV|CI|PASAPORTE), docNumber, name, email, address y fiscalProfile.condicionIVAReceptorId (RG 5616 — obligatoria en AR; ids en el catálogo). recipient: null = consumidor final innominado. |
items[] | description, qty, unitPrice NETO, taxRateCode (AR: IVA_21|IVA_10_5|IVA_27|IVA_5|IVA_2_5|IVA_0|EXENTO|NO_GRAVADO · PY: IVA_10|IVA_5|EXENTA|EXONERADO), discountAmount opcional. |
py | Opciones PY: tipoTransaccion (iTipTra 1-13), condicionVenta CONTADO|CREDITO (+plazoCredito), indicadorPresencia (iIndPres) y motivoEmision (iMotEmi de NC/ND). Moneda PYG (entera) o USD (exchangeRate obligatorio). El comprobante autorizado devuelve el CDC de 44 dígitos en authCode y el PDF es el KuDE con QR verificable en e-Kuatia. |
ar | Opciones AR: concepto (1=Productos, 2=Servicios, 3=Ambos — 2/3 exigen servicioDesde/servicioHasta), vtoPago, y condicionIVAReceptorId que pisa la del perfil si viene. |
notifyEmail | Opcional. Al autorizarse, el receptor recibe un mail con el link público. |
webhookUrl | Opcional. URL https adicional para los webhooks de ESTE comprobante (además de tus suscripciones). |
Respuesta
HTTP/1.1 202 Accepted
{ "invoiceId": "6f2b…", "status": "QUEUED", "docTypeLocal": "1",
"publicUrl": "https://facturauno.com/c/<token>" }
idempotencyKey del
mismo emisor devuelve 200 con el comprobante existente — no se re-emite ni
se re-encola. Un canónico inválido responde 422
validation_failed con el detalle.
Estados del ciclo de vida: QUEUED → SENT → AUTHORIZED |
REJECTED (rechazo de la autoridad) · VERIFYING (timeout en vuelo,
se verifica antes de reintentar) · DEAD (agotó reintentos) ·
CANCELED.
3. Consultar issue · read
Detalle (con items y eventos)
curl -s https://api.facturauno.com/api/v1/invoices/{invoiceId} \
-H "X-Api-Key: $FACTURAUNO_KEY"
Devuelve { invoice, items, events }: estado, número, authCode
(CAE) y su vencimiento, totales, pdfStatus, publicUrl y el
historial de transiciones.
Listado con filtros
curl -s "https://api.facturauno.com/api/v1/invoices?issuerId=…&status=AUTHORIZED&from=2026-07-01&page=1&pageSize=30" \
-H "X-Api-Key: $FACTURAUNO_KEY"
Filtros: issuerId, country, status,
docClass, search, from/to. Respuesta
{ total, items }.
XML / payload fiscal
curl -s https://api.facturauno.com/api/v1/invoices/{invoiceId}/xml \
-H "X-Api-Key: $FACTURAUNO_KEY"
Solo con el comprobante AUTHORIZED; antes responde 409
conflict. El PDF no se descarga por la API: se sirve desde el
link público cuando está materializado.
4. Notas de crédito / débito y anulación
Una NC o ND es un POST /api/v1/invoices más, con
docClass: "CREDIT_NOTE" (o DEBIT_NOTE) y el
relatedInvoiceId del comprobante que ajusta — obligatorio.
curl -s -X POST https://api.facturauno.com/api/v1/invoices \
-H "X-Api-Key: $FACTURAUNO_KEY" -H "Content-Type: application/json" \
-d '{ "issuerId": "…", "docClass": "CREDIT_NOTE",
"relatedInvoiceId": "6f2b…", "idempotencyKey": "nc-pedido-84512",
"currency": "PES", "recipient": { … }, "items": [ … ] }'
POST /api/v1/invoices/{id}/cancel sobre un comprobante AR responde
409 use_credit_note a propósito.
En Paraguay sí existe: el mismo endpoint (body opcional
{"reason": "…"}) registra el evento de cancelación ante SIFEN — solo sobre
un DTE AUTHORIZED y dentro de la ventana (48 h la Factura electrónica,
168 h NC/ND, desde la aprobación). Responde 202 con el evento
PENDING; cuando SIFEN lo acepta, el comprobante pasa a
CANCELED y te llega el webhook invoice.canceled. Vencida la
ventana, anulá con nota de crédito como en AR.
5. Webhooks firmados issue
Suscribirse
curl -s -X POST https://api.facturauno.com/api/v1/webhooks/subscriptions \
-H "X-Api-Key: $FACTURAUNO_KEY" -H "Content-Type: application/json" \
-d '{ "url": "https://miapp.com/hooks/facturauno", "events": "*" }'
HTTP/1.1 200 OK
{ "subscriptionId": "…", "url": "https://miapp.com/hooks/facturauno", "events": "*",
"secret": "<base64 — SE MUESTRA UNA SOLA VEZ, guardalo>",
"signature": { "header": "X-FacturaUno-Signature",
"scheme": "t=<unix>,v1=hex(HMACSHA256(secret, '<unix>.' + body))",
"toleranceSeconds": 300 } }
El secret viaja en claro una única vez en esta respuesta y
queda cifrado de nuestro lado. events acepta * o una lista
separada por comas. GET /api/v1/webhooks/subscriptions lista las tuyas
(sin secretos).
Eventos
| Evento | Cuándo |
|---|---|
invoice.authorized | La autoridad fiscal autorizó (hay CAE y link público descargable). |
invoice.rejected | La autoridad rechazó el comprobante. |
invoice.dead | La emisión agotó los reintentos (interviene soporte/admin). |
Entrega y verificación de firma
Cada entrega es un POST JSON con headers
X-FacturaUno-Event y X-FacturaUno-Signature: t=<unixSeconds>,v1=<hex>.
Para verificar: reconstruí "<t>." + body crudo, calculá
HMAC-SHA256 con tu secret, comparalo en tiempo constante con v1 y rechazá si
|ahora − t| > 300 s.
{ "eventType": "invoice.authorized", "invoiceId": "6f2b…", "issuerId": "…",
"country": "AR", "docClass": "INVOICE", "docTypeLocal": "1", "status": "AUTHORIZED",
"number": 1234, "authCode": "75123456789012", "totalAmount": 121000.00,
"currency": "PES", "externalRef": "pedido-84512", "idempotencyKey": "pedido-84512",
"publicUrl": "https://facturauno.com/c/<token>", "at": "2026-08-07T14:03:22Z" }
Respondé 2xx; ante otra cosa reintentamos con backoff (1m, 5m, 15m, 1h, 4h…) hasta 24 h y
después la entrega queda DEAD.
6. Link público del comprobante
Todo comprobante tiene un link https://facturauno.com/c/{token} (viene como
publicUrl en la respuesta de emisión, el detalle, el webhook y el mail al
receptor). Es una página sin login que informa el estado — "en proceso",
autorizada o cancelada — con los datos del comprobante, el CAE y su vencimiento, y los
botones Descargar PDF (/c/{token}/pdf — se habilita cuando el
PDF está materializado, pdfStatus = READY) y XML
(/c/{token}/xml).
- Token opaco criptográficamente aleatorio (anti-enumeración) y revocable por el emisor.
- Rate limit por IP; token inválido o revocado → 404 genérico.
- Con white-label habilitado, el receptor ve la marca del emisor.
7. Catálogo por país issue · read
curl -s https://api.facturauno.com/api/v1/catalog/AR/doctypes \
-H "X-Api-Key: $FACTURAUNO_KEY"
Devuelve los tipos locales soportados, los taxRateCodes válidos y las
tablas de códigos por país — todo lo que necesitás para armar el
IssueRequest sin hardcodear. /catalog/AR/doctypes:
Factura/NC/ND A, B y C + condicionesIvaReceptor (RG 5616).
/catalog/PY/doctypes: Factura (iTiDE 1), NC (5) y ND (6) + las opciones
py (tipoTransaccion, condicionVenta, indicadorPresencia, motivoEmision).