Scopes y empresas
Qué concede cada scope, cómo se combina con la lista blanca de empresas y qué error recibes cuando falta uno.
La tabla de scopes
| Scope | Concede |
|---|---|
documents:read | Leer documentos emitidos, PDF, XML y eventos |
documents:write | Emitir documentos, reintentar, enviar por correo |
received:read | Leer los DTE recibidos de proveedores |
received:write | Aceptar / reclamar / acusar recibo |
empresas:read | Leer empresas, puesta en marcha, configuración, folios |
empresas:write | Crear empresas, cargar certificados, cambiar configuración |
folios:write | Solicitar CAF al SII, cargar CAF |
tax:read | RCV, propuestas y declaraciones de F29, sugerencias |
tax:write | Caracterizar, declarar F29, confirmar sugerencias, ingresar gastos |
webhooks:read / webhooks:write | Endpoints de webhook y replay de eventos |
usage:read | Libro de consumo |
keys:write | Mintear, rotar y revocar llaves de API. Solo llaves root; nunca combinado con los scopes de arriba |
Si falta un scope recibes 403 insufficient_scope, con el scope requerido nombrado en
error.message. No tienes que adivinar cuál era.
Trampa
Una llave root no puede leer documentos
keys:write no se combina con ningún otro scope. Una llave root (sk_live_root_… /
sk_test_root_…) no puede emitir, no puede leer documentos y no puede tocar datos tributarios:
su único poder es mintear y revocar otras llaves.
Es la confusión más común al empezar: minteas la llave root, la pruebas contra /v1/documents y
recibes un 403. No está rota — está haciendo exactamente lo que debe. Mintea con ella una llave
ordinaria y usa esa.
Lista blanca de empresas
Además de los scopes, cada llave lleva una lista de empresas:
["*"]— toda empresa de la cuenta, incluidas las que se creen después.- Una lista explícita de RUT —
["77928532-4", "78281439-7"].
Una llave con exactamente un RUT es un token de empresa
y el header Facturia-Empresa se vuelve opcional.
Los dos ejes se aplican juntos: una llave con documents:write sobre ["77928532-4"] puede emitir
para esa empresa y para ninguna otra. Nombrar otra empresa devuelve 403 empresa_not_allowed — no un
404, porque ya conoces su RUT y fingir que no existe no protege a nadie.
Combinaciones que conviene tener en la cabeza
| Forma | Scopes | Empresas | Para qué |
|---|---|---|---|
| Backend de un producto propio | documents:*, received:*, tax:* | ["*"] | Una sola llave que opera todas las empresas de la cuenta |
| Llave por cliente (ERP, SaaS vertical) | lo mínimo que ese cliente necesita | un solo RUT | El sistema del cliente no puede direccionar nada más |
| Solo lectura para BI o conciliación | documents:read, tax:read, usage:read | ["*"] | Una llave que no puede emitir aunque se filtre |
| Root | keys:write | según lo que va a delegar | Mintear y revocar llaves. Nada más |
| Exploración y demos | cualquiera, pero sk_test_ | cualquiera | Una llave de test es un límite de capacidad, no una política |
Modo de sesión: Facturia-Mode
La superficie /dashboard/* se autentica con un JWT de cuenta en vez de una llave sk_, porque un
navegador nunca debe sostener una llave sk_. Una sesión no tiene prefijo que cargue su modo, así
que el modo viaja en un header:
Facturia-Mode: testPor defecto es live. El backend lo aplica exactamente igual que aplicaría el modo de una llave: en
modo live una empresa de sandbox no existe, y viceversa. Un valor no reconocido es un 400, nunca
una caída silenciosa a live.
Dos reglas aplican a una sesión que no aplican a una llave:
- Una sesión puede mintear llaves Y leer datos. Una llave root no puede lo segundo. La diferencia es intencional: una llave root es una credencial delegada, y una sesión es el dueño de la cuenta en persona.
- Una sesión mintea solo llaves ordinarias — nunca una llave root, y nunca una llave con
keys:write.