Alcanzar un NIF por el segmento de empresa
Trabaja con cualquier NIF que alcanza tu credencial nombrándolo en el segmento de empresa de la ruta — los propios, los de un acceso cedido y los de cuentas gestionadas — con cómo resolver su id, las respuestas que obtienes y la cabecera X-Active-Profile retirada.
Todo recurso de empresa de la API v1 cuelga de /v1/companies/{company}/…, donde {company} es el id público (UUID v7) del NIF sobre el que opera la petición. Funciona igual en todos los recursos de empresa, facturas, contactos, series y el resto:
curl https://api.factuarea.com/v1/companies/$COMPANY_ID/invoices \
-H "Authorization: Bearer $FACTUAREA_KEY"Una credencial alcanza todos los NIF de su ámbito, y eliges el destino en cada petición, en la ruta, sin reautenticarte ni manejar una clave por NIF. Esta página explica ese segmento de la ruta. Para dar a una integración solo una parte de la cuenta, acota la clave en su lugar.
Cuando el segmento nombra un NIF que tu credencial alcanza, la petición entera se ejecuta contra sus datos: toda lectura se filtra a él y toda escritura cae en él. El NIF se resuelve antes del límite de peticiones, de la idempotencia y del registro de consumo, así que los tres se atribuyen al NIF que nombras y no a la empresa titular de la credencial.
El segmento no es opcional. No hay ninguna ruta a un recurso de empresa sin él, así que ninguna petición puede acabar en un NIF que no nombraste, que es justo la garantía que la cabecera retirada no podía dar.
El segmento nunca amplía tu credencial. Sus scopes, su tier y su environment pasan intactos: una clave que solo tiene invoices:read y nombra un NIF sigue sin poder hacer POST /v1/companies/{company}/invoices en él (403 insufficient_scope), y una clave fact_test_ se queda en el sandbox sea cual sea el NIF que nombre. Elegir un NIF cambia sobre cuál actúas, nunca qué tienes permitido hacer.
Qué puede contener el ámbito de una credencial
El ámbito de una clave es la lista de NIF que alcanza, fijada cuando se emite la clave y cambiada con PATCH …/nif-scope. Puede contener tres clases de NIF, y cada uno lleva un nivel, view u operate:
| NIF | Cómo entra en el ámbito | Nivel que lleva |
|---|---|---|
| Los tuyos | Lo nombras en scoped_company_ids al emitir la clave, o la clave hereda el ámbito de la clave que la emitió. | El nivel que tiene en ese NIF la persona que emitió la clave. |
| Cedido por otra cuenta | El acceso cedido está vigente, y nombras el NIF al emitir la clave o al cambiar su ámbito. | El menor entre el nivel del acceso y el de la persona que emitió la clave, que para un member queda además limitado por su grant. |
| De una cuenta gestionada que aprovisionaste | La gestión está vigente con un nivel distinto de none, y nombras el NIF de la misma forma. Consulta las cuentas gestionadas. | El menor entre tu nivel en la cuenta gestionada y el de la persona que emitió la clave. |
Un nivel se fija cuando el NIF entra en la clave y solo baja: las claves acotadas explican cómo. Cuando un acceso se reduce o termina, el NIF sale del ámbito de tus claves en la siguiente petición. Las claves siguen funcionando sobre el resto, y una que se queda con el ámbito vacío se revoca.
El servidor MCP alcanza los mismos NIF: nombra el NIF con la cabecera X-Company-Id en lugar de un segmento de la ruta.
Resuelve el identificador del NIF
El segmento lleva el id opaco, nunca el tax_id. Tres sitios te lo dan, y ninguno exige que lo construyas a mano:
GET /v1/meintrospecciona la credencial que llama y enumera, enscope, cada NIF que alcanza con suid,tax_idyname. Lo hace siempre, también cuando hay exactamente uno. Suaccount.ides el identificador que espera el segmento/v1/accounts/{account}/….GET /v1/accounts/{account}/companies?tax_id=B12345674busca un NIF de tu propia cuenta por su identificador fiscal. Un número fiscal fuera de tu ámbito devuelve una lista vacía, nunca un rechazo. No lista los NIF que alcanzas por una relación.- Los NIF de una cuenta gestionada vienen en
companies[]deGET /v1/accounts/{account}, como describen las cuentas gestionadas.
curl https://api.factuarea.com/v1/me \
-H "Authorization: Bearer $FACTUAREA_KEY"{
"data": {
"object": "me",
"account": {
"id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a00",
"name": "Asesoría Martínez",
"environment": "live",
"is_provider": true,
"privileged_scopes": [
"accounts:read",
"accounts:write"
]
},
"api_key": {
"id": "019e81ef-e1d4-7208-a51d-94c2c2a54a84",
"name": "Producción",
"prefix": "fact_live_1OSf9KdP",
"scopes": [
"account:read",
"series:read",
"series:write"
],
"tier": "scale",
"environment": "live",
"created_at": "2026-01-15T09:30:00Z",
"last_used_at": "2026-05-25T18:00:00Z",
"expires_at": null
},
"scope": [
{
"id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a01",
"tax_id": "B12345674",
"name": "Acme Corporation"
},
{
"id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a02",
"tax_id": "B87654323",
"name": "Acme Logística S.L."
}
],
"client_accounts": [
{
"id": "0199a1f0-1c22-7a10-b111-5a5b5c5d5e5f",
"name": "Construcciones Ruiz",
"origin": "granted",
"access_level": "view",
"status": "active",
"paid_by_provider": false,
"environment": "live"
},
{
"id": "0199a1f0-1c22-7a10-b111-6a6b6c6d6e6f",
"name": "Talleres García",
"origin": "provisioned",
"access_level": "operate",
"status": "provisioned",
"paid_by_provider": true,
"environment": "live"
}
],
"client_accounts_visible": true,
"client_accounts_has_more": false
}
}El id de cada entrada de scope es lo que va en {company}. client_accounts lista las cuentas de tus clientes que alcanza tu cuenta, y solo cuando la clave lleva el scope privilegiado accounts:read en vigor: cuentas y NIF describe cada campo.
Guarda en tu integración la correspondencia tax_id → id y refréscala cuando des de alta un NIF: el id es estable mientras viva el NIF, y el tax_id es inmutable tras el alta. Un NIF archivado que se vuelve a dar de alta es uno nuevo, con un id nuevo.
Resolución y errores
El segmento de empresa resuelve el NIF efectivo antes de que se ejecute ningún handler:
| Segmento de empresa | Resultado |
|---|---|
Un NIF del ámbito de tu credencial, active, en el que tu nivel permite la petición | La petición opera sobre ese NIF. |
Dentro del ámbito, pero desactivado (inactive) o archivado | 403 company_inactive. Un NIF desactivado se puede reactivar antes; uno archivado no, porque archived es terminal. |
Fuera de tu ámbito, inexistente, que no es un identificador, o del otro entorno (live ↔ test) | 404 profile_not_found. |
Dentro del ámbito, pero tu clave tiene view en él y la petición escribe | 403 company_read_only, sin crear ni cambiar nada. |
| Dentro del ámbito, pero la persona que emitió la clave ya no lo alcanza y la petición escribe | 404 profile_not_found, igual que fuera del ámbito. |
| Alcanzado por una relación entre cuentas, en una operación que es de la cuenta dueña del NIF | 403 forbidden_action, con cualquier nivel y también en lecturas. |
| Una operación que tus scopes no cubren | 403 insufficient_scope. |
El 404 es indistinguible en todos sus casos: la API nunca revela que existe un NIF fuera de tu ámbito, y un NIF de producción y su gemelo sandbox comparten identificador fiscal. El entorno se comprueba antes que el estado, así que un NIF desactivado del otro entorno también responde 404.
{
"error": {
"type": "not_found_error",
"code": "profile_not_found",
"message": "La empresa indicada no existe o no está en el ámbito de tu credencial.",
"param": "company"
}
}El 403 company_inactive es distinto: el NIF sí está dentro de tu ámbito, así que revelar que está desactivado es legítimo, y, en un NIF desactivado, es la señal para reactivarlo antes de operar:
{
"error": {
"type": "authorization_error",
"code": "company_inactive",
"message": "Esta empresa está desactivada. Actívala para operar.",
"param": "company"
}
}Un NIF archivado responde el mismo 403 en este eje y no se puede reactivar. Por la cuenta, las operaciones que lo cambian responden 404.
Un 403 company_read_only dice que tu acceso al NIF es de solo lectura, y sus lecturas siguen funcionando. Depende del menor entre el nivel guardado en la clave y el que tiene hoy la persona que la emitió.
Un 403 forbidden_action sobre un NIF alcanzado por una relación dice que la operación es de la cuenta que lo posee. Esas operaciones son los registros de peticiones, los eventos, los endpoints de webhook de empresa, la facturación, el consumo de automatizaciones y las escrituras de las credenciales de pago. El acceso cedido las lista. El mensaje no nombra a la cuenta dueña:
{
"error": {
"type": "authorization_error",
"code": "forbidden_action",
"message": "Esta operación solo la puede hacer la cuenta dueña del NIF: con un acceso por relación entre cuentas no está disponible.",
"doc_url": "https://docs.factuarea.com/guides/errors#forbidden_action",
"request_id": "req_01J8Y3M2Q40000000000000008"
}
}El eje de cuenta es otra ruta
/v1/accounts/{account}/… nombra una cuenta, no un NIF. {account} debe ser la cuenta de tu credencial: una cuenta que no es tuya, una que no existe, un valor que no es un identificador y una que te dio acceso responden todas el mismo 404 account_not_found. Una cuenta gestionada se admite solo en una lista cerrada de rutas que describen las cuentas gestionadas. Las rutas de la cartera de NIF llevan también {company}, pero ahí nombra el NIF sobre el que actúa la operación, no el que posee los datos.
La cabecera X-Active-Profile retirada
Hasta esta versión, el NIF de destino viajaba en una cabecera de petición X-Active-Profile. Esa cabecera está retirada. Una petición que la lleve se rechaza con 400, sea cual sea su valor:
{
"error": {
"type": "invalid_request_error",
"code": "parameter_unknown",
"subcode": "retired_active_profile_header",
"message": "La cabecera 'X-Active-Profile' fue retirada de la API v1: la empresa efectiva se indica en el segmento de empresa de la ruta.",
"param": "X-Active-Profile"
}
}El rechazo se dispara por presencia, nunca por contenido: un identificador bien formado, un NIF fuera de tu ámbito, un valor mal formado, una cadena vacía y una cadena solo con espacios reciben exactamente el mismo error con el mismo mensaje. No se interpreta nada del valor, así que el rechazo no sirve para sondear qué NIF existen.
Enviar la cabecera y que se ignorara habría sido peor que rechazarla: una escritura pensada para otro NIF habría devuelto 201 con el documento emitido bajo el NIF del titular de la credencial. El 400 se lanza antes del handler, así que una escritura rechazada no deja nada atrás. Migrar es mecánico: borra la cabecera y mueve su valor al segmento {company} de la ruta.
¿Cuál usar?
El segmento de la ruta y las formas de ampliar o acotar lo que alcanza una credencial resuelven necesidades distintas, y conviven:
- Tus propios NIF. Usa una clave de tu cuenta y nombra el NIF en cada petición. Para dar a una integración solo una parte de la cuenta, acota la clave: su credencial alcanza solo esos NIF, y el segmento no puede nombrar ningún otro.
- Los NIF de un negocio que mantiene su propia cuenta. El acceso cedido permite que ese negocio dé a tu cuenta
viewuoperatesobre todos o algunos de sus NIF. Los añades a una clave y los nombras en el segmento como los tuyos. - Clientes que das de alta tú. Las cuentas gestionadas te permiten aprovisionar por API la cuenta de un cliente, y alcanzas sus NIF con tu nivel mientras dure la gestión.
Nombrar un NIF en la ruta solo cambia sobre cuál actúas. Nunca cambia los scopes de la credencial, y el aislamiento funciona como al gestionar la cartera: un NIF fuera de tu ámbito nunca es observable, y la respuesta es un 404 y no un 403.