Facturiadocs
Autenticación

Llaves root y rotación

Mintear una llave por empresa cliente sin que un humano abra un panel, rotar secretos sin corte y el arranque en frío de una cuenta nueva.

Si estás incrustando Facturia en tu propio producto — un SaaS vertical, un ERP, un estudio contable — vas a querer mintear una llave por empresa cliente sin que un humano abra un panel. Eso es un flujo de primera clase en la v1.

La llave root

Los endpoints de gestión de llaves se autentican con una llave root (sk_live_root_… / sk_test_root_…), emitida una vez en el panel y portadora del scope keys:write.

Una llave root no puede emitir, no puede leer documentos y no puede tocar datos tributarios. Su único poder es mintear y revocar otras llaves. Ten exactamente una, guárdala donde guardas las credenciales de tu base de datos, y nunca la despliegues a un runtime de edge.

Mintear

curl -sS https://api.facturia.cl/v1/api_keys \
  -H "Authorization: Bearer $FACTURIA_ROOT_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "cliente — Comercial Andina",
    "mode": "live",
    "scopes": ["documents:read", "documents:write", "received:read"],
    "empresas": ["76543212-K"]
  }'
{
  "id": "key_01K2QWB7T4N9",
  "object": "api_key",
  "name": "cliente — Comercial Andina",
  "mode": "live",
  "secret": "sk_live_qT8vN2wLmR5xKpJ7hYdCbA3s",
  "last4": "bA3s",
  "scopes": ["documents:read", "documents:write", "received:read"],
  "empresas": ["76543212-K"],
  "created_at": "2026-08-14T13:12:40Z"
}

secret se devuelve exactamente una vez. Como esta llave nombra una sola empresa, es un token de empresa: entrégasela al sistema de ese cliente y no podrá direccionar nada más.

Las tres barreras

Se aplican en el servidor, no en tu código:

Una llave minteada nunca puede alcanzar más que quien la mintea. Sus empresas deben ser un subconjunto de la lista blanca de la llave minteadora, y sus scopes un subconjunto de los suyos. Una llave root con ["*"] puede mintear cualquier cosa de la cuenta; una restringida a tres RUT solo puede producir llaves dentro de esos tres. Las violaciones devuelven 403 privilege_escalation nombrando el RUT o el scope ofensor.

El modo se hereda. Una llave sk_test_root_ solo mintea llaves de test. No hay camino de una credencial de test a una live.

Una llave root no puede mintear llaves root. La delegación es de un nivel de profundidad, por diseño. Si necesitas una segunda llave root, créala en el panel.

Listar, rotar, revocar

# Listar (solo metadatos — los secretos no son legibles, ni siquiera por una llave root)
curl https://api.facturia.cl/v1/api_keys -H "Authorization: Bearer $FACTURIA_ROOT_KEY"

# Rotar: emite un secreto de reemplazo; el anterior sigue funcionando 24 h,
# así que puedes desplegar sin corte
curl -X POST https://api.facturia.cl/v1/api_keys/key_01K2QWB7T4N9/roll \
  -H "Authorization: Bearer $FACTURIA_ROOT_KEY"

# Revocar de inmediato
curl -X DELETE https://api.facturia.cl/v1/api_keys/key_01K2QWB7T4N9 \
  -H "Authorization: Bearer $FACTURIA_ROOT_KEY"

Una llave ordinaria (no root) que llame a GET /v1/api_keys se ve solo a sí misma — útil como health check, inútil como inventario.

Todo esto queda auditado: api_key.created, api_key.rolled y api_key.revoked caen en el libro de eventos con el id de la llave que las minteó.

Rotar no es revocar

POST /v1/api_keys/{key_id}/roll deja el secreto anterior vivo 24 horas para que puedas desplegar sin ventana de caída. Si estás rotando porque una llave se filtró, rota y después revoca — o revoca directamente y asume el corte. Las 24 horas son una comodidad de despliegue, no una respuesta a incidentes.

El arranque en frío

Todo lo anterior necesita una llave root, y una cuenta nueva no tiene ninguna. La salida es la sesión de cuenta: el mismo JWT de una hora que devuelve POST /account/login.

# 1. Registrarte (o iniciar sesión). No se necesita navegador: es una llamada normal.
TOKEN=$(curl -sS https://api.facturia.cl/account/register \
  -H "Content-Type: application/json" \
  -d '{"email":"tu@empresa.cl","password":"..."}' | jq -r .data.token)

# 2. 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 una superficie deliberadamente estrecha: empresas, documentos, documentos recibidos, consumo, llaves de API y certificados, y nada más. En particular, no puede emitir.

POST /account/login y POST /account/register reportan ambos emailVerified, así que un cliente puede mostrar el estado sin una segunda llamada. Mintear una llave sk_live_ desde una cuenta sin verificar devuelve 403 email_verification_required; el modo test no se ve afectado.

En esta página