API de facturación — Al toque
Guía para integrar la facturación electrónica (ARCA/AFIP) desde tu propia app.
Antes de empezar
La API viene en el plan Pro (y durante los 15 días de prueba).
- Creá tu cuenta en facturaraltoque.com.ar y habilitá ARCA (Configuración → Mi negocio: la guía te lleva paso a paso hasta cargar tu certificado). Sin certificado no se puede emitir.
- Generá tu API key en Configuración → API (una por punto de venta). Se muestra una sola vez — guardala en un lugar seguro. Si la perdés, generás otra (la anterior deja de funcionar).
Base URL
https://facturaraltoque.com.ar/fact/api
Autenticación
Todas las llamadas llevan el header:
X-API-Key: arca_prod_xxxxxxxxxxxxxxxx
La key está atada a un punto de venta. Si operás varios puntos de venta, usás una key distinta por cada uno.
- Sin header o key inválida →
401. - Cuenta inhabilitada (falta de pago) →
403en todo. - Email sin confirmar →
403 email_sin_verificarsolo al emitir. Las cuentas nuevas nacen con el email confirmado (el registro pide un código que llega por mail); si tu cuenta es anterior y te quedó pendiente, se confirma desde Configuración → Mi cuenta. - Prueba/suscripción vencida →
403solo al emitir (podés seguir consultando). - Cupo de comprobantes agotado →
403 limite_alcanzadosolo al emitir. El cupo es de la cuenta, no del punto de venta: todos tus puntos de venta consumen del mismo pozo, y la API y la web comparten ese pozo.
Límite de uso
60 solicitudes por minuto por punto de venta. Si lo superás, recibís 429; esperá unos segundos y reintentá.
Índice de endpoints
Tu punto de venta
Parámetros (lo que necesitás para armar un comprobante)
GET /parametros/condiciones-ivaGET /parametros/tipos-comprobanteGET /parametros/alicuotas-ivaGET /parametros/monedasGET /parametros/cotizacion/:monIdGET /parametros/estado-arca
Emitir
Consultar
Entregarle el comprobante al cliente
Datos auxiliares
GET /padron/:cuit·GET /receptoresGET /itemsy su ABM
Tu punto de venta
GET /emisores/me
Datos del punto de venta asociado a la key (para verificar que la key es correcta).
curl https://facturaraltoque.com.ar/fact/api/emisores/me \
-H "X-API-Key: TU_KEY"
Devuelve además clases (p.ej. ["C"] monotributo, ["A","B"] Responsable Inscripto) y discriminaIva (true/false), para que sepas de entrada qué podés emitir.
Parámetros
Todos vienen filtrados por lo que tu punto de venta puede hacer.
GET /parametros/condiciones-iva
Condiciones de IVA del receptor (id + descripción). Usá el id en condicionIVAReceptorId al emitir.
GET /parametros/tipos-comprobante
Tipos que este emisor puede emitir según su categoría fiscal (id, desc, clase, grupo, seccion, titulo, fce, leyenda). El id va en cbteTipo.
| Comprobante | A | B | C |
|---|---|---|---|
| Factura | 1 | 6 | 11 |
| Nota de débito | 2 | 7 | 12 |
| Nota de crédito | 3 | 8 | 13 |
| Recibo | 4 | 9 | 15 |
| Nota de venta al contado | 5 | 10 | — |
| Factura de Crédito MiPyME (FCE) | 201 | 206 | 211 |
| Nota de débito FCE | 202 | 207 | 212 |
| Nota de crédito FCE | 203 | 208 | 213 |
| A con leyenda (operación sujeta a retención): factura / ND / NC / recibo | 51 / 52 / 53 / 54 | — | — |
Monotributo y exento → la columna C. Responsable Inscripto → A y B. La "A con leyenda" es solo para quien ARCA tiene en ese régimen: a los demás ARCA se la rechaza.
GET /parametros/alicuotas-iva
Alícuotas de IVA (id, tasa, descripcion) para items[].alicuotaIvaId. Contextual: si el emisor no discrimina IVA (Factura C, monotributo/exento) devuelve []. Si es Responsable Inscripto (A/B):
| id | tasa |
|---|---|
| 3 | 0% |
| 8 | 5% |
| 9 | 2,5% |
| 4 | 10,5% |
| 5 | 21% |
| 6 | 27% |
En Factura C el IVA no se discrimina; precioUnitario es el precio final.
GET /parametros/monedas
Monedas vigentes en ARCA (id, desc). El id va en monId al emitir (PES = pesos, es el default).
GET /parametros/cotizacion/:monId
Cotización oficial de ARCA, en vivo. Necesaria para facturar en moneda extranjera.
curl https://facturaraltoque.com.ar/fact/api/parametros/cotizacion/DOL -H "X-API-Key: TU_KEY"
# {"monId":"DOL","cotiz":1156.515,"fecha":"20260823"}
GET /parametros/estado-arca
Semáforo del servicio de ARCA: {"estado":"ok"|"degradado"|"caido", "componentes":{...}}. Útil para no intentar emitir cuando ARCA está caído.
Barrera fiscal:
POST /comprobantesrespeta la categoría del emisor. Emitir un tipo no permitido (p.ej. Factura A siendo monotributo) devuelve 403no_permitido.
Emitir
GET /mi-plan
Cuánto cupo te queda en el período. Consultalo antes de una tanda grande y evitás chocarte el 403 a mitad de camino.
curl https://facturaraltoque.com.ar/fact/api/mi-plan -H "X-API-Key: TU_KEY"
# {"consumo":{"origen":"pago","desde":"...","hasta":"...","incluidos":50,
# "emitidos":12,"restantes":38,"excedido":false,"paquete":{"id":6,"nombre":"Pro"}}}
incluidos: null = sin tope. Solo cuentan los comprobantes aprobados de producción: un rechazo de ARCA no consume cupo, y homologación tampoco.
POST /comprobantes — emitir
El detalle va como renglones (items). Para el caso simple hay un atajo: descripcion + importe (arma un único renglón de cantidad 1).
| Campo | Obligatorio | Detalle |
|---|---|---|
items | sí* | [{ descripcion, cantidad, precioUnitario, alicuotaIvaId?, codigo?, unidad? }]. El total lo calcula el sistema |
descripcion + importe | sí* | Atajo en lugar de items: un solo renglón (cantidad 1) |
receptorNombre | sí | Nombre / razón social. Para venta sin CUIT: "Consumidor Final" |
condicionIVAReceptorId | sí | Id de GET /parametros/condiciones-iva (Consumidor Final = 5) |
receptorCuit | no | CUIT del receptor. Si va vacío → Consumidor Final (sin CUIT) |
cbteTipo | no | Tipo de comprobante. Default 11 (Factura C) |
concepto | no | 1 = Productos (default), 2 = Servicios, 3 = Ambos |
fchServDesde, fchServHasta, fchVtoPago | según concepto | Requeridos si concepto = 2 o 3, formato AAAAMMDD |
preciosConIva | no | true = el precioUnitario ya incluye IVA (se desnetea). Default false |
monId, monCotiz, canMisMonExt | no | Moneda extranjera — ver más abajo |
tributos | no | Percepciones y otros tributos que se suman al total — ver más abajo |
comprobanteAsociadoId | según tipo | Obligatorio para NC/ND — ver más abajo |
fceCbu, fceAlias, fceTransferencia, fceReferencia, fceAnulacion | según tipo | Solo Factura de Crédito MiPyME — ver más abajo |
condicionVenta, fchVencimiento | no | Datos comerciales que salen impresos |
\* Va uno de los dos: items, o el atajo descripcion + importe.
# Simple (un renglón, atajo)
curl -X POST https://facturaraltoque.com.ar/fact/api/comprobantes \
-H "X-API-Key: TU_KEY" -H "Content-Type: application/json" \
-d '{
"receptorCuit": "20386039853",
"receptorNombre": "Juan Perez",
"condicionIVAReceptorId": 1,
"concepto": 1,
"descripcion": "Servicio de ejemplo",
"importe": 15000
}'
# Varios renglones (items)
curl -X POST https://facturaraltoque.com.ar/fact/api/comprobantes \
-H "X-API-Key: TU_KEY" -H "Content-Type: application/json" \
-d '{
"receptorNombre": "Consumidor Final",
"condicionIVAReceptorId": 5,
"concepto": 1,
"items": [
{ "descripcion": "Producto A", "cantidad": 2, "precioUnitario": 5000 },
{ "descripcion": "Producto B", "cantidad": 1, "precioUnitario": 5000 }
]
}'
Percepciones y otros tributos
Importes que no son IVA y se suman al total: percepción de IIBB, percepción de IVA, impuestos municipales, etc.
{
"receptorNombre": "Cliente SA",
"receptorCuit": "30500010912",
"condicionIVAReceptorId": 1,
"cbteTipo": 1,
"items": [{ "descripcion": "Servicio", "cantidad": 1, "precioUnitario": 10000, "alicuotaIvaId": 5 }],
"tributos": [
{ "tributoId": 7, "descripcion": "Percepción IIBB CABA", "baseImp": 10000, "alicuota": 3 },
{ "tributoId": 6, "descripcion": "Percepción de IVA", "importe": 150 }
]
}
Cada tributo lleva el importe directo, o una base y una alícuota para que el sistema lo calcule (importe = baseImp × alicuota / 100).
tributoId | Tipo |
|---|---|
| 1 | Impuestos nacionales |
| 2 | Impuestos provinciales |
| 3 | Impuestos municipales |
| 4 | Impuestos internos |
| 5 | IIBB |
| 6 | Percepción de IVA |
| 7 | Percepción de IIBB |
| 8 | Percepción impuestos municipales |
| 9 | Otras percepciones |
| 13 | Percepción de IVA a no categorizado |
| 99 | Otro |
El total lo calcula el sistema: total = neto + IVA + tributos. ARCA valida que cierre; si no, rechaza el comprobante entero. Los tributos salen detallados en el PDF y en el ticket, y se exportan en la columna Otros Tributos del Libro IVA.
Factura de Crédito Electrónica MiPyME (FCE)
Tipos 201/206/211 (factura), 202/207/212 (débito) y 203/208/213 (crédito). Va siempre a una empresa con CUIT (receptorCuit). Además:
| Campo | En | Detalle |
|---|---|---|
fceCbu | factura, obligatorio | CBU donde se cobra (22 dígitos). Sale impreso |
fceAlias | factura | Alias del CBU |
fceTransferencia | factura | "SCA" (Sistema de Circulación Abierta, default) o "ADC" (Agente de Depósito Colectivo) |
fceReferencia | factura | Referencia comercial (hasta 50 caracteres) |
fchVtoPago o fchVencimiento | factura, obligatorio | Vencimiento del pago, AAAAMMDD. En la FCE va también con productos |
fceAnulacion | notas | "S" si la nota anula la factura (el cliente la rechazó); "N" (default) si la ajusta |
Las notas de la FCE llevan su comprobante asociado como cualquier NC/ND (una FCE del mismo tipo).
Ojo con la B: ARCA acepta la FCE B solo si el receptor es exento (condicionIVAReceptorId 4). A un inscripto o a un monotributista la rechaza.
{
"cbteTipo": 211,
"receptorCuit": "30500010912",
"receptorNombre": "Empresa S.A.",
"condicionIVAReceptorId": 1,
"descripcion": "Servicio de mantenimiento",
"importe": 250000,
"fceCbu": "2850590994000041450674",
"fceTransferencia": "SCA",
"fchVtoPago": "20261106"
}
Notas de crédito y débito
Llevan obligatoriamente el comprobante que ajustan. Pasá el id (el que devolvió la emisión original) en comprobanteAsociadoId, y el cbteTipo de la nota.
Están implementadas las tres clases; cuál podés usar lo determina tu categoría fiscal:
| Clase | Nota de crédito | Nota de débito |
|---|---|---|
| A | 3 | 2 |
| B | 8 | 7 |
| C | 13 | 12 |
Consultá GET /parametros/tipos-comprobante para no hardcodearlos: devuelve solo los habilitados para ese emisor. Un tipo de otra clase responde 403.
curl -X POST https://facturaraltoque.com.ar/fact/api/comprobantes \
-H "X-API-Key: TU_KEY" -H "Content-Type: application/json" \
-d '{
"cbteTipo": 13,
"comprobanteAsociadoId": 128,
"receptorNombre": "Juan Perez",
"receptorCuit": "20386039853",
"condicionIVAReceptorId": 1,
"items": [{ "descripcion": "Anulación parcial", "cantidad": 1, "precioUnitario": 5000 }]
}'
Referenciar por número, cuando la original no salió por la API. El id solo existe para los comprobantes emitidos por este canal. Para una factura hecha desde la web, o anterior a la integración, usá comprobanteAsociado con los datos que ARCA pide:
curl -X POST https://facturaraltoque.com.ar/fact/api/comprobantes -H "X-API-Key: TU_KEY" -H "Content-Type: application/json" -d '{
"cbteTipo": 13,
"comprobanteAsociado": { "cbteTipo": 11, "ptoVta": 23, "cbteNro": 105 },
"receptorNombre": "Juan Perez",
"receptorCuit": "20386039853",
"condicionIVAReceptorId": 1,
"items": [{ "descripcion": "Anulación parcial", "cantidad": 1, "precioUnitario": 5000 }]
}'
| Campo | Obligatorio | Default |
|---|---|---|
cbteTipo | sí | — |
cbteNro | sí | — |
ptoVta | no | el punto de venta de la key |
cuit | no | el CUIT del emisor |
fecha (AAAAMMDD) | no | se completa si el comprobante está en la base |
Si el comprobante existe en la base (mismo emisor), se resuelve contra ella y cuit/fecha se completan solos, ignorando lo declarado. Si no existe, los datos viajan tal cual a ARCA, que es quien valida la referencia: un número inexistente vuelve como 422 con el rechazo de ARCA.
Los dos campos son mutuamente excluyentes: mandar comprobanteAsociadoId y comprobanteAsociado en la misma llamada responde 400.
Si falta la referencia por completo, o el comprobante apuntado no existe / no está aprobado / no es tuyo, responde 400.
GET /comprobantes/:id devuelve el campo asociados con la referencia guardada, y el PDF borrador de POST /comprobantes/preview-pdf también la muestra.
Moneda extranjera
| Campo | Detalle |
|---|---|
monId | Id de GET /parametros/monedas. Default PES |
monCotiz | Cotización usada. Con canMisMonExt: "N" la declarás vos (ARCA tolera ±20%–200% de la oficial) |
canMisMonExt | "S" = se cobra en la misma moneda extranjera; "N" = se convierte a pesos |
Con canMisMonExt: "S" ARCA exige la cotización oficial exacta: el sistema la trae solo de FEParamGetCotizacion y pisa lo que hayas declarado, para evitar el rechazo.
POST /comprobantes/preview-pdf
Devuelve el PDF borrador de lo que se emitiría, con los mismos campos que POST /comprobantes. No toca ARCA ni la base — sirve para mostrarle al cliente cómo va a quedar antes de confirmar. Usa la plantilla de diseño activa de tu cuenta.
POST /comprobantes/resolver-pendientes
Destraba la emisión del punto de venta. Un comprobante pendiente sin resolver bloquea toda emisión nueva; este endpoint lo resuelve contra ARCA sin emitir nada.
{ "ok": true, "habia": 1, "resueltos": [{ "idUnico": 42, "cbteNro": 17, "estado": "aprobado", "cae": "751..." }], "pendientes": 0, "destrabado": true }
destrabado: true significa que ya podés volver a emitir. Si ARCA sigue sin confirmar, devuelve destrabado: false: reintentá en unos minutos (no reenvíes el comprobante).
Respuestas de la emisión
| HTTP | categoría | Qué significa | ¿Reintentar? |
|---|---|---|---|
201 | aprobado | Emitido. Trae cae, caeVto, comprobante (nº) | — |
422 | rechazado | ARCA rechazó los datos | No — corregí y reenviá |
502 | error_infraestructura | ARCA no evaluó (caída/timeout) | Sí |
202 | ambiguo | Quedó pendiente; confirmá con GET /comprobantes/:id | No reenviar; consultar |
502 | ambiguo (no_emitido) | No se emitió | Sí |
400 | validacion | Faltan/están mal los datos del cuerpo | No — corregí |
403 | no_permitido | Tu categoría fiscal no puede emitir ese tipo | No |
403 | trial_vencido | Venció la prueba/suscripción | Registrar pago |
403 | email_sin_verificar | La cuenta tiene el email sin confirmar | Confirmarlo desde el sistema |
403 | emision_bloqueada | El proveedor inhabilitó la emisión de la cuenta | Contactarnos |
403 | limite_alcanzado | Se agotaron los comprobantes incluidos en el plan | Ampliar el plan (viene con cupo) |
429 | — | Superaste el límite de uso | Sí, en unos segundos |
409 | clave_en_uso | Hay otra emisión en curso con esa misma clave | Consultá por la clave |
Cuándo se puede reintentar. Son tres situaciones distintas y conviene no mezclarlas:
502(te llegó nuestra respuesta): ARCA evaluó y no emitió. Reintentar es seguro.202(te llegó nuestra respuesta): quedó ambiguo. No reenvíes; consultáGET /comprobantes/:id, que lo resuelve contra ARCA.- No te llegó ninguna respuesta (timeout, se cortó la red): no sabés si emitimos. Acá reintentar a ciegas puede duplicar un comprobante fiscal, con CAE real y numeración consumida. Para esto está la clave de idempotencia, abajo.
Que un corte de conexión no te deje dos facturas
Si se corta la red entre que mandás el POST y recibís la respuesta, perdés el id que te íbamos a devolver y no sabés si el comprobante se emitió. Mandá una clave de idempotencia: la elegís vos, viaja en el pedido, y por eso te queda aunque se pierda la respuesta.
Idempotency-Key: pedido-2026-00184
También podés mandarla en el cuerpo como claveIdempotencia, si no podés tocar los headers. Es única por punto de venta: dos negocios pueden usar pedido-1 sin pisarse.
Al reintentar con la misma clave, no se emite nada nuevo. Te devolvemos lo que pasó la primera vez, con repetido: true:
| Cómo terminó la primera | Qué recibís al reintentar |
|---|---|
| Se emitió | 200 con el comprobante y su CAE |
| Quedó pendiente | 202 — consultá, no reenvíes |
| ARCA la rechazó | 422 — corregí los datos y mandala con una clave nueva |
ARCA no emitió (502) | La clave queda libre: reintentá esa misma venta con ella |
Dos llamadas simultáneas con la misma clave emiten una sola: la segunda recibe el comprobante de la primera, o un 409 clave_en_uso si todavía está en curso.
Si no mandás clave, te avisamos
Cuando emitimos algo idéntico a otro comprobante tuyo de los últimos 10 minutos —mismo receptor, mismo importe, mismos renglones— y no viene clave, la respuesta trae un aviso además del comprobante:
{
"ok": true,
"cae": "75123456789012",
"aviso": "Ojo: hace 8 segundos emitiste un comprobante idéntico (00003-00000184). Si esto fue un reintento porque no te llegó la respuesta, acabás de duplicarlo...",
"posibleDuplicadoDe": { "id": 184, "comprobante": "00003-00000184", "haceSegundos": 8 }
}
No bloqueamos la emisión: dos ventas iguales al mismo cliente por el mismo importe son legítimas y nadie puede decidir por vos. El aviso es para que lo detectes en el momento y no a fin de mes. Si mandás clave no aparece, porque ahí ya nos dijiste que es otra operación.
POST /comprobantes/verificar — ¿esto ya lo facturé?
Si no usás clave y te quedaste sin respuesta, mandá acá el mismo cuerpo que le habías mandado a /comprobantes. No emite nada: compara y contesta.
{ "existe": true, "comprobante": "00003-00000184", "cae": "75123456789012",
"haceSegundos": 8, "detalle": "Ya hay un comprobante idéntico emitido..." }
Con existe: false no se emitió: podés reenviarlo. La ventana por defecto es de 10 minutos y se puede ampliar hasta 60 con ?minutos=.
Su límite: si de verdad vendiste dos veces lo mismo al mismo cliente por el mismo importe, esto no las distingue — son idénticas. Da una respuesta muy buena, no una certeza. La certeza es la clave de idempotencia.
GET /comprobantes/por-clave/:clave
La salida del corte: buscá por tu clave, no por nuestro id.
200con el comprobante: se emitió. Si había quedado pendiente, esta llamada lo resuelve contra ARCA.404: no se emitió nada. Podés mandarlo de nuevo, con la misma clave.
Consultar
GET /comprobantes?limit=&offset=
Listado de tus comprobantes (default limit=100, máximo 500).
GET /comprobantes/:id
Detalle de un comprobante (incluye cae, estado, categoria).
Si quedó en pendiente (respuesta 202), esta llamada lo resuelve contra ARCA y devuelve el estado real: aprobado con su CAE, o no_emitido (seguro reintentar). Si ARCA no está disponible, devuelve el estado actual sin error.
GET /comprobantes.csv
Listado completo en CSV (hasta 5000, todos los estados). Formato Excel es-AR: BOM, ; como separador y coma decimal.
GET /libro-iva.csv
Libro IVA Ventas de un período: ?desde=AAAAMMDD&hasta=AAAAMMDD (default: mes en curso; también acepta AAAA-MM-DD).
Trae una columna de neto y otra de IVA por cada alícuota presente, más no gravado, exento, otros tributos, totales y CAE. Solo comprobantes aprobados; las notas de crédito van en negativo (así se netea el período).
Entregarle el comprobante al cliente
GET /comprobantes/:id/pdf
PDF A4 del comprobante.
GET /comprobantes/:id/ticket
Mismo comprobante en formato ticket 80 mm (rollo térmico).
POST /comprobantes/:id/enviar-email
Envía el comprobante por email con el PDF adjunto.
{ "email": "cliente@ejemplo.com", "mensaje": "Gracias por tu compra" }
Responde { "ok": true, "enviado": true }. Si el servidor todavía no tiene el correo configurado, responde enviado: false y el detalle — no des por hecho que llegó sin mirar ese campo.
Sale desde comprobantes@facturaraltoque.com.ar con el nombre de tu negocio como remitente; si el cliente responde, la respuesta te llega a vos (al mail de contacto del punto de venta o al de tu cuenta).
Datos auxiliares
GET /padron/:cuit
Datos del receptor desde el padrón de ARCA (razón social, condición IVA, domicilio). Con caché de 30 días por punto de venta.
Requiere que tu certificado esté autorizado al servicio ws_sr_constancia_inscripcion. Si no lo está o ARCA no responde, devuelve {"encontrado": false, "error": "..."} en vez de romper.
GET /receptores
Clientes que ya facturaste con este punto de venta (nombre, CUIT, condición IVA). Para autocompletar.
Ítems — catálogo de productos/servicios
GET /items | Lista el catálogo (?todos=1 incluye inactivos) |
POST /items | Alta: { nombre, codigo?, descripcion?, precioUnitario, unidad?, alicuotaIvaId? } |
PUT /items/:id | Edición (mismos campos) |
DELETE /items/:id | Desactiva el ítem (no lo borra, para no romper comprobantes ya emitidos) |
El codigo es único por cuenta: repetirlo devuelve 409.
Lo que NO está en la API (se hace desde la web)
Son operaciones de configuración de la cuenta, no de facturación:
- Alta de la cuenta, carga y renovación del certificado, generación del CSR.
- Generar/rotar la API key (necesitarías una key para pedir una key).
- Editor de plantillas de diseño del PDF.
- Datos comerciales del emisor y preferencias de impresión.
Ejemplo de flujo típico
- (Opcional)
GET /parametros/estado-arca→ si estácaido, esperá. - (Opcional)
GET /padron/:cuit→ autocompletás los datos del cliente. POST /comprobantes→ si201, guardás elcaey el número.- Si
202, guardás elidy consultásGET /comprobantes/:idhasta ver el estado final. - Se lo entregás al cliente:
POST /comprobantes/:id/enviar-email(con el PDF adjunto), o bajás el PDF conGET /comprobantes/:id/pdfy lo mandás por tu canal. - A fin de mes:
GET /libro-iva.csv?desde=…&hasta=…para el contador.
Cualquier duda de integración, escribinos.