# 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.

```bash
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:

```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:

```js
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.

```bash
# 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.

```bash
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

1. **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](https://yo-facturo.com/dev/arca/delegar-web-service-facturacion/) explica el paso a paso. Confirmalo con `POST /bill/tax_info/verify-delegation/` y el cuerpo `{"cuit": "..."}`.
2. **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.
3. **Sacá `"ambiente": "testing"`** de tus requests, porque el valor por defecto es producción, y usá una clave `yf_live_*`. Mantené el `Idempotency-Key` en cada escritura.
4. **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.

1. **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`.
2. **Autorizá.** El cliente abre tu navegador; iniciá sesión en YoFacturo y aprobá `yofacturo:read`, `yofacturo:write` o ambos. Una conexión de solo lectura nunca puede modificar nada.
3. **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](https://yo-facturo.com/dev/mcp/).

## Seguí leyendo

- [Conectar un asistente de IA por MCP](https://yo-facturo.com/dev/mcp/)
- [Referencia de la API por recurso y operación](https://yo-facturo.com/dev/referencia/)
- [Delegar el web service de facturación en ARCA](https://yo-facturo.com/dev/arca/delegar-web-service-facturacion/)
- [API de facturación electrónica de YoFacturo](https://yo-facturo.com/api-facturacion/)
- [Autenticación y tokens](https://yo-facturo.com/dev/authentication/)
- [Especificación OpenAPI (JSON)](https://api.yo-facturo.com/api/v1/openapi.json)
- [API de facturación electrónica de YoFacturo](https://yo-facturo.com/api-facturacion/)
- [English version](https://yo-facturo.com/en/dev/quickstart/)

Fuente: https://yo-facturo.com/dev/quickstart/
