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.
El set de arranque
La primera llave de una cuenta se mintea con estos seis, que son exactamente lo que recorre el quickstart de punta a punta:
documents:read, documents:write, empresas:read, empresas:write, webhooks:read, webhooks:writeNi uno más. keys:write queda fuera porque es el poder de una llave root, y los cuatro scopes de la
puesta en marcha quedan fuera porque conceden actos con efecto legal.
Los scopes de la puesta en marcha
Cuatro scopes estrechos gobiernan los actos que autorizan a Facturia ante el SII (disponibles desde v1.1). Ninguno entra en el set de arranque, ni por defecto ni por conveniencia, y se piden uno por uno:
| Scope | Concede |
|---|---|
mandato:write | Acuñar el enlace de firma del mandato y leerlo (GET …/mandato) |
mandato:attest | Postear una aceptación con cuerpo (el integrador recogió la firma en su propio flujo; queda registrado como acceptance_method: api) y revocar el mandato con DELETE …/mandato — la revocación es el acto de mayor efecto del contrato y desde v1.1 no la concede empresas:write |
onboarding:write | Acuñar enlaces de pasos humanos, pedir una re-lectura, acuñar el enlace de aprobación de go_live, cargar el certificado |
onboarding:attest | Postear la autorización de go_live con cuerpo |
empresas:write implica los dos scopes :write (mandato:write, onboarding:write) — así una
llave que ya existe sigue pudiendo acuñar el enlace de firma y los enlaces de los pasos humanos. No
implica ninguno de los dos :attest: esos se piden explícitamente o no se conceden nunca (ADR-0012
§4). Una llave con solo empresas:write que intenta POST …/mandato con cuerpo recibe 403 insufficient_scope: mandato:attest, exactamente como si no tuviera ningún scope de la puesta en
marcha. La diferencia entre :write y :attest es la diferencia entre pedirle a una persona que
apruebe y afirmar que ya aprobó en otra parte: lo segundo es una atestación, se registra
visiblemente como tal, y por eso vive detrás de su propio scope que nunca se concede por implicación
ni por defecto. El camino completo está en De sandbox a producción.
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 de cuenta es la única credencial que mintea una llave root:
POST /dashboard/api_keyscon{"root": true}(sinscopesniempresas) devuelve unask_live_root_…/sk_test_root_…sin abrir ningún panel. Una llave —root u ordinaria— que pideroot: truerecibe403 privilege_escalation: la delegación llega hasta un nivel y una llave root no mintea otra llave root. Ver Llaves root y rotación.