Facturación electrónica AFIP/ARCA
Emití comprobantes electrónicos AFIP/ARCA —facturas, notas de crédito y notas de débito— de forma programática desde tus propios sistemas.
Introducción
Este recurso permite emitir comprobantes electrónicos AFIP/ARCA (facturas, notas de crédito y notas de débito) de forma programática. Para usarlo, la cuenta debe tener la configuración fiscal y el certificado AFIP cargados desde el panel.
El tipo de comprobante (A, B o C) se determina según la condición fiscal del emisor y del receptor. Podés indicar el tipo de forma explícita con el campo tipo_comprobante o dejar que la API lo resuelva automáticamente.
Todos los endpoints están bajo la URL base https://api.yo-facturo.com/api/v1/bill/receipts. El scope necesario es invoices: invoices:read para consultar e invoices:write para emitir o modificar comprobantes.
Endpoints
Todos los endpoints son relativos a https://api.yo-facturo.com/api/v1/bill/receipts.
| Método | Endpoint | Descripción | Scope |
|---|---|---|---|
POST | /invoice/ | Emitir una factura | invoices:write |
POST | /invoice/customer/ | Emitir una factura a un cliente registrado | invoices:write |
POST | /credit-note/ | Emitir una nota de crédito | invoices:write |
POST | /debit-note/ | Emitir una nota de débito | invoices:write |
POST | /authorize/{id}/ | Autorizar un comprobante ante AFIP (obtener CAE) | invoices:write |
GET | /{id}/ | Obtener un comprobante por su ID | invoices:read |
GET | /list/ | Listar comprobantes (con filtros y paginación) | invoices:read |
PUT | /{id}/ | Actualizar el estado de un comprobante | invoices:write |
PATCH | /{id}/ | Editar un comprobante en borrador | invoices:write |
POST | /cancel/{id}/ | Anular un comprobante (genera una nota de crédito por el total) | invoices:write |
DELETE | /{id}/ | Eliminar un comprobante en borrador | invoices:write |
GET | /types/ | Tipos de comprobante soportados | invoices:read |
GET | /supported-types/ | Tipos de comprobante soportados (detallado) | invoices:read |
POST | /preview-type/ | Previsualizar qué tipo de comprobante se generaría | invoices:write |
POST | /validate-type/{tipo}/ | Validar los datos para un tipo de comprobante | invoices:write |
GET | /notes/reasons/{tipo_nota}/ | Motivos disponibles para notas de crédito/débito | invoices:read |
POST | /notes/calculate-amounts/ | Calcular automáticamente los importes de una nota | invoices:write |
POST | /notes/validate-amounts/ | Validar los importes de una nota contra el comprobante original | invoices:write |
POST | /test-environment/ | Probar la conexión con AFIP | invoices:write |
POST | /doctor/ | Diagnostica y repara la numeración de comprobantes contra AFIP | invoices:write |
GET | /{id}/pdf/ | Descargar el PDF del comprobante (formato A4 o ticket térmico 80mm) | invoices:read |
GET | /{id}/print/ | Obtener el HTML embebible del comprobante (CSS inline, QR como data URI) | invoices:read |
POST | /{id}/public-link/ | Generar URLs públicas firmadas (HMAC) para compartir el PDF/HTML sin auth | invoices:read |
DELETE | /{id}/pdf/cache/ | Invalidar el PDF cacheado del comprobante (forzar regeneración) | invoices:write |
Emitir una factura
Para emitir una factura usá POST /api/v1/bill/receipts/invoice/. El body es un objeto JSON con los siguientes campos:
| Campo | Tipo | Descripción |
|---|---|---|
tipo_comprobante | entero (opcional) | Código del tipo de comprobante AFIP. Si se omite, se determina automáticamente según la condición fiscal. La lista de códigos válidos se obtiene con GET /types/. |
punto_venta | entero | Punto de venta habilitado en AFIP. |
tipo_documento | entero | Tipo de documento del receptor (por ejemplo CUIT, DNI, Consumidor Final). |
numero_documento | string | Número de documento del receptor. |
razon_social | string | Razón social del receptor. Por defecto "CONSUMIDOR FINAL". |
domicilio_comercial | string (opcional) | Domicilio del receptor. |
condicion_iva | string | Condición frente al IVA del receptor. |
cotizacion | número (opcional) | Cotización de la moneda. Por defecto 1.0. |
items | array | Líneas del comprobante. Cada item con descripción, cantidad y precio unitario. |
iva_items | array | Desglose de alícuotas de IVA. Cada elemento es un objeto con Id (entero, código de alícuota AFIP), BaseImp (número, base imponible) e Importe (número, IVA resultante). Obligatorio en facturas A y B con IVA discriminado; vacío en facturas C. |
importe_total | número | Importe total del comprobante. |
importe_neto_gravado | número | Importe neto gravado. |
importe_neto_no_gravado | número | Importe neto no gravado. |
importe_exento | número | Importe exento. |
importe_iva | número | Importe de IVA. |
importe_tributos | número | Importe de otros tributos. |
tributos | array (opcional) | Otros tributos. |
autorizar | booleano | Si es true, el comprobante se autoriza ante AFIP automáticamente tras crearse. Si es false, queda como borrador para autorizar después. |
Ejemplo de body
Factura C de ejemplo, emitida a consumidor final y autorizada en el mismo paso:
{
"punto_venta": 1,
"tipo_documento": 99,
"numero_documento": "0",
"razon_social": "CONSUMIDOR FINAL",
"condicion_iva": "Consumidor Final",
"cotizacion": 1.0,
"items": [
{
"descripcion": "Servicio de consultoría",
"cantidad": 1,
"precio_unitario": 15000.00
}
],
"iva_items": [],
"importe_total": 15000.00,
"importe_neto_gravado": 0.00,
"importe_neto_no_gravado": 0.00,
"importe_exento": 0.00,
"importe_iva": 0.00,
"importe_tributos": 0.00,
"autorizar": true
}Ejemplo de respuesta
La respuesta exitosa incluye el _id del comprobante, el tipo_comprobante resuelto y los importes. Si el comprobante se autorizó, también devuelve el cae y la fecha_vencimiento_cae:
{
"success": true,
"data": {
"_id": "66f1a2b3c4d5e6f7a8b9c0d1",
"tipo_comprobante": 11,
"punto_venta": 1,
"numero_comprobante": 87,
"razon_social": "CONSUMIDOR FINAL",
"condicion_iva": "Consumidor Final",
"importe_total": 15000.00,
"importe_neto_gravado": 0.00,
"importe_iva": 0.00,
"estado": "autorizado",
"cae": "75123456789012",
"fecha_vencimiento_cae": "2026-05-31"
}
}Factura A: IVA discriminado
En una factura A o B el IVA se discrimina: el campo iva_items debe llevar un elemento por cada alícuota aplicada. Cada elemento tiene tres campos: Id (entero, el código de la alícuota de IVA), BaseImp (número, el neto gravado al que se aplica esa alícuota) e Importe (número, el IVA resultante). En el ejemplo, la alícuota 5 corresponde al 21%:
{
"tipo_comprobante": 1,
"punto_venta": 1,
"tipo_documento": 80,
"numero_documento": "30709876543",
"razon_social": "Comercial Andina S.A.",
"condicion_iva": "Responsable Inscripto",
"cotizacion": 1.0,
"items": [
{
"descripcion": "Servicio de consultoría",
"cantidad": 1,
"precio_unitario": 100000.00
}
],
"iva_items": [
{
"Id": 5,
"BaseImp": 100000.00,
"Importe": 21000.00
}
],
"importe_total": 121000.00,
"importe_neto_gravado": 100000.00,
"importe_neto_no_gravado": 0.00,
"importe_exento": 0.00,
"importe_iva": 21000.00,
"importe_tributos": 0.00,
"autorizar": true
}Flujo de emisión
Hay dos modos de emitir un comprobante, según el valor del campo autorizar:
1. Emisión directa
Enviá "autorizar": true en el body. El comprobante se crea y se autoriza ante AFIP en un solo paso, devolviendo directamente el CAE y su fecha de vencimiento. Es el modo más simple cuando los datos ya están validados.
2. Borrador + autorización
Creá el comprobante con "autorizar": false. Queda en estado de borrador, sin CAE. Cuando esté listo para emitirse, llamá a POST /authorize/{id}/ para autorizarlo ante AFIP y obtener el CAE. Este modo es útil para revisar el comprobante antes de emitirlo definitivamente.
El body de POST /authorize/{id}/ va vacío ({}): el entorno —producción u homologación— es configuración de la cuenta, no un parámetro del request.
{}La respuesta es el comprobante ya autorizado, con su cae y la fecha_vencimiento_cae asignados por AFIP:
{
"success": true,
"data": {
"_id": "66f1a2b3c4d5e6f7a8b9c0d1",
"tipo_comprobante": 1,
"punto_venta": 1,
"numero_comprobante": 142,
"importe_total": 121000.00,
"estado": "autorizado",
"cae": "75987654321098",
"fecha_vencimiento_cae": "2026-05-31"
}
}Notas de crédito y débito
Los endpoints POST /credit-note/ y POST /debit-note/ usan un body similar al de la factura, más un campo comprobantes_asociados (array) que referencia el comprobante original al que la nota se vincula.
Para calcular los importes de la nota podés usar POST /notes/calculate-amounts/, que los determina automáticamente, y validarlos contra el comprobante original con POST /notes/validate-amounts/. Los motivos válidos para cada tipo de nota se consultan con GET /notes/reasons/{tipo_nota}/.
Ejemplo de body para POST /credit-note/: es el mismo body de una factura más el array comprobantes_asociados, donde cada elemento referencia el comprobante original por tipo_comprobante, punto_venta y numero_comprobante. El body de POST /debit-note/ es idéntico, cambiando el tipo_comprobante por el de la nota de débito:
{
"tipo_comprobante": 3,
"punto_venta": 1,
"tipo_documento": 80,
"numero_documento": "30709876543",
"razon_social": "Comercial Andina S.A.",
"condicion_iva": "Responsable Inscripto",
"items": [
{
"descripcion": "Servicio de consultoría",
"cantidad": 1,
"precio_unitario": 100000.00
}
],
"iva_items": [
{
"Id": 5,
"BaseImp": 100000.00,
"Importe": 21000.00
}
],
"importe_total": 121000.00,
"importe_neto_gravado": 100000.00,
"importe_iva": 21000.00,
"comprobantes_asociados": [
{
"tipo_comprobante": 1,
"punto_venta": 1,
"numero_comprobante": 142
}
],
"autorizar": true
}La respuesta es la nota generada, con su propio _id y, si se autorizó, su cae:
{
"success": true,
"data": {
"_id": "66f1a2b3c4d5e6f7a8b9c0d2",
"tipo_comprobante": 3,
"punto_venta": 1,
"numero_comprobante": 17,
"importe_total": 121000.00,
"estado": "autorizado",
"cae": "75112233445566",
"fecha_vencimiento_cae": "2026-05-31"
}
}Anular un comprobante
POST /cancel/{id}/ anula un comprobante ya emitido: genera automáticamente una nota de crédito por el importe total del comprobante original. Es la forma correcta de revertir un comprobante que ya fue autorizado ante AFIP.
DELETE /{id}/, en cambio, solo elimina comprobantes que están en estado de borrador (no autorizados). Un comprobante autorizado no puede eliminarse, únicamente anularse.
El body de POST /cancel/{id}/ puede ir vacío ({}) o incluir un motivo de la anulación:
{
"motivo": "Comprobante emitido por error"
}La respuesta es la nota de crédito generada para revertir el comprobante original, ya autorizada y con su cae:
{
"success": true,
"data": {
"_id": "66f1a2b3c4d5e6f7a8b9c0d3",
"tipo_comprobante": 3,
"punto_venta": 1,
"numero_comprobante": 18,
"importe_total": 121000.00,
"estado": "autorizado",
"cae": "75223344556677",
"fecha_vencimiento_cae": "2026-05-31"
}
}Consultar comprobantes
GET /list/ devuelve los comprobantes de la cuenta con soporte de filtros y paginación, mientras que GET /{id}/ obtiene un comprobante puntual por su ID. Ejemplo de listado:
curl "https://api.yo-facturo.com/api/v1/bill/receipts/list/?page=1&limit=20" \ -H "X-API-Key: TU_TOKEN"
Representación impresa — PDF, HTML y links públicos
Una vez que el comprobante tiene CAE (estado aprobado) podés descargarlo como PDF, embeberlo como HTML, o generar un link público firmado para compartirlo por email/WhatsApp sin exponer tu API token. Todos los PDFs incluyen el QR AFIP per RG 4291/2018 (escaneable desde cualquier validador). Los PDFs aprobados se cachean en el servidor; el primer hit lo genera, los siguientes vienen del cache.
PDF — dos formatos
?format=a4 (default) es la representación A4 con los totales + QR + CAE anclados al pie. ?format=ticket es la versión 80mm para impresora térmica (POS); la altura del PDF se ajusta al contenido. ?download=1 fuerza Content-Disposition: attachment.
# PDF A4 (default) — abre en el browser curl "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/pdf/" \ -H "X-API-Key: TU_TOKEN" \ --output factura.pdf # Forzar descarga en lugar de inline curl "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/pdf/?download=1" \ -H "X-API-Key: TU_TOKEN" \ --output factura.pdf # Ticket térmico (80mm × alto dinámico) para impresora POS curl "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/pdf/?format=ticket" \ -H "X-API-Key: TU_TOKEN" \ --output factura_ticket.pdf
HTML embebible
Devuelve el comprobante como página HTML autocontenida (CSS inline, QR como data URI, sin recursos externos). Útil para iframe en tu propio sistema, previa antes de imprimir, o vista en el browser sin descargar el PDF. Header X-Frame-Options: SAMEORIGIN — embed solo desde el mismo origen.
# HTML embebible (CSS inline, QR como data URI, X-Frame-Options: SAMEORIGIN) curl "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/print/" \ -H "X-API-Key: TU_TOKEN" \ > factura.html
Link público compartible
Devuelve un token firmado (HMAC-SHA256, stateless — no se persiste) y dos URLs listas para compartir: pdf_url y view_url. Quien las recibe abre el comprobante sin necesitar el API token. La firma garantiza que nadie pueda fabricar URLs para comprobantes ajenos. expires_in_seconds es opcional (mínimo 60); sin ese campo, el link no expira.
POST /api/v1/bill/receipts/<COMP_ID>/public-link/
{
"expires_in_seconds": 86400 // opcional; sin esto el link no expira
}Response:
{
"success": true,
"data": {
"token": "eyJ0Ij...._sig",
"pdf_url": "https://api.yo-facturo.com/api/v1/public/comprobantes/<TOKEN>/pdf",
"view_url": "https://api.yo-facturo.com/api/v1/public/comprobantes/<TOKEN>/view",
"expires_at": 1748390400
}
}Las URLs públicas vienen con Cache-Control: public, max-age=31536000, immutable — Cloudflare las cachea por un año por cada variante (?format=a4 y ?format=ticket se cachean como entradas separadas). El comprobante con CAE es inmutable, así que es seguro.
Invalidar el PDF cacheado
Rara vez necesario (los comprobantes con CAE son inmutables), útil si actualizamos el template del PDF y querés forzar el re-render. DELETE /{id}/pdf/cache/ sin query params borra todas las variantes; con ?format=ticket borra sólo esa. Requiere scope invoices:write.
Diagnóstico y recuperación de comprobantes
Cada comprobante reserva su número en una secuencia local al crearse el borrador. Si ese borrador nunca llega a autorizarse —por un corte de red, una validación fallida o un rechazo de AFIP— la secuencia local queda adelantada respecto del último número realmente autorizado en AFIP. A partir de ahí, toda emisión posterior falla con el error AFIP 10016.
POST /doctor/ es el endpoint que cubre ambos casos: (a) diagnostica esa desincronización de numeración —compara, por cada tipo, el último número autorizado en AFIP contra la secuencia local— y (b) recupera comprobantes que quedaron procesando o en error: consulta AFIP por cada uno, adopta el CAE si ya fue autorizado, reintenta los que fallaron y deja para revisión manual los procesando que AFIP no confirma (no se reintentan a ciegas porque podrían ser autorizaciones en curso y duplicar el comprobante).
Tiene dos modos según el campo apply: con "apply": false (el valor por defecto) solo diagnostica y no modifica nada; con "apply": true además repara las secuencias desincronizadas y recupera los comprobantes atascados que se puedan resolver automáticamente.
Todos los campos del body son opcionales:
| Campo | Tipo | Descripción |
|---|---|---|
environment | string (opcional) | "testing" o "production". Por defecto se usa el entorno configurado en la cuenta. Alias deprecado: "ambiente". |
apply | booleano (opcional) | Si es false (por defecto), solo diagnostica sin modificar nada. Si es true, además repara la numeración y recupera comprobantes atascados. Debe ser un booleano JSON (true/false) — strings como "true" son rechazadas con 400. |
tipos | array de enteros (opcional) | Códigos de tipo de comprobante a revisar. Si se omite, se revisan los habituales (Factura A, B y C). Una lista vacía [] significa "ningún tipo" (no hace fallback al default). Strings se rechazan con 400. |
Ejemplo de petición en modo solo-diagnóstico, revisando las facturas A, B y C:
POST /api/v1/bill/receipts/doctor/
{
"environment": "testing",
"apply": false,
"tipos": [1, 6, 11]
}El campo data es el reporte completo. Incluye el bloque de numeración (detail: una entrada por tipo de comprobante con el último número autorizado en AFIP, la secuencia local y si están en sincronía) y el bloque stuck_receipts con los comprobantes en procesando/error que necesitan resolución. La action de cada atascado describe qué pasó: adopted_from_afip, reauthorized, processing_unconfirmed, number_reused, not_verifiable, etc.
{
"success": true,
"data": {
"environment": "production",
"cuit": "30709876543",
"punto_venta": 1,
"mode": "diagnosis",
"types_reviewed": 3,
"out_of_sync": 1,
"repaired": 0,
"detail": [
{
"tipo_comprobante": 1,
"afip_last_authorized": 142,
"local_sequence": 142,
"in_sync": true
},
{
"tipo_comprobante": 6,
"afip_last_authorized": 318,
"local_sequence": 320,
"in_sync": false,
"suggested_action": "resync local sequence to 318"
},
{
"tipo_comprobante": 11,
"afip_last_authorized": 87,
"local_sequence": 87,
"in_sync": true
}
],
"stuck_receipts": {
"found": 2,
"recovered": 0,
"retried_ok": 0,
"still_failing": 0,
"detail": [
{
"id": "8b12ed81-99b8-4f6e-b25c-0d7e94bcbcc8",
"tipo_comprobante": 6,
"numero_comprobante": 318,
"previous_state": "procesando",
"action": "pending — send apply=true to recover it"
},
{
"id": "2cfee208-e24f-4713-8d0e-201aabfa007e",
"tipo_comprobante": 6,
"numero_comprobante": 319,
"previous_state": "error",
"action": "pending — send apply=true to recover it"
}
]
}
},
"message": "Detected 1 out-of-sync sequence(s). Send apply=true to repair them. | 2 receipt(s) left unlegalized — send apply=true to recover them."
}Entorno: producción y homologación
El entorno —producción u homologación (testing)— es configuración de la cuenta, no un parámetro de cada request. Todos los comprobantes que emitís se autorizan contra el entorno configurado en tu cuenta. Una cuenta en homologación emite contra el ambiente de pruebas de AFIP: los comprobantes obtienen un CAE de homologación y no tienen validez fiscal.
Para cambiar el entorno de tu cuenta usá POST /api/v1/bill/tax_info/afip-environment/ (scope accounting:write) con el body {"environment": "testing"} — o production. Mientras integrás y probás, mantené la cuenta en testing; pasala a production recién cuando vayas a emitir comprobantes con validez fiscal.
Para probar el flujo en homologación no necesitás cargar un CUIT ni un certificado propio: YoFacturo usa de manera transparente el certificado y CUIT de homologación de la plataforma. Vos seguís viendo tu propio CUIT en la UI y en los payloads; el intercambio para llegar a los WS de AFIP es interno. Esto vale solo en testing — en production emitís con tu propio CUIT y tu propio certificado.
Para consultar en qué entorno está tu cuenta usá GET /api/v1/bill/tax_info/taxpayer/ (scope accounting:read): el campo afip_environment del taxpayer activo indica testing o production.
Las cuentas de prueba pueden estar bloqueadas en homologación: en ese caso el endpoint rechaza el cambio a producción y hay que solicitarlo al administrador. Es una protección para no emitir comprobantes reales por accidente desde una cuenta de pruebas.
Para verificar que la conexión con AFIP funciona correctamente usá POST /test-environment/, que prueba la comunicación con los servicios de AFIP del entorno configurado.
Recetas con curl — flujo de prueba end-to-end
Guía paso a paso para probar todo el sistema desde cero. Reemplazá TU_TOKEN por tu API token y COMP_ID por el _id que devuelva la emisión. No necesitás CUIT ni certificado de homologación propios: la plataforma usa los suyos de manera transparente cuando la cuenta está en testing.
Paso 1 — Activar el entorno de homologación
El entorno es configuración de la cuenta, no parámetro del request. Pasala a testing antes de probar para no emitir comprobantes con validez fiscal.
# 1) Pasar la cuenta a homologación (no requiere CUIT/cert propio)
curl -X POST "https://api.yo-facturo.com/api/v1/bill/tax_info/afip-environment/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"environment": "testing"}'Paso 2 — Confirmar el entorno actual
Verificá que el cambio se aplicó correctamente leyendo el taxpayer activo.
# 2) Verificar en qué entorno está la cuenta curl "https://api.yo-facturo.com/api/v1/bill/tax_info/taxpayer/" \ -H "X-API-Key: TU_TOKEN" # → el campo "afip_environment" del taxpayer activo es "testing" o "production"
Paso 3 — Probar la conexión con AFIP
Antes de emitir, asegurate de que los WS de AFIP del entorno configurado respondan.
# 3) Verificar conexión con AFIP del entorno configurado
curl -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/test-environment/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'Paso 4 — Emitir una Factura B a Consumidor Final
Con autorizar: true, la API obtiene el CAE en la misma llamada. Guardá el _id del response: lo vamos a usar como COMP_ID en los pasos siguientes.
# 4) Emitir Factura B a Consumidor Final (no discrimina IVA)
curl -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/invoice/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tipo_comprobante": 6,
"punto_venta": 1,
"tipo_documento": 99,
"numero_documento": "0",
"razon_social": "CONSUMIDOR FINAL",
"condicion_iva": "Consumidor Final",
"items": [
{"descripcion": "Producto demo", "cantidad": 1, "precio_unitario": 1000.00}
],
"iva_items": [
{"Id": 5, "BaseImp": 1000.00, "Importe": 210.00}
],
"importe_total": 1210.00,
"importe_neto_gravado": 1000.00,
"importe_neto_no_gravado": 0.00,
"importe_exento": 0.00,
"importe_iva": 210.00,
"importe_tributos": 0.00,
"autorizar": true
}'
# Guardá el "_id" devuelto — lo vamos a usar como <COMP_ID> en los pasos siguientes.Paso 5 — Listar los comprobantes emitidos
# 5) Listar comprobantes emitidos curl "https://api.yo-facturo.com/api/v1/bill/receipts/list/?page=1&limit=20" \ -H "X-API-Key: TU_TOKEN"
Paso 6 — Obtener un comprobante por su ID
# 6) Obtener un comprobante puntual curl "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/" \ -H "X-API-Key: TU_TOKEN"
Paso 7 — Descargar el PDF
El PDF viene en dos formatos: a4 (default, hoja A4 con QR AFIP) y ticket (80mm para impresora térmica, alto ajustado al contenido).
# 7) Descargar el PDF (A4 o ticket térmico 80mm) curl "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/pdf/" \ -H "X-API-Key: TU_TOKEN" \ --output factura.pdf # Versión ticket térmico 80mm: curl "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/pdf/?format=ticket" \ -H "X-API-Key: TU_TOKEN" \ --output factura_ticket.pdf
Paso 8 — Generar link público compartible
Devuelve dos URLs firmadas con HMAC: pdf_url (descarga directa) y view_url (HTML embebible). Quien las abre no necesita el API token; sirven para mandar la factura por WhatsApp o email al cliente final.
# 8) Generar link público compartible (firmado HMAC, no expone el API token)
curl -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/<COMP_ID>/public-link/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
# → devuelve pdf_url + view_url que se pueden mandar por WhatsApp / email.
# Para que el link expire, agregar "expires_in_seconds": 86400 (mínimo 60).Paso 9 — Anular el comprobante con una Nota de Crédito
cancel arma sola la NC por el total y la referencia al comprobante original. Solo funciona si el comprobante ya tiene CAE; si está en procesando, primero hay que resolverlo con el Doctor (paso 10).
# 9) Anular el comprobante emitiendo una Nota de Crédito por el total
curl -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/cancel/<COMP_ID>/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"motivo": "Comprobante emitido por error"}'
# La API arma sola la NC referenciando el comprobante original.Paso 10 — Doctor: arreglar comprobantes atascados o numeración
Si quedan facturas en procesando (autorización a medias) o error (rechazo de AFIP), o si la numeración local se desincronizó (error AFIP 10016), el Doctor consulta AFIP por cada caso y adopta el CAE existente, reintenta los rechazados, y resincroniza la numeración.
# 10) Si quedan facturas en estado "procesando" o "error", correr el Doctor
# Primero en modo solo-diagnóstico (no aplica cambios):
curl -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/doctor/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"environment": "testing", "apply": false}'
# Si el diagnóstico muestra problemas, aplicarlos:
curl -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/doctor/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"environment": "testing", "apply": true}'
# Nota: apply DEBE ser boolean JSON (true/false), no string "true".Paso 11 — Pasar a producción cuando termines de probar
A partir de acá los comprobantes tienen validez fiscal real y la cuenta usa tu propio CUIT y certificado. Si la cuenta está bloqueada en testing, el cambio se rechaza y hay que pedirlo al administrador.
# 11) Cuando termines de probar, volver a producción (validez fiscal real)
curl -X POST "https://api.yo-facturo.com/api/v1/bill/tax_info/afip-environment/" \
-H "X-API-Key: TU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"environment": "production"}'