SimpleComm
Documentación de la API

Facturación electrónica argentina, por API

Emití facturas A/B/C, notas de crédito y notas de débito autorizadas por ARCA directo desde tu sistema — e-commerce propio, ERP, o cualquier backend que ya tengas. Mismo motor que usa el dashboard de SimpleComm, sin pasar por él.

REST · JSONAutenticación BearerCAE real de ARCA

Introducción

La API de SimpleComm te deja emitir comprobantes electrónicos válidos ante ARCA (ex AFIP) con una sola llamada HTTP: mandás el monto, los datos del comprador y el tipo de comprobante, y recibís de vuelta el CAE, el número de comprobante y el PDF listo para descargar. No hace falta que manejes certificados ni te conectes vos mismo a los webservices de ARCA — eso ya lo resuelve SimpleComm.

Todos los comprobantes emitidos por API son reales y quedan registrados en ARCA — no hay un modo "sandbox" separado. Probá primero con un monto chico si es tu primera integración.

Autenticación

Todas las llamadas requieren una API key en el header Authorization, formato Bearer. Generá la tuya desde Configuración → API en tu dashboard — se muestra una única vez al crearla, así que guardala en un lugar seguro.

Header en cada request
Authorization: Bearer sc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Tu API key da acceso a emitir comprobantes fiscales reales a tu nombre. No la pongas en código frontend ni la subas a un repositorio público — usala solo desde tu backend.

Inicio rápido

La URL base de la API es:

Base URL
https://simplecomm-production.up.railway.app

Un ejemplo completo — emitir una Factura B a un consumidor final:

curl
curl -X POST https://simplecomm-production.up.railway.app/v1/invoices/issue \
  -H "Authorization: Bearer sc_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "pedido-10234",
    "invoice": {
      "total_amount": 15000,
      "invoice_letter": "B"
    },
    "buyer": {
      "full_name": "Consumidor Final"
    }
  }'
JavaScript (fetch)
const res = await fetch("https://simplecomm-production.up.railway.app/v1/invoices/issue", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sc_live_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    idempotency_key: `pedido-${orderId}`,
    invoice: {
      total_amount: 15000,
      invoice_letter: "B",
    },
    buyer: {
      full_name: "Consumidor Final",
    },
  }),
});

const data = await res.json();
console.log(data.invoice_number, data.cae);
Respuesta
{
  "status": "issued",
  "invoice_id": "clx4k9j8e0001abc123",
  "invoice_number": "0004-00000123",
  "cae": "75312457896541",
  "cae_due_date": "20261015",
  "pdf_base64": "JVBERi0xLjQKJcOkw7zDtsO..."
}

Emitir un comprobante

POST/v1/invoices/issue

Emite una Factura A, B o C. El monto se interpreta distinto según la letra: para Factura A es el neto (sin IVA, que se suma aparte); para B y C es el total (con IVA incluido en B, sin IVA en C porque los monotributistas no lo discriminan).

Body — invoice

CampoTipoDescripción
total_amountnumberrequeridoNeto para Factura A, total (con IVA) para B/C.
invoice_letter"A" | "B" | "C"opcionalPor defecto "B". Tu condición fiscal en ARCA determina qué letras podés emitir.
iva_ratenumberopcional21, 10.5, 27 o 0 (exento). Por defecto 21.
concept1 | 2 | 3opcional1=Productos (default), 2=Servicios, 3=Ambos. Si es 2 o 3, ARCA exige el período facturado.
descriptionstringopcionalDetalle que aparece en el PDF del comprobante.
pto_vtanumberopcionalPunto de venta a usar. Por defecto, el punto de venta principal de tu cuenta.
service_date_fromstringopcional*YYYY-MM-DD. Requerido si concept es 2 o 3.
service_date_tostringopcional*YYYY-MM-DD. Requerido si concept es 2 o 3.
payment_due_datestringopcional*YYYY-MM-DD. Requerido si concept es 2 o 3.
currency"PES" | "DOL"opcionalPor defecto pesos.
exchange_ratenumberopcional*Requerido y mayor a 1 si currency es "DOL".

Body — buyer

CampoTipoDescripción
full_namestringrequeridoNombre o razón social del comprador.
doc_typestringopcional"CUIT", "CUIL", "DNI" o "CONSUMIDOR_FINAL". Por defecto "CONSUMIDOR_FINAL". Factura A requiere CUIT.
doc_numberstringopcionalSolo dígitos. Por defecto "0".
emailstringopcionalNo se usa para enviar el comprobante — el envío por email es responsabilidad tuya.
addressstringopcionalAparece en el PDF si se provee.

Body — nivel raíz

CampoTipoDescripción
idempotency_keystringrequeridoVer Idempotencia. 1-255 caracteres.
external_refstringopcionalTu propio ID de referencia (ej. número de pedido) — se guarda pero no se usa para nada más.
source_appstringopcionalIdentificador libre de tu integración, útil para tus propios logs.
metadataobjectopcionalCualquier dato adicional que quieras asociar al comprobante.

Respuesta

201 si se emitió, o 200 si ya la habías emitido antes con esa misma idempotency_key.

200 / 201
{
  "status": "issued",       // o "duplicate" si ya existía
  "invoice_id": "clx4k9j8e0001abc123",
  "invoice_number": "0004-00000123",
  "cae": "75312457896541",
  "cae_due_date": "20261015",  // YYYYMMDD
  "pdf_base64": "..."          // PDF del comprobante, en base64
}

Ejemplo — Factura A a un Responsable Inscripto

