How they’re validated
On every request, the auth guard loads the token and puts its scopes on the request context. Each endpoint declares the scope it needs with@RequireScopes('messages:send'). If the scope is missing, the response is 403 Forbidden with code: INSUFFICIENT_SCOPE.
Catalog
The catalog lives in theapi_scopes MongoDB collection. The portal pulls it via GET /api/v1/api-scopes and builds the create-token modal dynamically, so adding a new scope doesn’t require a frontend deploy.
The MCP server uses the same scopes
The MCP server does not have a scope system of its own. Each of its tools requires exactly the scope its REST counterpart does —keebai_crm_ticket_create needs crm:tickets:write, keebai_contacts_list needs contacts:read, and so on. The tool catalogue lists the mapping.
One difference matters when you hand a token to an agent: a missing scope is not a 403. Every tool stays visible in tools/list regardless of your scopes, and the call comes back as a tool error carrying INSUFFICIENT_SCOPE. An agent will happily try something it cannot do and discover the limit afterwards, so pick the scope set deliberately rather than relying on the agent not to reach for a tool.
Permission groups
When an app connects to the MCP server over OAuth — Claude, ChatGPT, Cursor — the user does not tick scopes one by one. The consent screen shows six groups. The token ends up with the scopes the app asked for that belong to a group the user approved and that the user’s role allows. Each scope’s group is stored with it in theapi_scopes catalog, as consent_group. It is not derived from the scope’s name: contacts: and loyalty: sit with crm: in Customers, restaurants:menu:read sits with the catalog reads in Products and sales, and ecommerce: splits by action — reads go to Products and sales, anything that writes or issues goes to Sell and invoice — so a user can let an app look at sales without letting it create them.
cli:device is in no group. It is an internal marker that Keebai puts on tokens issued to the CLI, not a permission an app can ask for. Inactive scopes are in no group either.
Rules that apply on the consent screen:
- Your role limits the groups. A group is available only if your Keebai role has the permission behind at least one of the scopes the app asked for in it. Inside an approved group, scopes your role does not allow are left out. The company owner and superusers can approve every group.
- One company per connection. The user picks the company before approving. To use another company, connect again.
- Reconnecting replaces. A second approval from the same user, for the same app and company, replaces the scopes of the first one.
- Disconnecting stops the connection within 15 minutes. Under Developers › Connected apps in the portal, the company owner and superusers see every connection in the company and everyone else sees their own. Disconnecting revokes the refresh token at once; the app’s current access token is not revoked and expires on its own, at most 15 minutes later.
- Losing access ends the connection. If the user is deactivated or loses access to the company, the app’s next refresh fails and it has to sign in again. A change of role alone does not change the scopes already granted; disconnect and connect again to apply it.
Scopes are independent from role permissions
Scopes are independent from the role permissions of the user who creates the token. The backend validates what scopes you’re allowed to assign at creation time (each scope must exist and be active inapi_scopes, and a few are tied to role permissions — see below), but once minted, the token uses its assigned scopes regardless of later changes to your role.
That means:
- To create a token you need
developer.manage_tokenson your role. Without it you don’t even see the API Keys screen. - Once created, a token’s scopes are fixed. If your role is later trimmed, the token keeps working with its original scopes. To revoke access, revoke the key explicitly.
- To use new scopes, mint a new token. You can’t add scopes to an existing key.
Two ecommerce scopes require the permission in your role. Minting a token with
ecommerce:stock:write requires the permissions to adjust and transfer stock in your Keebai role, and ecommerce:invoicing:issue requires the permission to issue DTE. The company owner and superusers are exempt. On every call the API passes the ecommerce service the permissions that match the token’s scopes, so what the token can do is what the role allowed when it was minted.Least privilege by example
Pick the smallest scope set that does the job. Splittingmessages:send and messages:bulk exists exactly for this — bulk is higher-risk (Meta cost, sender reputation, abuse potential), so isolate it in a key the marketing tool owns, not the transactional backend.
Transactional backend (1:1 notifications)
Only needs to send single messages.
messages:send.Marketing tool / outbound CRM
Needs to launch campaigns and check status.
messages:bulk, templates:read.Template viewer
Read-only browser of the approved catalog.
templates:read.Template provisioning
Creates and maintains the company’s templates without using the portal.
templates:read, templates:create, templates:update.Full-stack integration (internal)
The whole combo, when it’s under your team’s direct control.
messages:send, messages:bulk, templates:read, templates:create, templates:update.CLI-driven provisioning
Automated onboarding: connects channels, registers webhooks, verifies.
channels:read, channels:connect, webhooks:read, webhooks:manage.Webhook-based integration
Your backend receives realtime events and inspects delivery history.
webhooks:read, webhooks:manage, channels:read.Knowledge-base sync
Your CMS or docs pipeline publishes documents and assigns them to agents automatically.
knowledge:read, knowledge:write, knowledge:delete, knowledge:assign, agents:read.External RAG / search
An external app queries your knowledge base as retrieval for its own LLM.
knowledge:read, knowledge:query.Scheduling — read-only catalog and availability
Your public website or client app shows branches, services, professionals, and available times — no booking.
scheduling:branches:read, scheduling:services:read, scheduling:professionals:read, scheduling:availability:read.Scheduling — full booking flow
Your integration creates, confirms, and cancels appointments end-to-end.
scheduling:branches:read, scheduling:services:read, scheduling:professionals:read, scheduling:availability:read, scheduling:appointments:read, scheduling:appointments:create, scheduling:appointments:confirm, scheduling:appointments:cancel.CRM — reporting and dashboards
A BI tool or dashboard reads the pipeline without ever writing to it.
crm:customers:read, crm:tickets:read, crm:tasks:read, crm:notes:read.CRM — two-way sync, no deletes
Your external CRM or ERP keeps records in step with Keebai. Deletes stay out so a sync bug cannot erase history.
crm:customers:read, crm:customers:write, crm:tickets:read, crm:tickets:write, crm:tasks:read, crm:tasks:write, crm:notes:read, crm:notes:write.CRM — activity logger
A dialer or email tool writes call and email records onto the right ticket, and nothing else.
crm:tickets:read, crm:notes:write.Storefront pricing widget
Your website shows live prices and stock. It never touches customer data.
ecommerce:products:read.Abandoned-cart recovery
Finds pending carts and messages the customer with the recovery link.
ecommerce:carts:read, contacts:read, messages:send.Sales reporting
A BI job pulls closed sales nightly. Read-only, no catalog, no carts.
ecommerce:sales:read.Point of sale
Your POS looks up products by barcode, records sales with their boleta or factura, and keeps stock in step.
ecommerce:products:read, ecommerce:stock:read, ecommerce:sales:write, ecommerce:invoicing:read, ecommerce:invoicing:issue.Warehouse and stock sync
Your ERP or warehouse system adjusts and transfers stock and audits the movements. It never creates sales or touches invoicing.
ecommerce:products:read, ecommerce:stock:read, ecommerce:stock:write.Email campaigns
Your marketing tool sends emails to a list from the company sender and tracks opens.
messages:bulk, templates:read, channels:read.Loyalty terminal
Your point of sale enrolls customers, accrues on purchase, and hands out the wallet card.
loyalty:read, loyalty:write.Loyalty balance display
A kiosk or a customer-facing screen shows the balance and nothing more. Cannot move points or push notifications.
loyalty:read.Agent provisioning
Your onboarding flow creates an agent per client and writes its prompt blocks from a template you keep in git.
agents:read, agents:write.Prompt auditor
A reviewer reads every agent’s blocks and their history to check what the bots are told to say. Cannot change a word, and webhook secrets stay masked.
agents:read.Contact sync
Your CRM or ERP keeps the contact directory in step with Keebai. Deletes stay out so a sync bug cannot erase people.
contacts:read, contacts:write.AI agent over MCP
An agent that answers with your knowledge base, replies on WhatsApp, and logs what it did — without being able to destroy anything.
knowledge:query, contacts:read, messages:send, crm:tickets:read, crm:tickets:write, crm:notes:write.Change a token’s scopes
You can’t edit scopes on an existing token. The pattern is:1
Mint a new token with the right scopes
From API Keys, click Create API Key and pick the new scopes.
2
Update your integration
Swap the old token for the new one in your secret manager.
3
Revoke the old
Once the integration is happily on the new token, revoke the old one.