Quickstart
De una cuenta nueva a una boleta emitida en el sandbox, con el ciclo queued → accepted completo y sin tocar el SII.
Todo lo de esta página ocurre en modo test: no hay tráfico al SII, no hay certificado, no hay
CAF y no hay costo. Cuando cambies sk_test_ por sk_live_, la misma llamada golpea el SII real.
1. Consigue tu primera llave
Una cuenta recién creada no tiene ninguna llave todavía. La salida es la sesión de cuenta: el
mismo JWT de una hora que devuelve POST /account/login, presentado a la superficie del panel.
# Registrarte (o iniciar sesión). No necesitas un navegador: es una llamada normal.
TOKEN=$(curl -sS https://api.facturia.cl/account/register \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"..."}' | jq -r .data.token)
# Mintear la primera llave con la sesión, no con una llave que todavía no tienes.
curl -sS https://api.facturia.cl/dashboard/api_keys \
-H "Authorization: Bearer $TOKEN" \
-H "Facturia-Mode: test" \
-H "Content-Type: application/json" \
-d '{"name":"primera llave","scopes":["documents:read","documents:write"],"empresas":["*"]}'/dashboard/* es la superficie de sesión de cuenta. Sirve los mismos recursos que /v1 — los
mismos serializadores, los mismos filtros, el mismo sobre de error — autenticada con un JWT de
cuenta en vez de una llave sk_, porque un navegador nunca debe sostener una llave sk_.
El modo viaja en un header en la sesión
Una sesión no tiene prefijo que cargue su modo, así que lo hace Facturia-Mode: test|live, con
live por defecto. Un valor no reconocido es un 400, nunca una caída silenciosa a live.
Guarda el secreto: se devuelve exactamente una vez.
export FACTURIA_KEY=sk_test_9lQpV3fA2mKcRt7wZxYb1Nde
export EMPRESA=77928532-42. Crea una empresa de sandbox
En modo test la empresa nace lista para emitir: sin certificado, sin mandato y sin certificación.
curl -sS https://api.facturia.cl/v1/empresas \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Content-Type: application/json" \
-d '{"rut":"77928532-4","legal_name":"Connect SpA"}'Solo rut y legal_name son obligatorios. El resto lo leemos del registro de contribuyentes del
SII una vez cargado el certificado, y puedes sobrescribir cualquier campo después.
3. Emite una boleta electrónica
Dos campos.
curl -sS https://api.facturia.cl/v1/documents \
-H "Authorization: Bearer $FACTURIA_KEY" \
-H "Facturia-Empresa: $EMPRESA" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"tipo_dte": 39,
"items": [{ "description": "Plan Pro mensual", "quantity": 1, "unit_price": 29990 }]
}'La respuesta es 201 y llega de inmediato:
{
"id": "doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N",
"object": "document",
"mode": "test",
"status": "queued",
"tipo_dte": 39,
"folio": 1,
"issue_date": "2026-08-14",
"totals": { "net": 25202, "iva": 4788, "exempt": 0, "total": 29990 },
"pdf_url": "https://api.facturia.cl/v1/documents/doc_01K2R7.../pdf",
"xml_url": "https://api.facturia.cl/v1/documents/doc_01K2R7.../xml",
"sii": { "environment": "sandbox", "track_id": null, "estado": null },
"created_at": "2026-08-14T13:04:11Z"
}Fíjate en tres cosas: el folio ya está asignado (1, porque en modo test los folios parten en 1 por
cada (empresa, tipo_dte)), los totales ya están calculados (una boleta trae los precios brutos, así
que 29.990 se descompone en neto e IVA), y el status es queued, no accepted.
4. El ciclo de vida honesto: queued → sent → accepted
El POST es síncrono. La ida y vuelta al SII no lo es, y no fingimos lo contrario.
┌───────────► rejected (terminal)
│
queued ──► sent ──────┼───────────► reparo (terminal-ish; válido pero observado)
│ │
│ └───────────► accepted ──► annulled (una NC lo anuló)
│
└──► failed ──(retry)──► queuedEn el sandbox el documento se asienta en accepted en aproximadamente un segundo, disparando cada
webhook que dispararía un documento real. En producción el trayecto típico a un estado terminal es
de 30 segundos a unos pocos minutos, y el SII puede tardar horas en sus peaks o en mantención.
curl https://api.facturia.cl/v1/documents/doc_01K2R7Q4XW9M3B8ZC5YHTVJD6N \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA"# Los eventos del documento, del más antiguo al más nuevo
curl https://api.facturia.cl/v1/documents/doc_01K2R7.../events \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA"{
"object": "list",
"data": [
{ "type": "document.created", "at": "2026-08-14T13:04:11Z", "detail": { "folio": 1 } },
{ "type": "document.sent", "at": "2026-08-14T13:04:19Z", "detail": { "track_id": "9000000001" } },
{ "type": "document.accepted", "at": "2026-08-14T13:04:20Z", "detail": { "estado": "DOK" } }
]
}No construyas sobre polling apretado
Los webhooks son la integración prevista. Si igual necesitas hacer polling: no consultes
GET /v1/documents/{document_id} más seguido que cada 10 segundos durante los primeros 2
minutos, y luego cada 60 segundos. Mejor aún, consulta el listado con
status=sent&created_at[gte]=… una vez por minuto y reconcilia en bloque. El header
Facturia-Poll-After en la respuesta del documento te dice el próximo momento útil, calculado por
nuestro propio scheduler.
5. Baja el PDF
curl -L https://api.facturia.cl/v1/documents/doc_01K2R7.../pdf \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Facturia-Empresa: $EMPRESA" -o boleta.pdfEn modo test el PDF trae el layout real con una marca de agua SIN VALOR TRIBUTARIO.
6. Recibe el webhook en vez de preguntar
curl -sS https://api.facturia.cl/v1/webhook_endpoints \
-H "Authorization: Bearer $FACTURIA_KEY" -H "Content-Type: application/json" \
-d '{
"url": "https://api.miempresa.cl/hooks/facturia",
"enabled_events": ["document.accepted","document.rejected","document.reparo"]
}'El secret (whsec_…) se devuelve una sola vez. Cómo verificar la firma está en
Webhooks · Firma.
Y ahora, en serio
Cambiar sk_test_ por sk_live_ cambia lo que pasa en el cable, no tu código. Lo que sí cambia es
que la empresa necesita recorrer una puesta en marcha real: mandato, certificado, postulación,
certificación y timbraje. Eso está en Empresas y lo maneja un solo
endpoint que puedes dibujar como asistente: GET /v1/empresas/{empresa_id}/onboarding.