curl
curl -X POST https://simplecomm-production.up.railway.app/v1/invoices/issue \
  -H "Authorization: Bearer sc_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "pedido-10235",
    "invoice": {
      "total_amount": 50000,
      "invoice_letter": "A",
      "iva_rate": 21,
      "description": "Servicio de consultoría — septiembre"
    },
    "buyer": {
      "full_name": "Comercial del Sur S.A.",
      "doc_type": "CUIT",
      "doc_number": "30712345671"
    }
  }'

Consultar un comprobante

GET/v1/invoices/:id

Devuelve el estado actual de un comprobante emitido por vos, identificado por el invoice_id que te devolvió /v1/invoices/issue.

Respuesta
{
  "invoice_id": "clx4k9j8e0001abc123",
  "status": "issued",             // "issued" | "pending" | "error"
  "invoice_number": "0004-00000123",
  "invoice_number_int": 123,
  "pto_vta": 4,
  "invoice_type": 6,               // código AFIP: 1=Fact.A, 6=Fact.B, 11=Fact.C
  "cae": "75312457896541",
  "cae_due_date": "20261015",
  "total_amount": 15000,
  "net_amount": 12396.69,
  "iva_amount": 2603.31,
  "concept": 1,
  "buyer_name": "Consumidor Final",
  "buyer_doc_type": "CONSUMIDOR_FINAL",
  "buyer_doc_number": "0",
  "created_at": "2026-09-11T14:32:08.000Z",
  "error": null
}

Nota de crédito

POST/v1/invoices/:id/credit-note

Anula por completo un comprobante ya emitido. La letra, el receptor, el punto de venta y el monto se toman directo de la factura original — no hace falta (ni se puede) reenviarlos. Hoy solo soporta notas de crédito totales, no parciales.

CampoTipoDescripción
idempotency_keystringrequeridoIgual que en la emisión — usá una nueva por cada intento real.
source_appstringopcionalIdentificador libre de tu integración.
curl
curl -X POST https://simplecomm-production.up.railway.app/v1/invoices/clx4k9j8e0001abc123/credit-note \
  -H "Authorization: Bearer sc_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "idempotency_key": "nc-pedido-10234" }'

La respuesta tiene la misma forma que la de emisión.

Nota de débito

POST/v1/invoices/:id/debit-note

A diferencia de la nota de crédito, esta no anula nada — suma un cargo adicional asociado a una factura ya emitida (ej. intereses por mora, un ajuste de precio). Vos definís el monto y el motivo; la letra, el receptor y el punto de venta se toman de la factura original.

CampoTipoDescripción
idempotency_keystringrequerido
amountnumberrequeridoMonto del cargo, mayor a cero. Interpretado igual que total_amount en la emisión (neto para A, total para B/C).
reasonstringrequeridoMotivo del cargo — queda impreso en el comprobante. 1-255 caracteres.
source_appstringopcional
curl
curl -X POST https://simplecomm-production.up.railway.app/v1/invoices/clx4k9j8e0001abc123/debit-note \
  -H "Authorization: Bearer sc_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "nd-pedido-10234",
    "amount": 1500,
    "reason": "Intereses por pago fuera de término"
  }'

Idempotencia

Todo endpoint que emite un comprobante requiere idempotency_key. Si repetís la misma llamada con la misma key (por ejemplo, porque tu request original tuvo timeout y reintentaste), la API no emite un comprobante duplicado — te devuelve el mismo resultado de la primera vez, con status: "duplicate" y código 200 en vez de 201.

Usá algo determinístico y único por operación real — el ID de tu pedido es una buena opción (ej. `pedido-${orderId}`). No generes una key nueva en cada reintento: ahí perdés la protección contra duplicados.

Errores

CódigoSignifica
400Payload inválido — el body no cumple el formato esperado. El campo details de la respuesta indica qué falló.
401API key faltante, inválida o revocada.
402Alcanzaste el cupo mensual de tu API key. Ver Límites.
404El comprobante (o la factura original, en notas de crédito/débito) no existe o no te pertenece.
502Error al emitir contra ARCA — el body incluye un mensaje explicando la causa (rechazo de ARCA, timeout, etc.).
Ejemplo de error 400
{
  "error": "Payload inválido",
  "details": {
    "invoice": ["Required"]
  }
}

Límites del Plan API

El acceso directo por API es independiente del plan de tu dashboard — tiene su propio cupo mensual de comprobantes, que ves reflejado en Configuración → API junto a cada key. El cupo se resetea el primer día de cada mes.

Si lo superás, vas a recibir 402 hasta el próximo reseteo. Si tu volumen creció y necesitás más, escribinos a soporte@simplecomm.com.ar.

Buenas prácticas

  • Guardá siempre invoice_id, invoice_number y cae apenas los recibís — son los datos que después necesitás para una nota de crédito/débito o para mostrarle el comprobante al comprador.
  • Descargá y guardá el pdf_base64 en tu propio storage si necesitás servirlo después — la API no lo re-expone en GET /v1/invoices/:id.
  • Verificá el campo status de la respuesta: un "duplicate" no es un error, es la protección de idempotencia funcionando.
  • Para Factura A siempre mandá doc_type: "CUIT" con un CUIT válido — ARCA la rechaza sin eso.
  • Manejá el 502 con reintento manual, no automático inmediato: un rechazo de ARCA casi nunca se resuelve reintentando al instante con los mismos datos.

¿Listo para integrar?

Generá tu API key desde el dashboard y emitís tu primer comprobante en minutos.

Generar mi API key