Developers
Plugin Permissions
Understand how plugins request authority, how admins grant it, and how platform bridge permissions are enforced.
Why plugin permissions exist
Plugins let an external system participate in conversations on a connected WhatsApp number instance. A gas-ordering plugin might create delivery orders. A legal-services plugin might request payment before a consultation. A reminder plugin might schedule follow-ups.
That authority must be explicit because it can affect money, customer messages, orders, refunds, escalations, and operations. Plugin permissions answer four questions:
- Which plugin is installed for the organization?
- Which connected WhatsApp number instance may use it?
- Which plugin tools may the AI agent call?
- Which platform-owned actions may the plugin request directly through a bridge?
The aim is deterministic enforcement. If a plugin is not allowed to request a refund, the platform refuses the refund before money moves. The decision does not depend on prompt wording.
The four gates
Every plugin action passes through separate gates.
| Gate | What it controls |
|---|---|
| Installation | The organization has installed the plugin |
| WhatsApp number instance grant | A specific connected WhatsApp number may use the plugin |
| Tool grant | The AI agent may see and call selected plugin tools |
| Permission grant | The plugin may request selected sensitive platform actions |
Installing a plugin does not grant it to every WhatsApp bot. For example, a business can install a CRM plugin for the organization, grant it to the support WhatsApp number instance, and leave it disabled on the sales WhatsApp number instance.
Granting a plugin to a WhatsApp number instance also does not approve every sensitive action. A merchant can allow a plugin to create orders while refusing refunds.
Two permission families
Declare requested permissions in the plugin manifest:
{
"permissions": [
{
"key": "gas:orders:create",
"label": "Create gas orders",
"description": "Allows the plugin to create gas delivery orders in the merchant's gas system.",
"default": true
},
{
"key": "plugin:payments:initiate:current_chat",
"label": "Request payment from the current WhatsApp customer",
"description": "Allows the plugin to ask KasiLabs to create a payment request for the customer currently chatting with this WhatsApp number instance."
}
]
}Use two kinds of permission keys:
| Permission kind | Example | Meaning | Enforced by KasiLabs? |
|---|---|---|---|
| Plugin-owned | gas:orders:create | Authority inside your plugin or external system | Not automatically |
| Platform bridge | plugin:payments:initiate:current_chat | Authority to ask KasiLabs to perform a platform-owned action | Yes |
Plugin-owned permissions are still useful. They tell the merchant what your plugin claims it can do, and your plugin backend should enforce them for your own business domain.
Platform bridge permissions are reserved by KasiLabs. They are enforced before a bridge action runs. If Gas OS lacks plugin:payments:initiate:current_chat, the payment bridge rejects the request before creating a payment.
Recipient scopes
Most dangerous actions are scoped by recipient.
| Scope | Meaning | Example |
|---|---|---|
current_chat | The customer currently chatting with the WhatsApp number instance | The plugin requests payment from the person who just ordered gas |
known_contact | A WhatsApp JID already known in this WhatsApp number instance's chat history | The plugin follows up with an existing customer |
external_recipient | A WhatsApp JID not yet known to this WhatsApp number instance | The plugin messages a new phone number supplied by an external system |
Use current_chat whenever possible. The plugin receives a short-lived context.currentChat.token when the AI calls one of its tools during a customer conversation. The plugin sends that token to a bridge instead of sending the raw WhatsApp JID.
Example bridge recipient:
{
"recipient": {
"type": "current_chat",
"token": "<context.currentChat.token>"
}
}For known_contact and external_recipient, the plugin must provide a JID. External-recipient permissions should be granted rarely because they let a plugin initiate actions toward people outside the active conversation.
Platform permissions available today
Payments:
| Permission | Allows |
|---|---|
plugin:payments:initiate:current_chat | Request payment from the current WhatsApp customer |
plugin:payments:initiate:known_contact | Request payment from an existing known chat |
plugin:payments:initiate:external_recipient | Request payment from a new external recipient |
plugin:payments:status:own | Read status for payments created by the same plugin |
plugin:payments:status:any | Read status for any payment on the WhatsApp number instance |
plugin:payments:refund:execute:own | Refund payments created by the same plugin |
plugin:payments:refund:execute:any | Refund any payment on the WhatsApp number instance |
E-Commerce:
| Permission | Allows |
|---|---|
plugin:ecommerce:orders:create:current_chat | Create an order for the current WhatsApp customer |
plugin:ecommerce:orders:create:known_contact | Create an order for an existing known chat |
plugin:ecommerce:orders:create:external_recipient | Create an order for a new external recipient |
plugin:ecommerce:orders:read:any | Read orders in the WhatsApp number instance |
plugin:ecommerce:catalog:sync | Let a dashboard user import the plugin's catalog into the platform E-Commerce catalog |
plugin:ecommerce:checkout:initiate | Start checkout for an order through the platform payment flow |
plugin:ecommerce:after_sales:support:create | Create a support request for an order |
plugin:ecommerce:after_sales:return:create | Create a return request |
plugin:ecommerce:after_sales:replacement:create | Create a replacement request |
plugin:ecommerce:after_sales:cancel:create | Create a cancellation request |
plugin:ecommerce:after_sales:refund:create | Create a refund request |
Messaging and escalation:
| Permission | Allows |
|---|---|
plugin:messages:send:current_chat | Send a text message to the current WhatsApp customer |
plugin:messages:send:known_contact | Send a text message to an existing known chat |
plugin:messages:send:external_recipient | Send a text message to a new external recipient |
plugin:messages:schedule:current_chat | Schedule a text message to the current WhatsApp customer |
plugin:messages:schedule:known_contact | Schedule a text message to an existing known chat |
plugin:messages:schedule:external_recipient | Schedule a text message to a new external recipient |
plugin:messages:escalate:current_chat | Create an escalation for the current WhatsApp customer |
plugin:messages:escalate:known_contact | Create an escalation for an existing known chat |
plugin:messages:escalate:external_recipient | Create an escalation for a new external recipient |
plugin:obligations:request | Submit plugin-owned obligations for reminder/escalation processing |
If one is missing, the bridge fails with a direct error such as:
Plugin is missing permission: plugin:payments:initiate:current_chatPermission combinations
Sensitive workflows usually need more than one permission.
| Workflow | Required permissions |
|---|---|
| Plugin creates a payment for the active customer and sends instructions | plugin:payments:initiate:current_chat, plugin:messages:send:current_chat |
| Plugin checks a payment it created | plugin:payments:status:own |
| Plugin creates a commerce order and starts checkout for the active customer | plugin:ecommerce:orders:create:current_chat, plugin:ecommerce:checkout:initiate, plugin:payments:initiate:current_chat |
| Plugin exposes products or services for platform checkout | plugin:ecommerce:catalog:sync |
| Plugin schedules a renewal reminder for the active customer | plugin:messages:schedule:current_chat |
| Plugin files a return request | plugin:ecommerce:after_sales:return:create |
| Plugin escalates an overdue delivery for the active customer | plugin:messages:escalate:current_chat |
The bridge checks permissions at execution time. A manifest declaration alone is not enough; the merchant must grant the permission on the WhatsApp number instance.
Dependency-only platform capabilities
Payments, M-Pesa, and E-Commerce can be available to a plugin without being exposed as raw agent tools. This is the preferred setup when a plugin owns the business workflow.
Example for a gas ordering plugin:
- Gas OS tools are agent-facing:
list_products,quote_order,create_b2c_order. - E-Commerce is dependency-only: it stores synced catalog items and durable orders.
- Payments or M-Pesa is dependency-only: it requests payment through the active provider.
The agent talks to the Gas OS tools. Gas OS talks to KasiLabs through signed bridges. The platform remains agnostic; it only enforces generic permissions and state transitions.
When a plugin has E-Commerce bridge permissions on a WhatsApp number instance, raw platform commerce_* tools are hidden from that agent. This reduces the risk of the AI bypassing the plugin's domain flow and calling a generic order tool directly.
Receipts are generated by the shared platform receipt action after payment succeeds. The customer receives one WhatsApp document message: the receipt PDF plus a short text summary as the caption.
Tool calls versus bridge calls
There are two ways a plugin participates.
| Path | Who starts it | Best for |
|---|---|---|
| Agent tool call | The AI agent during a conversation | Looking up external data, quoting, booking, creating external records |
| Platform bridge call | The plugin server, signed with its plugin secret | Payment requests, order creation, reminders, escalations, status updates outside the agent tool loop |
Use normal plugin tools when the agent needs reasoning. Use bridges when the plugin needs a deterministic platform-owned action.
Deterministic enforcement
The bridge does not ask the AI whether an action is allowed. It checks:
- The request signature is valid.
- The plugin is installed.
- The plugin is granted to the target WhatsApp number instance.
- The required permission is granted.
- The recipient scope is allowed.
- The current-chat token matches the plugin, organization, WhatsApp number instance, and expiry time.
- The request has an idempotency key for side effects.
- The request is recorded with status and result/error snapshot.
That means a retried request can return the same result instead of creating duplicate orders, duplicate payments, or duplicate reminders.
Relationship to employee permissions
Plugin permissions control what the plugin may request. Employee permissions control what dashboard users may do.
Example:
- Gas OS may request
plugin:ecommerce:orders:create:current_chat. - A fulfillment employee may have permission to mark the order out for delivery.
- A finance employee may have permission to issue refunds.
The plugin grant does not make every employee a finance manager. Employee permissions are still enforced in the dashboard and operational workflows.
Related pages
- Platform Bridges - Bridge endpoints, payloads, and examples
- Manifest Reference - How to declare permissions
- Testing & Debugging - How to test missing-permission cases