Guía de uso de la API
REST JSON para registrar usuarios, administrar negocios emisores y solicitar comprobantes electrónicos ARCA/AFIP. Pensada para integrarla desde otro sistema.
Introducción
Base preferida: /api
Si /api no responde (por ejemplo si Apache enruta esa ruta a otra app), usá el fallback:
/api.php?path=usuario/me
/api/usuario/... y /api/usuarios/... son equivalentes.
Autenticación
Todos los endpoints requieren token, excepto el registro de usuario y el GET raíz.
Enviá el token en uno de estos headers:
Authorization: Bearer <api_token> X-Api-Token: <api_token>
También se acepta ?api_token= en la query; no lo uses en producción.
GET /api/usuario/me, o desde Configuración en el panel web. Regenerarlo invalida el anterior.Convenciones
Request
Content-Type: application/json
También se acepta form-urlencoded y multipart/form-data (archivos de certificado).
Override de método: POST + header X-HTTP-Method-Override: PUT.
Response
Siempre JSON UTF-8.
{ "ok": true, ... }
{ "ok": false, "error": "mensaje" }
Códigos: 200/201 OK · 400 validación · 401 token · 404 · 409 conflicto · 500.
Flujo típico
POST /api/usuarioo usar un token ya generado en Configuración.POST /api/negociosy luego cargar certificado AFIP con/credenciales.POST /api/comprobantes→ guardar elid(queda en estadosolicitado).- Polling a
GET /api/comprobantes/{id}hastaemitidoorechazado. - Si está emitido, usar
cae,numeroypdf_path.
Descubrimiento
Devuelve versión y lista de endpoints. No requiere token.
Usuarios
Registra un usuario y devuelve el api_token. Email duplicado → 409.
| Campo | Obligatorio | Notas |
|---|---|---|
| nombre | sí | |
| sí | formato email válido | |
| password | sí | mínimo 6 caracteres |
{
"nombre": "Juan Pérez",
"email": "juan@empresa.com",
"password": "minimo6"
}
{
"ok": true,
"usuario": {
"id": 1,
"nombre": "Juan Pérez",
"email": "juan@empresa.com",
"api_token": "a1b2c3..."
}
}
Perfil del usuario autenticado, incluyendo el token actual.
Actualiza perfil. Todos los campos son opcionales: nombre, email, password.
Regenera el token. El anterior deja de funcionar.
{ "ok": true, "api_token": "nuevo_hex_64..." }
Negocios (emisores)
Requieren token. Solo se listan y modifican los negocios del usuario autenticado.
Lista negocios. Cada ítem incluye tiene_credenciales y el pto_vta activo.
| Campo | Obligatorio | Notas |
|---|---|---|
| nombre | sí | |
| cuit | sí | 11 dígitos |
| condicion | sí | código IVA del emisor (ver catálogos) |
| pto_vta | sí | 1–99999 |
| domicilio | no | |
| passphrase | no | contraseña de la clave privada |
| certificado | sí | multipart: $_FILES['certificado'] (.crt/.cer/.pem). JSON: PEM o base64. Name exacto, no cert. |
| private_key | sí | multipart: $_FILES['private_key'] (.key/.pem). JSON: PEM o base64. Name exacto con guion bajo, no privateKey ni key. |
400 (no se crea el negocio). En multipart PHP no pone el archivo en $_POST: tiene que ser file part. Preferí /api.php?path=negocios o la URL con barra final para no perder el body en un redirect 301.{
"nombre": "Mi comercio",
"cuit": "20123456789",
"condicion": 1,
"pto_vta": 1,
"domicilio": "Av. Corrientes 1000",
"certificado": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}
{
"ok": true,
"negocio": {
"id": 12,
"nombre": "Mi comercio",
"cuit": "20123456789",
"condicion": 1,
"domicilio": "Av. Corrientes 1000",
"pto_vta": 1,
"tiene_credenciales": true
}
}
Detalle de un negocio.
Actualiza datos. Mismos campos que el alta; si enviás pto_vta se actualiza el punto de venta activo.
Carga certificado y/o clave privada AFIP. JSON o multipart/form-data.
| Campo | Formato |
|---|---|
| certificado | archivo .crt / .cer / .pem, PEM crudo, o base64 |
| certificado_base64 | alternativa al campo certificado |
| private_key | archivo .key / .pem, PEM crudo, o base64 |
| private_key_base64 | alternativa al campo private_key |
| passphrase | opcional |
POST /api/comprobantes responde error: el negocio no tiene credenciales AFIP cargadas.Padrón ARCA (constancia de inscripción)
Consulta ws_sr_constancia_inscripcion con el certificado del negocio central (id 1). El token de API alcanza: el negocio del usuario no necesita tener ese web service adherido.
También: GET /api/padron?cuit=20386368563 o POST /api/padron con {"cuit":"20386368563"}. Alias: /api/constancia/....
{
"ok": true,
"padron": {
"cuit": "20386368563",
"doc_tipo": 80,
"razon_social": "PEREZ JUAN",
"domicilio": "HIDALGO 820 Piso:8 Dpto:E, CIUDAD AUTONOMA BUENOS AIRES, CP 1405",
"domicilio_detalle": {
"direccion": "HIDALGO 820 Piso:8 Dpto:E",
"localidad": "CIUDAD AUTONOMA BUENOS AIRES",
"provincia": "CIUDAD AUTONOMA BUENOS AIRES",
"cod_postal": "1405"
},
"condicion_iva": 6,
"condicion_iva_label": "Responsable Monotributo",
"tipo_persona": "FISICA",
"estado_clave": "ACTIVO",
"errores": []
}
}
condicion_iva usa los mismos códigos que al crear un comprobante (1 RI, 4 Exento, 6 Mono, etc.). Puede ser null si el padrón no permite inferirlo.
Comprobantes
Requieren token. El negocio debe tener un punto de venta activo y credenciales AFIP. El PV se toma automáticamente (el primero activo); no se elige en el POST.
| Query | Default | Notas |
|---|---|---|
| negocio_id | — | filtra por emisor. Ej: ?negocio_id=9 devuelve solo comprobantes de ese negocio. No confundir con GET /api/comprobantes/9 (eso es el detalle del comprobante id 9). |
| estado | — | solicitado, procesando, emitido, rechazado, anulado |
| id_externo | — | coincidencia exacta con el ID que envió el cliente al crear el comprobante |
| desde | — | fecha_cbte ≥ esta fecha. Formato YYYY-MM-DD |
| hasta | — | fecha_cbte ≤ esta fecha. Formato YYYY-MM-DD |
| page | 1 | página (1-based) |
| limit | 100 | tamaño de página, 1–100 |
Ordenados por id descendente. La respuesta incluye paginacion con page, limit, total y pages.
Cada comprobante incluye fecha_cbte (fecha fiscal, YYYY-MM-DD) y fecha_hora_emision (fecha y hora de registro/emisión en America/Argentina/Buenos_Aires, YYYY-MM-DD HH:MM:SS).
{
"ok": true,
"comprobantes": [
{
"id": 99,
"negocio_id": 9,
"negocio_nombre": "Mi comercio",
"estado": "emitido",
"fecha_cbte": "2026-09-14",
"fecha_hora_emision": "2026-09-14 12:34:56",
"created_at": "2026-09-14 12:34:56"
}
],
"paginacion": {
"page": 1,
"limit": 100,
"total": 250,
"pages": 3
}
}
Detalle + array items. Cuando está emitido incluye cae, cae_vto, numero, pdf_path, xml_path. Si falló: estado: "rechazado" y motivo_rechazo.
Solicita la emisión. Queda en solicitado hasta que el worker autorice en ARCA. Máximo 20 ítems.
| Campo | Obligatorio | Notas |
|---|---|---|
| negocio_id | sí | |
| cbte_tipo | sí | ver catálogo; debe coincidir con el IVA del emisor |
| doc_tipo | sí | 80 CUIT o 96 DNI |
| doc_nro | sí | CUIT 11 dígitos; DNI 7 u 8 |
| items | recomendado | o bien importe_total suelto |
| receptor_razon_social | si CUIT | en DNI: nombre del receptor (alias: receptor_nombre) |
| condicion_iva | si CUIT | alias: receptor_condicion_iva; con DNI queda 5 |
| receptor_domicilio_comercial | no | alias: receptor_domicilio / receptor_direccion; en DNI es la dirección |
| receptor_email | no | |
| concepto | no | 1 productos (default), 2 servicios, 3 ambos |
| condicion_venta | no | código 1–8 o el nombre; default 1 (Contado) |
| fecha_cbte | no | YYYY-MM-DD (calendario Buenos Aires). Default: hoy AR. Si mandás datetime ISO/UTC, se convierte a fecha en America/Argentina/Buenos_Aires. created_at y updated_at se guardan en esa misma zona. |
| periodo_desde / periodo_hasta / vto_pago | si concepto 2 o 3 | YYYY-MM-DD |
| factura_asociada | si NC | número de factura emitida, mismo PV y letra |
| importe_total | si no hay items | para A/B se infiere neto/IVA al 21% |
Ítem
| Campo | Obligatorio | Notas |
|---|---|---|
| descripcion | sí | alias: producto_servicio |
| cantidad | sí | > 0 |
| precio_unitario | sí | ≥ 0 |
| codigo | no | |
| unidad_medida | no | default UNI; alias: unidad |
| alicuota_iva | no | default 21 |
| porcentaje_bonificado | no | |
| importe_bonificado | no | si no viene, se calcula del porcentaje |
Factura B a consumidor final (DNI)
{
"negocio_id": 12,
"cbte_tipo": 6,
"doc_tipo": 96,
"doc_nro": "12345678",
"receptor_nombre": "Juan Pérez",
"receptor_direccion": "Av. Siempre Viva 123",
"condicion_venta": 6,
"items": [
{
"descripcion": "Servicio de consultoría",
"cantidad": 1,
"precio_unitario": 10000,
"alicuota_iva": 21,
"unidad_medida": "UNI"
}
]
}
Factura A a CUIT
{
"negocio_id": 12,
"cbte_tipo": 1,
"doc_tipo": 80,
"doc_nro": "30712345678",
"receptor_razon_social": "Cliente SA",
"condicion_iva": 1,
"receptor_domicilio_comercial": "Av. Siempre Viva 123",
"receptor_email": "facturacion@cliente.com",
"concepto": 1,
"condicion_venta": 1,
"items": [
{
"codigo": "SKU-01",
"descripcion": "Producto",
"cantidad": 2,
"precio_unitario": 1500.50,
"porcentaje_bonificado": 10,
"alicuota_iva": 21,
"unidad_medida": "UNI"
}
]
}
{
"ok": true,
"comprobante": {
"id": 99,
"estado": "solicitado",
"cae": "PENDIENTE",
"numero": 0,
"importe_total": 12100,
"importe_neto": 10000,
"importe_iva": 2100
},
"mensaje": "Solicitud registrada. El comprobante se autorizará en ARCA de forma asíncrona (estado: solicitado)."
}
Con DNI (doc_tipo: 96) la condición IVA queda en Consumidor Final (5). Podés enviar receptor_nombre y receptor_direccion (o los campos receptor_razon_social / receptor_domicilio_comercial); si no hay nombre se usa “Consumidor Final”.
Catálogos
cbte_tipo
| Código | Tipo | Emisor |
|---|---|---|
| 1 / 2 / 3 | Factura / ND / NC A | Responsable Inscripto (1) |
| 6 / 7 / 8 | Factura / ND / NC B | Responsable Inscripto (1) |
| 11 / 12 / 13 | Factura / ND / NC C | Monotributo / Exento / similares |
| 19 / 20 / 21 | Factura / ND / NC E | todos |
Notas de crédito (3, 8, 13, 21) exigen factura_asociada (número de factura emitida del mismo punto de venta y letra).
doc_tipo
| Código | Documento |
|---|---|
| 80 | CUIT/CUIL (11 dígitos) |
| 96 | DNI (7 u 8 dígitos) |
condicion / condicion_iva
| Código | Etiqueta |
|---|---|
| 1 | IVA Responsable Inscripto |
| 4 | IVA Sujeto Exento |
| 5 | Consumidor Final |
| 6 | Responsable Monotributo |
| 7 | Sujeto No Categorizado |
| 8 | Proveedor del Exterior |
| 9 | Cliente del Exterior |
| 10 | IVA Liberado – Ley 19.640 |
| 13 | Monotributista Social |
| 15 | IVA No Alcanzado |
concepto
1 Productos · 2 Servicios · 3 Productos y Servicios.
condicion_venta
1 Contado · 2 Débito · 3 Crédito · 4 Cuenta corriente · 5 Cheque · 6 Transferencia · 7 Otra · 8 Otros electrónicos.
alicuota_iva
0 · 2.5 · 5 · 10.5 · 21 (default) · 27.
estado del comprobante
solicitado · procesando · emitido · rechazado · anulado.
URLs alternativas
Si el rewrite de /api/... no está activo:
GET /api.php?path=usuario/me POST /api.php?path=negocios POST /api.php?path=negocios/12/credenciales POST /api.php?path=padron/20386368563 GET /api.php?path=padron&cuit=20386368563 POST /api.php?path=comprobantes GET /api.php?path=comprobantes/99 GET /api/comprobantes/?id=99
/negocios → /negocios/) con el POST original: el body multipart se pierde. Usá HTTPS desde el inicio y /api.php?path=negocios, o la URL final con barra.Ejemplos curl
curl -i -H "Authorization: Bearer $TOKEN" \ "$BASE/api.php?path=padron/20386368563"
curl -i -X POST "$BASE/api.php?path=negocios" \ -H "Authorization: Bearer $TOKEN" \ -F "nombre=EVENTO DE PRUEBA NEW" \ -F "cuit=20386368563" \ -F "condicion=6" \ -F "pto_vta=4" \ -F "domicilio=HIDALGO 820" \ -F "passphrase=" \ -F "certificado=@/ruta/certificado.crt;type=application/x-x509-ca-cert" \ -F "private_key=@/ruta/privada.key;type=application/octet-stream"
curl -i -X POST "$BASE/api.php?path=negocios" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"nombre\":\"Mi comercio\",\"cuit\":\"20123456789\",\"condicion\":6,\"pto_vta\":4,\"certificado\":\"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\",\"private_key\":\"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\"}"
TOKEN="..." BASE="https://emitifacil.com" curl -s -H "Authorization: Bearer $TOKEN" "$BASE/api/negocios"
curl -s -H "Authorization: Bearer $TOKEN" \ "$BASE/api/comprobantes?negocio_id=9&desde=2026-09-01&hasta=2026-09-30&page=1&limit=100"
curl -s -X POST "$BASE/api/comprobantes" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"negocio_id": 12,
"cbte_tipo": 6,
"doc_tipo": 96,
"doc_nro": "12345678",
"receptor_nombre": "Juan Pérez",
"receptor_direccion": "Av. Siempre Viva 123",
"items": [{
"descripcion": "Venta",
"cantidad": 1,
"precio_unitario": 1000,
"alicuota_iva": 21
}]
}'
curl -s -H "Authorization: Bearer $TOKEN" "$BASE/api/comprobantes/99"
curl -s -H "X-Api-Token: $TOKEN" "$BASE/api.php?path=usuario/me"