Permisos de la API (scopes)
Cómo conceder y retirar permisos a una aplicación externa: los 56 permisos, sus tipos, los 14 que solo concede un Super Administrador, el recorte por plan y la auditoría.
Actualizado el . 17 min de lectura
Incluido en todos los planes. Ver precios
Los permisos de la API (scopes) deciden qué datos puede leer y qué
acciones puede hacer una aplicación externa cuando llama a la API con
su X-Api-Key. Esta página explica cómo se conceden desde el panel, qué
reglas de seguridad y de datos personales se aplican, y cómo
automatizarlo por API o por MCP.
Antes de empezar
Para cambiar los permisos de una aplicación necesitas el permiso
EXTERNAL_APPS_EDIT. Para añadir cualquiera de los 14 permisos
protegidos (datos personales críticos, dinero o agentes de IA), además
tienes que ser Super Administrador. Además, hoy la pantalla Aplicaciones
externas, donde se crean y gestionan, solo aparece si tu organización
usa el perfil de trabajo «Software / Desarrollo» en Gestión de proyectos.
Dónde se configuran
En Gestión de proyectos › Aplicaciones externas, necesitas entrar con tu cuenta › tu aplicación › Ajustes › pestaña Permisos, está la tarjeta Permisos de la API con todos los permisos disponibles. Cada uno lleva su nombre, una descripción corta y, si procede, un distintivo de dato sensible o de acción protegida.
La tarjeta se alimenta del catálogo de
GET /api/integrations/apps/scopes/catalog, que es la única fuente de
verdad: los textos y distintivos se calculan en el servidor.
Catálogo de permisos
El catálogo tiene 56 permisos en trece áreas: contactos, leads, clientes, usuarios externos, facturación, cobros con tarjeta, suscripciones, autorizaciones de cobro, cobros programados, soporte, archivos, presupuestos, analítica y chat. Las tablas indican el tipo de operación, los endpoints que lo exigen y si solo puede concederlo un Super Administrador. El recuento y su desglose están en Catálogo de permisos de la API.
Cada permiso declara además qué aplicativos y capacidades del plan necesita para servir de algo, y el catálogo se recorta con esa declaración: los que tu plan no cubre aparecen con candado y no se pueden conceder. Ver El catálogo se recorta por el plan.
Dominio CRM · Contactos (6)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
crm:contacts:read | Lectura básica | Listar, buscar y ver el detalle de contactos del CRM. | GET /external/v1/contacts, /:id, /search, /by-email, /sync | No |
crm:contacts:write | Escritura | Registrar bajas y reactivaciones, estas con prueba del consentimiento. | POST /external/v1/contacts/:id/unsubscribe, /resubscribe | No |
crm:contacts:read:secondary-email | Sensible | Segundo correo del contacto, cuando pides ?include=secondaryEmail. | GET /external/v1/contacts con include | No |
crm:contacts:read:birthday | Sensible | Día y mes de nacimiento del contacto. | GET /external/v1/contacts con ?include=birthday | No |
crm:contacts:read:notes | Datos personales críticos | Notas privadas del equipo sobre el contacto. Datos cualitativos sensibles. | GET /external/v1/contacts con ?include=notes | Sí |
crm:contacts:read:opted-out | Datos personales críticos | Acceso a contactos que ejercieron su derecho de oposición (baja). | GET /external/v1/contacts (listado completo) | Sí |
Dominio CRM · Leads (5)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
crm:leads:read | Lectura básica | Listar y ver leads (nombre, empresa, correo, estado, etapa, prioridad y origen). | GET /external/v1/leads | No |
crm:leads:read:scoring | Sensible | Puntuación y temperatura del lead (score, temperature). | GET /external/v1/leads con ?include=scoring | No |
crm:leads:write | Escritura | Crear leads, cualificar (QUALIFIED), descartar (LOST), actualizar y ajustar el scoring. No elimina ni convierte. | POST /external/v1/leads, /:id/qualify, /:id/disqualify, /:id/score, PATCH /:id | No |
crm:leads:convert | Datos personales críticos | Convertir un lead en contacto del CRM y opcionalmente en oportunidad. Crea entidades nuevas. | POST /external/v1/leads/:id/convert | Sí |
crm:leads:read:notes | Datos personales críticos | Notas privadas del equipo sobre el lead. | GET /external/v1/leads con ?include=notes | Sí |
Dominio CRM · Clientes (5)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
crm:clients:read | Lectura básica | Listar y ver clientes (nombre comercial, sector, estado), incluido su grupo de empresas. Sin él, primaryClient no sale en los contactos. | GET /external/v1/clients, /:id/group | No |
crm:clients:write | Escritura | Crear clientes, actualizar la ficha, desactivar (status=INACTIVE) y reactivar. No elimina ni cambia el vínculo de grupo. | POST /external/v1/clients, PATCH /:id, POST /:id/deactivate, /:id/reactivate | No |
crm:clients:write:hierarchy | Sensible | Vincular y desvincular filiales de su empresa matriz (parentClientId). Se exige además de crm:clients:write porque reorganizar el grupo cambia las vistas consolidadas y permite facturar a la matriz un presupuesto de la filial. | PATCH /external/v1/clients/:id con parentClientId | No |
crm:clients:read:fiscal-data | Datos personales críticos | NIF o CIF, dirección fiscal, régimen y retenciones. Para autónomos es dato personal identificativo. | GET /external/v1/clients/:id, /by-tax-id con ?include=fiscalData | Sí |
crm:clients:read:notes | Datos personales críticos | Notas privadas del equipo sobre el cliente. | GET /external/v1/clients/:id con ?include=notes | Sí |
Dominio CRM · Usuarios externos (2)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
crm:users:read | Lectura básica | Consultar el listado de usuarios externos vinculados a la aplicación. | GET /external/v1/users | No |
crm:users:write | Escritura | Dar de alta y actualizar los usuarios finales de la aplicación, con su correo, su NIF y su dirección de facturación, y vincularlos a una ficha de cliente del CRM. | POST /external/v1/users/identify | No |
Dominio Facturación (5)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
crm:invoices:read | Lectura básica | Listar facturas, ver el detalle, descargar el PDF, consultar estadísticas y leer el enlace público vigente. | GET /external/v1/invoices, /:id, /:id/pdf, /stats, /:id/public-link | No |
crm:invoices:write | Escritura | Crear facturas en nombre del usuario externo, registrar cobros fuera de la pasarela y emitir el enlace público. Por sí solo no basta para crear: POST /external/v1/invoices exige además crm:invoices:issue. No permite cancelar ni modificar facturas ya emitidas. | POST /external/v1/invoices, /:id/mark-paid, /:id/public-link | No |
crm:invoices:send | Escritura | Enviar al usuario final la factura por correo con su PDF, usando la plantilla y el remitente de la organización. Se concede aparte de la creación: facturar y escribir al cliente son cosas distintas. | POST /external/v1/invoices/:id/send | No |
crm:invoices:issue | Sensible | Junto con crm:invoices:write, permite que POST /external/v1/invoices numere y selle fiscalmente la factura en el mismo paso, con VeriFactu si está activo. Se exige desde la primera llamada: sin él, la creación responde 403. | POST /external/v1/invoices | No |
crm:invoices:cancel | Crítico financiero | Anular facturas emitidas. Genera el registro fiscal de anulación si está activo. Solo se revierte emitiendo una rectificativa. | POST /external/v1/invoices/:id/cancel | Sí |
Dominio Cobros con tarjeta (4)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
billing:payment-methods:read | Lectura básica | Listar las tarjetas guardadas del usuario externo y consultar el historial de intentos de cobro de una factura. | GET /external/v1/payment-methods, GET /external/v1/invoices/:id/payment-intents | No |
billing:payment-methods:write | Escritura | Crear el SetupIntent con el que guardar una tarjeta, marcar una como predeterminada y desvincularla. | POST /external/v1/payment-methods/setup-intent, /payment-methods/:pmId/set-default, DELETE /payment-methods/:pmId | No |
billing:charge | Crítico financiero | Cobrar una factura, con el usuario delante o sin él. Mueve dinero real desde la tarjeta guardada del cliente. | POST /external/v1/invoices/:id/pay, /:id/charge | Sí |
billing:refund | Crítico financiero | Devolver, entero o en parte, el dinero ya cobrado de una factura. | POST /external/v1/invoices/:id/refund | Sí |
Dominio Suscripciones (3)
Exigen el aplicativo Finanzas y la capacidad de facturación recurrente.
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
billing:subscriptions:read | Lectura básica | Consultar las suscripciones de los usuarios de la aplicación: estado, importe por periodo, próxima factura, historial y facturas generadas. | GET /external/v1/subscriptions y sus subrutas de lectura | No |
billing:subscriptions:write | Escritura | Dar de alta suscripciones, modificarlas, pausarlas, reanudarlas, reactivarlas, adelantar la generación de una factura y reintentar su cobro. | POST /external/v1/subscriptions, PATCH /:id, /:id/pause, /:id/resume, /:id/reactivate, /:id/generate-now, /:id/invoices/:invoiceId/retry-charge | No |
billing:subscriptions:cancel | Crítico financiero | Dar de baja definitivamente una suscripción. Corta un ingreso recurrente y no se deshace. | POST /external/v1/subscriptions/:id/cancel | Sí |
Dominio Autorizaciones de cobro (3)
Exigen los aplicativos Finanzas y Stripe y la capacidad de cobro automático.
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
billing:payment-authorizations:read | Lectura básica | Consultar qué usuarios han autorizado el cobro automático, con qué alcance y sobre qué tarjeta, y pedir el texto de consentimiento vigente. | GET /external/v1/payment-authorizations, /:id, /consent-text | No |
billing:payment-authorizations:write | Crítico financiero | Registrar la autorización que el usuario acaba de firmar en la aplicación, con el texto, la fecha, la dirección IP y el navegador. Es la prueba legal que habilita cobrar sin nadie delante. | POST /external/v1/payment-authorizations | Sí |
billing:payment-authorizations:revoke | Escritura | Retirar una autorización. La retirada es inmediata y arrastra los cobros programados y el cobro automático de las suscripciones. | POST /external/v1/payment-authorizations/:id/revoke | No |
Dominio Cobros programados (2)
Exigen los aplicativos Finanzas y Stripe y la capacidad de cobro automático.
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
billing:scheduled-charges:read | Lectura básica | Consultar los cobros programados de las facturas: cuándo se ejecutarán, cuántos intentos llevan y por qué falló el último. | GET /external/v1/invoices/:id/scheduled-charges | No |
billing:scheduled-charges:write | Escritura | Programar el cobro de una factura para una fecha futura, cancelarlo mientras la ventana siga abierta y adelantar un reintento. No sustituye a la autorización del usuario. | POST /external/v1/invoices/:id/scheduled-charges, DELETE /external/v1/scheduled-charges/:id, POST /scheduled-charges/:id/retry-now | No |
Dominio Soporte · Tickets (3)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
support:tickets:read | Lectura básica | Listar tickets, ver el detalle, consultar los mensajes sin leer y recibir los cambios por SSE. | GET /external/v1/tickets, /:id, /unread-count, /events | No |
support:tickets:write | Escritura | Crear tickets, añadir mensajes, cerrarlos y reabrirlos en nombre del usuario externo. | POST /external/v1/tickets, /:id/messages, PATCH /:id/close, /:id/reopen | No |
support:tickets:ai | Datos personales críticos | Pedir sugerencias con IA para el ticket y transcribir audio. Consume cuota de IA y envía datos personales a un proveedor externo. | POST /external/v1/tickets/ai-suggest, /ai-track-action, /ai-transcribe, /ai-transcribe-async y sus consultas de estado | Sí |
Dominio Archivos (2)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
fm:files:read | Lectura básica | Consultar la cuota y obtener direcciones firmadas para descargar los archivos subidos por la aplicación. | GET /external/v1/files/quota, /:id/url | No |
fm:files:write | Escritura | Subir archivos desde la aplicación externa. | POST /external/v1/files/upload | No |
Dominio Presupuestos (4)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
crm:budgets:comments:read | Lectura básica | Listar los comentarios CLIENT del presupuesto (los que ve el cliente en el portal). | GET /external/v1/budgets/:budgetId/comments | No |
crm:budgets:comments:write | Escritura | Crear comentarios CLIENT en el presupuesto. Las menciones se ignoran. | POST /external/v1/budgets/:budgetId/comments | No |
crm:budgets:signatures:read | Lectura básica | Listar las firmas y ver su detalle (con la IP parcialmente oculta). | GET /external/v1/budgets/:budgetId/signatures, /:sigId | No |
crm:budgets:signatures:verify | Datos personales críticos | Recalcular la huella del documento firmado y compararla con la guardada. En malas manos, permitiría comprobar si una manipulación pasa desapercibida. | GET /external/v1/budgets/:budgetId/signatures/:sigId/verify | Sí |
Dominio Analítica de IA (1)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
analytics:ai:read | Lectura básica | Consultar el resumen y la evolución del uso de IA de la propia aplicación. | GET /external/v1/ai-analytics/overview, /trends | No |
Dominio Errores de la aplicación (2)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
analytics:errors:read | Lectura básica | Listar los errores que ha enviado la aplicación y consultar sus estadísticas. | GET /external/v1/errors, /stats | No |
analytics:errors:write | Escritura | Enviar errores del servidor o del navegador de la aplicación. Los repetidos se agrupan. | POST /external/v1/errors/report, POST /external/v1/tickets/client-errors | No |
Dominio Chat (9)
| Permiso | Tipo | Descripción | Endpoint(s) | ¿Solo Super Administrador? |
|---|---|---|---|---|
chat:messages:send | Escritura | Publicar mensajes como la aplicación en un canal concedido. Aparece como autor propio, nunca en nombre de una persona. | POST /external/v1/chat/channels/:channelId/messages | No |
chat:channels:view | Lectura básica | Listar los canales concedidos, su detalle y sus miembros. | GET /external/v1/chat/channels, /:channelId, /:channelId/members | No |
chat:messages:view | Lectura básica | Leer los mensajes de un canal concedido. Solo mensajes públicos y dirigidos a los participantes; nunca internos del equipo, privados ni respuestas privadas de la IA. | GET /external/v1/chat/channels/:channelId/messages, /messages/:messageId | No |
chat:events:subscribe | Lectura básica | Recibir los avisos de los canales concedidos donde participa la aplicación. | Entrega saliente (no tiene endpoint propio) | No |
chat:channels:create | Escritura | Crear canales como la aplicación, dentro de los permisos de quien concedió el acceso. | POST /external/v1/chat/channels | No |
chat:channels:manage | Escritura | Editar y archivar canales concedidos. Borrarlos exige además su permiso propio. | PATCH /external/v1/chat/channels/:channelId, POST /:channelId/archive | No |
chat:members:manage | Escritura | Añadir y retirar miembros de un canal concedido. Retirar exige además el permiso correspondiente. | POST /external/v1/chat/channels/:channelId/members, DELETE /:channelId/members/:userId | No |
chat:agents:view | Lectura básica | Listar los agentes de IA que la propia aplicación ha creado en los canales concedidos y ver su estado. | GET /external/v1/chat/channels/:channelId/agents | No |
chat:agents:manage:external | Escritura | Crear y configurar agentes de IA de canal que actúan con los permisos prestados de una persona. La capacidad más protegida del catálogo. | POST /external/v1/chat/channels/:channelId/agents, PATCH y DELETE /external/v1/chat/channels/:channelId/agents/:agentId, más /pause y /resume | Sí |
En el chat hay dos puertas: el permiso autoriza la acción y el acceso a
cada canal lo concede aparte una persona responsable de ese canal. Con
chat:messages:send no basta para escribir en un canal al que la aplicación
no ha sido invitada. Al conceder cualquier chat:*, la aplicación queda
habilitada en el chat, pero no ve ningún canal hasta que alguien se lo
conceda. Más en Scopes y acceso por canal.
Los cinco tipos
- Lectura básica (
basic, 19 permisos): lo imprescindible para que la aplicación funcione. Sin distintivo. - Escritura (
write, 19 permisos): cambios reversibles en el CRM, las facturas, las tarjetas, los archivos, los tickets o el chat. - Sensible (
sensitive, 5 permisos): datos personales o comerciales adicionales y acciones de más alcance del que aparentan, sin llegar a críticos. - Datos personales críticos (
rgpd-critical, 8 permisos): notas internas, contactos dados de baja, datos fiscales, conversión de leads, verificación de firmas y procesado de tickets con IA. - Crítico financiero (
financial-critical, 5 permisos): mueve dinero o corta un ingreso. Se concede con las mismas exigencias que el tipo anterior; el tipo distinto dice a quien revisa la solicitud por qué está protegido.
Los 14 permisos que solo concede un Super Administrador
Solo puede añadirlos un Super Administrador, con un motivo de al menos veinte caracteres. Retirarlos no exige nada especial.
- Datos personales críticos:
crm:contacts:read:notes,crm:contacts:read:opted-out,crm:leads:convert,crm:leads:read:notes,crm:clients:read:fiscal-data,crm:clients:read:notes,support:tickets:aiycrm:budgets:signatures:verify. - Críticos financieros:
crm:invoices:cancel,billing:charge,billing:refund,billing:subscriptions:cancelybilling:payment-authorizations:write. - Agentes de IA:
chat:agents:manage:external, de tipo escritura pero el más protegido del catálogo: permite crear agentes de IA que actúan con los permisos prestados de una persona, no entra en ningún paquete y cada agente creado espera la firma en persona de un responsable del canal (Gestionar agentes de IA).
Paquetes sugeridos
La tarjeta ofrece atajos para los casos más comunes. Elegir uno marca sus permisos y te deja afinar el resto.
| Paquete | Para qué | Permisos que marca |
|---|---|---|
| Herramienta de envío de correos | Sincronizar listas y respetar las bajas | crm:contacts:read, crm:contacts:read:opted-out |
| Plataforma de prospección | Leer y registrar contactos, leads y empresas | crm:contacts:read, crm:contacts:write, crm:clients:read, crm:leads:read, crm:leads:write |
| Tickets y soporte | Dar de alta a los usuarios y dejar que abran y sigan sus tickets | crm:users:read, crm:users:write, support:tickets:read, support:tickets:write |
| Sincronización CRM | Sincronizar contactos, leads y clientes, sin notas internas ni conversión | crm:contacts:read, crm:contacts:read:secondary-email, crm:contacts:read:birthday, crm:contacts:write, crm:clients:read, crm:clients:write, crm:leads:read, crm:leads:read:scoring, crm:leads:write |
| Facturación y cobros | Dar de alta a los usuarios, facturarles, guardar su tarjeta y cobrarles, también cuotas | crm:users:read, crm:users:write, crm:invoices:read, crm:invoices:write, crm:invoices:issue, crm:invoices:send, billing:payment-methods:read, billing:payment-methods:write, billing:charge, billing:subscriptions:read, billing:subscriptions:write, billing:payment-authorizations:read, billing:payment-authorizations:write, billing:scheduled-charges:read, billing:scheduled-charges:write |
| Aplicación de chat | Leer y escribir en los canales y recibir sus avisos | chat:channels:view, chat:messages:view, chat:messages:send, chat:events:subscribe |
| Personalizado | Elegir uno a uno | Ninguno |
Anular facturas, devolver dinero y dar de baja suscripciones no entran en ningún paquete: se conceden a mano, uno a uno.
Conceder o retirar permisos
Abre la aplicación
En Gestión de proyectos, Aplicaciones externas, abre la aplicación y entra en Ajustes, pestaña Permisos.
Busca los permisos
La tarjeta Permisos de la API muestra todos los permisos con su estado actual, agrupados por área. Bajo cada uno aparece su nombre técnico (por ejemplo,
crm:invoices:write) para encontrarlo rápido.Marca o desmarca
Pulsa para añadir o quitar. La tarjeta muestra antes de guardar qué permisos vas a añadir y cuáles vas a quitar.
Escribe el motivo si añades uno protegido
Si añades alguno de los 14 permisos protegidos, la tarjeta pide un motivo de al menos 20 caracteres. Sin él, no se puede guardar (y la API respondería
422 REASON_REQUIRED_FOR_RGPD_SCOPE).Guarda
Pulsa Guardar. El servidor comprueba tus permisos, comprueba que nadie haya cambiado la aplicación mientras tanto y aplica el cambio. Un mensaje confirma exactamente qué se ha cambiado. El cambio vale desde la siguiente llamada: no hace falta rotar la clave de API ni reiniciar la aplicación.
Si tu aplicación recibe un 403 INSUFFICIENT_SCOPE
Significa que le falta un permiso. La respuesta no dice cuál, a propósito: decirlo permitiría a quien tuviera una clave robada ir descubriendo la API. Quien integra sabe qué acaba de llamar.
{
"errorCode": "INSUFFICIENT_SCOPE",
"message": "Esta operación requiere permisos adicionales. Contacta con el administrador del espacio de trabajo donde está instalada tu app.",
"statusCode": 403
}No hay periodo de gracia: el permiso se exige en todas las llamadas desde la primera, también en aplicaciones antiguas. La tolerancia que acompañó al despliegue del 25 de mayo de 2026 ya no existe.
Para pedir el permiso:
- Localiza el permiso del endpoint que respondió
403en las tablas de arriba. Por ejemplo, si fallaPOST /external/v1/invoices, faltacrm:invoices:writeocrm:invoices:issue(crear exige los dos). - Pídeselo al administrador de la organización con el nombre exacto (por ejemplo,
crm:invoices:write) y para qué lo necesitas. Si es uno de los 14 protegidos, prepara también un motivo de al menos 20 caracteres. - El administrador lo concede en la tarjeta Permisos de la API. La siguiente llamada ya responde
200.
Reglas de seguridad
PATCH /api/integrations/apps/:id/scopes recibe la lista completa de
permisos que debe tener la aplicación. Antes de guardarla, el servidor
hace estas comprobaciones, en este orden:
Qué comprueba el servidor al cambiar los permisos
¿Están todos en el catálogo?
Si no: 400 INVALID_SCOPE.
¿Está activa la aplicación?
Si no: 409 EXTERNAL_APP_REVOKED. Reactívala antes.
¿Nadie la ha cambiado antes?
Solo si envías expectedUpdatedAt con la versión que estabas viendo.Si no: 409 EXTERNAL_APP_SCOPES_CONFLICT. Recarga y repite.
¿Los cubre el plan?
Retirar un permiso siempre es posible.Si no: 400 SCOPE_OUT_OF_PLAN.
¿Puedes añadir los protegidos?
Hace falta ser Super Administrador y un motivo de 20 caracteres o más.Si no: 403 SUPER_ADMIN_REQUIRED_FOR_RGPD_SCOPE o 422 REASON_REQUIRED_FOR_RGPD_SCOPE.
Se guarda el cambio
El servidor calcula qué se añade y qué se quita, y lo deja en el registro de auditoría.
- Los tokens OAuth se revocan: al retirar un permiso, los tokens OAuth activos que lo incluían dejan de valer y la aplicación tiene que volver a pedir consentimiento. La clave de API y el secreto de los avisos no se rotan.
- Cambio en tiempo real: quien tenga la aplicación abierta ve el cambio sin recargar.
- Mensaje genérico: la respuesta
INSUFFICIENT_SCOPEnunca incluye direcciones del panel ni identificadores internos.
El catálogo se recorta por el plan
Conceder un permiso no basta: tu organización tiene que tener en su
plan el aplicativo, y en su caso la capacidad, que ese permiso
gobierna. Son dos puertas distintas, y las dos se comprueban en el
servidor. Cada permiso declara sus requiredModules y
requiredCapabilities, y con eso:
- Se marca el catálogo que ve el panel: los permisos que tu plan no cubre llegan con
outOfPlan: truey se muestran con candado, sin poder concederse. - Se rechaza conceder un permiso fuera de plan, con
400 SCOPE_OUT_OF_PLAN. - El endpoint responde
403antes incluso de mirar el permiso:MODULE_NOT_ENABLEDsi falta el aplicativo, oCAPABILITY_NOT_ENABLEDsi falta la capacidad.
Si tu organización baja de plan, los permisos ya concedidos se conservan: simplemente dejan de funcionar hasta que vuelva el aplicativo. Retirar un permiso es siempre posible, esté o no en plan.
| Familia | Aplicativos del plan | Capacidad |
|---|---|---|
crm:contacts:*, crm:clients:*, crm:budgets:* | CRM | — |
crm:clients:write:hierarchy | CRM | Grupos de empresas |
crm:leads:* | CRM | Leads |
crm:invoices:* | Finanzas | — |
billing:payment-methods:*, billing:charge, billing:refund | Finanzas y Pagos con tarjeta (Stripe) | — |
billing:subscriptions:* | Finanzas | Facturación recurrente |
billing:payment-authorizations:*, billing:scheduled-charges:* | Finanzas y Pagos con tarjeta (Stripe) | Cobro automático |
support:tickets:* | Tickets de soporte | Tickets propios |
fm:files:* | Gestor de archivos | — |
crm:users:*, analytics:* | Integraciones | — |
chat:* | Chat | Agentes de canal, para chat:agents:* |
billing:charge no declara la capacidad de cobro automático porque
también sirve para cobrar con el usuario delante, que funciona sin
ella. La puerta del cobro automático está en el endpoint que la
necesita (/invoices/:id/charge).
Registro de auditoría
Cada cambio se guarda en el registro de auditoría con la acción
external_apps.scopes.changed y estos datos: appId, appSlug,
organizationId; before y after (listas completas); added y
removed; actorUserId y actorRole; reason si se aportó; source
(WEB desde el panel o MCP desde un asistente de IA); ipAddress y
userAgent cuando viene del panel; y occurredAt. El registro no se
puede modificar.
Automatizar por API
Si gestionas muchas aplicaciones o tienes scripts de alta, llama al endpoint con el token de sesión de un administrador:
curl -X PATCH "https://os.utilia.ai/api/integrations/apps/$APP_ID/scopes" \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{
"scopes": [
"crm:users:read",
"crm:users:write",
"support:tickets:read",
"support:tickets:write"
],
"reason": "Alta inicial de la aplicación de soporte con los permisos mínimos",
"expectedUpdatedAt": "2026-05-25T09:00:00.000Z"
}'Para consultar antes el catálogo de permisos válidos:
curl -H "Authorization: Bearer $ADMIN_JWT" \
"https://os.utilia.ai/api/integrations/apps/scopes/catalog"La respuesta es una lista de objetos con value, label,
description, category, rgpdSensitive, rgpdCritical,
requiresSuperAdmin, requiredModules, requiredCapabilities y, si
procede, outOfPlan.
Automatizar por MCP
La operación equivalente es apps_update_scopes de la herramienta MCP
integrations (exige confirm: true). Sus parámetros y un ejemplo
están en la referencia MCP.
Códigos de error
| Código | HTTP | Cuándo aparece |
|---|---|---|
INVALID_SCOPE | 400 | La lista scopes contiene un valor que no está en el catálogo. |
EXTERNAL_APP_NOT_FOUND | 404 | La aplicación no existe en tu organización. |
EXTERNAL_APP_REVOKED | 409 | La aplicación está desactivada. Reactívala antes de cambiar sus permisos. |
EXTERNAL_APP_SCOPES_CONFLICT | 409 | Bloqueo optimista: otra persona la cambió antes. Recarga y vuelve a intentarlo. |
SUPER_ADMIN_REQUIRED_FOR_RGPD_SCOPE | 403 | Hace falta ser Super Administrador para añadir un permiso protegido. |
REASON_REQUIRED_FOR_RGPD_SCOPE | 422 | Falta reason, o tiene menos de 20 caracteres, al añadir un permiso protegido. |
SCOPE_OUT_OF_PLAN | 400 | El plan de tu organización no cubre ese permiso. Retirarlo siempre es posible. |
INSUFFICIENT_SCOPE | 403 | La aplicación llamó a un endpoint sin tener el permiso. Mensaje genérico a propósito. |
MODULE_NOT_ENABLED | 403 | El plan no incluye el aplicativo del endpoint. Se comprueba antes que el permiso; la respuesta trae su moduleKey. |
CAPABILITY_NOT_ENABLED | 403 | El aplicativo está contratado, pero no la capacidad concreta. La respuesta trae su capabilityKey. |
Cambios del catálogo que afectan a aplicaciones existentes
- 25 de mayo de 2026: los endpoints de facturación, cobros, archivos, tickets, usuarios, presupuestos, analítica de IA y errores pasaron a exigir permiso propio, y se retiró
fm:files:delete(nunca hubo endpoint de borrado). - 5 de julio de 2026: llegó
crm:clients:write:hierarchypara los grupos de empresas. Se exige además decrm:clients:write, y las aplicaciones existentes no lo recibieron solas. - 12 de julio de 2026: llegaron los nueve permisos del chat.
- 5 de septiembre de 2026:
POST /external/v1/users/identifypasó a exigircrm:users:write.
El historial completo está en Cambios de la API.