Quickstart: tu primera factura electrónica por API
Esta guía lleva a un desarrollador o a un agente de IA desde cero hasta una factura electrónica con CAE (el código de autorización de ARCA), y después a webhooks y producción. La URL base es https://api.yo-facturo.com/api/v1.
Dos formas de entrar
Elegí una. La API REST con un token (yf_test_* o yf_live_*) te da control total, incluida la facturación, y está disponible en el plan Premium y durante la prueba gratis de 15 días (+15 al completar la activación). El servidor MCP da acceso conversacional desde Claude, ChatGPT o Cursor con un inicio de sesión OAuth y sin token para copiar; está disponible desde el plan Básico. La última sección cubre MCP.
1. Conseguí una clave sandbox
En el panel andá a Configuración, Integraciones, API Tokens y creá un token en modo test. Un token yf_test_* trabaja sobre una base sandbox aislada y nunca toca datos reales. El token se muestra una sola vez, así que guardalo enseguida.
Para esta guía el token necesita los scopes invoices:write, invoices:read, webhooks:write y webhooks:read, más accounting:write si querés cambiar el entorno de ARCA. Mandá la clave en cualquiera de los dos headers; si van los dos, gana X-API-Key.
X-API-Key: yf_test_xxxxxxxx
Authorization: Bearer yf_test_xxxxxxxx
Los límites son 10 requests por segundo, 100 por minuto, 3.000 por hora y 20.000 por día para toda la cuenta, compartidos entre todos los tokens. Crear y autorizar comprobantes tiene además un tope de 30 cada 5 minutos.
2. Emití una factura en el sandbox
Con una clave de test, POST /bill/receipts/invoice/ nunca llama a ARCA. Guarda una factura simulada con simulated: true, livemode: false y un CAE sintético, que es lo que querés mientras armás la integración. Los precios de items son finales, con IVA incluido.
Mandá siempre un Idempotency-Key. Si repetís la misma clave con el mismo cuerpo, la API devuelve la primera respuesta y agrega el header Idempotency-Replayed: true; la misma clave con otro cuerpo devuelve 422.
curl -s -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/invoice/" \
-H "X-API-Key: $YF_TEST_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"punto_venta": 1,
"concepto": 1,
"tipo_comprobante": 6,
"tipo_documento": 99,
"numero_documento": "0",
"razon_social": "Consumidor Final",
"condicion_iva_receptor_id": 5,
"items": [{"descripcion": "Item de prueba", "cantidad": 1, "precio_unitario": 1000}]
}'
La respuesta tiene la forma {"success": true, "data": {"id": "...", "cae": "...", "simulated": true, "livemode": false}}. Leé data.cae. La misma llamada en Python:
import os, uuid, requests
BASE = "https://api.yo-facturo.com/api/v1"
H = {"X-API-Key": os.environ["YF_TEST_KEY"]}
body = {
"punto_venta": 1, "concepto": 1, "tipo_comprobante": 6,
"tipo_documento": 99, "numero_documento": "0",
"razon_social": "Consumidor Final", "condicion_iva_receptor_id": 5,
"items": [{"descripcion": "Item de prueba", "cantidad": 1, "precio_unitario": 1000}],
}
r = requests.post(f"{BASE}/bill/receipts/invoice/", json=body,
headers={**H, "Idempotency-Key": str(uuid.uuid4())}, timeout=30)
r.raise_for_status()
invoice = r.json()["data"]
print(invoice["id"], invoice.get("cae"), invoice.get("simulated"))
Y en Node.js 18 o superior:
const BASE = "https://api.yo-facturo.com/api/v1";
const res = await fetch(`${BASE}/bill/receipts/invoice/`, {
method: "POST",
headers: {
"X-API-Key": process.env.YF_TEST_KEY,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
punto_venta: 1, concepto: 1, tipo_comprobante: 6,
tipo_documento: 99, numero_documento: "0",
razon_social: "Consumidor Final", condicion_iva_receptor_id: 5,
items: [{ descripcion: "Item de prueba", cantidad: 1, precio_unitario: 1000 }],
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const { data } = await res.json();
console.log(data.id, data.cae, data.simulated);
Podés vaciar el sandbox cuando quieras con POST /sandbox/reset/. Solo funciona con una clave de test; con una clave live devuelve 403.
3. Conseguí un CAE real de homologación de ARCA
El CAE del sandbox es sintético. Para obtener un CAE emitido por los web services de homologación de ARCA, usá una clave live en una cuenta pasada al entorno de testing. En testing no necesitás certificado ni delegación propios: se usan el CUIT y el certificado de homologación de la plataforma.
# 1) pasá la cuenta a homologación de ARCA (scope accounting:write)
curl -s -X POST "https://api.yo-facturo.com/api/v1/bill/tax_info/afip-environment/" \
-H "X-API-Key: $YF_LIVE_KEY" -H "Content-Type: application/json" \
-d '{"environment": "testing"}'
# 2) creá la factura como borrador. "ambiente" se lee del cuerpo de cada request
# y por defecto es "production": mandá siempre "testing" mientras probás.
curl -s -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/invoice/" \
-H "X-API-Key: $YF_LIVE_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"ambiente": "testing", "autorizar": false, "punto_venta": 1, "concepto": 1,
"tipo_comprobante": 6, "tipo_documento": 99, "numero_documento": "0",
"razon_social": "Consumidor Final", "condicion_iva_receptor_id": 5,
"items": [{"descripcion": "Prueba de homologación", "cantidad": 1, "precio_unitario": 1000}]}'
# 3) autorizala: es sincrónico, devuelve el CAE o el motivo de rechazo de ARCA en un 400
curl -s -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/authorize/<id>/" \
-H "X-API-Key: $YF_LIVE_KEY" -H "Content-Type: application/json" \
-d '{"ambiente": "testing"}'
El data.cae de la respuesta de authorize es el CAE de homologación. Por qué dos pasos: con "autorizar": true en el paso 2 la autorización corre en segundo plano y la respuesta trae authorization_pending: true sin CAE todavía, así que tendrías que consultar GET /bill/receipts/{id}/. El flujo en dos pasos es sincrónico y muestra el motivo del rechazo, que es justo lo que un agente necesita para corregirse.
Una trampa conocida: el número de comprobante se reserva al crear, no al autorizar. Si ARCA rechaza un borrador, las facturas siguientes pueden fallar con el error 10016 de ARCA hasta que corras POST /bill/receipts/doctor/ con {"apply": true}.
4. Suscribite a un webhook
Registrá un endpoint con el scope webhooks:write. El secreto de firma se devuelve una sola vez.
curl -s -X POST "https://api.yo-facturo.com/api/v1/webhooks/endpoints" \
-H "X-API-Key: $YF_LIVE_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://example.com/yf-webhook", "events": ["invoice.authorized"], "description": "agente"}'
# -> 201 {"data": {"id": "...", "secret": "whsec_...", "events": [...], "mode": "live"}}
Las entregas son requests POST con los headers X-YF-Signature, X-YF-Event y X-YF-Delivery. Verificá la firma antes de confiar en el cuerpo. Respondé con un 2xx dentro de los 10 segundos; los timeouts, los 429 y los 5xx se reintentan con espera creciente.
5. Pasá a producción
- Delegá el servicio de facturación. Producción exige que el contribuyente delegue el servicio de facturación electrónica (wsfe) al CUIT de la plataforma en el portal de ARCA; la guía Delegar el web service de facturación explica el paso a paso. Confirmalo con
POST /bill/tax_info/verify-delegation/y el cuerpo{"cuit": "..."}. - Volvé el entorno a producción con
POST /bill/tax_info/afip-environment/y{"environment": "production"}. Las cuentas marcadas como testing por un administrador no pueden hacerlo solas. - Sacá
"ambiente": "testing"de tus requests, porque el valor por defecto es producción, y usá una claveyf_live_*. Mantené elIdempotency-Keyen cada escritura. - Las plataformas que facturan para muchos CUIT usan cuentas partner, que registran cada contribuyente con
POST /partner/taxpayers/y emiten A o B para responsables inscriptos y C para monotributistas o exentos. El acceso partner se otorga por contrato.
Conectá un asistente de IA por MCP
El servidor MCP está en https://api.yo-facturo.com/api/v1/mcp. Usa transporte Streamable HTTP y OAuth 2.1 con PKCE y registro dinámico de clientes, así que no hay token para pegar.
- Agregá el servidor. En Claude Code corré
claude mcp add --transport http yofacturo https://api.yo-facturo.com/api/v1/mcp. En Claude Desktop o claude.ai sumá un conector personalizado con la misma URL. En ChatGPT creá un conector MCP personalizado en modo desarrollador. En Cursor agregá{"mcpServers": {"yofacturo": {"url": "https://api.yo-facturo.com/api/v1/mcp"}}}a~/.cursor/mcp.json. - Autorizá. El cliente abre tu navegador; iniciá sesión en YoFacturo y aprobá
yofacturo:read,yofacturo:writeo ambos. Una conexión de solo lectura nunca puede modificar nada. - Pedí. Por ejemplo, "listá las ventas de este mes" o "creá un cliente llamado ACME". Podés revocar la conexión cuando quieras en el panel, en Configuración, Integraciones, Servidor MCP.
Más detalle de cada cliente en la guía MCP.



