Ability Catalog
Every ability string a Subscriby token can carry, what enforces it, and how to pick the right ones when minting.
Ability strings are the fine-grained permissions you tick when you mint a personal access token. Miss the one an endpoint or tool needs and the request returns TOKEN_MISSING_ABILITY, naming it in error.context.required_ability.
One string, every surface
A single ability — say project-subscription-plan:create — is the source of truth in three places:
- The dashboard, when a human clicks "Create plan".
- The REST API, in the controller before the mutation runs.
- The MCP server, inside the tool handler before the action runs.
An MCP tool requires exactly what its REST equivalent requires. Mint for the operations you intend to perform, never for the channel you intend to perform them over. A client connected to the MCP server by signing in acts as the creator themselves and satisfies every ability their team role grants; this catalog governs what a personal access token carries.
Changed in 3.0.0: there is no channel ability
mcp:full has been removed. It read like full access and was really a
gate meaning "this token may speak MCP" — 47 of the tools behind it already
enforced a real ability of their own. Any token whose abilities cover the
tools it calls may now use MCP. Tokens that carried mcp:full are unaffected;
the value is simply no longer checked.
webhook-endpoint:manage has been split into the five endpoint verbs plus
two webhook-delivery: abilities. It still grants all seven on tokens that
carry it, but it cannot be granted to a new one — the mint endpoint refuses it
and names the replacements.
Format
<entity>:<action>, with : as the separator and - inside a multi-word entity or action — project-subscription-plan:view-any.
Most entities carry the five CRUD actions (view-any, view, create, update, delete). Two do not, because their lifecycle is not CRUD:
team-member— membership isinvited andremoved rather than created and deleted, andupdate-roleis its own action.webhook-delivery— a delivery is a record of something that already happened, so it can only be listed andretry'd.
The catalog
109 ability strings, of which 108 can be granted to a new token.
The Enforced on column says what actually checks each one today:
REST / MCP | A live endpoint or tool demands it. |
Dashboard | Enforced in the app, and by the webhook events it gates, but no API surface requires it. |
Coming | The ability exists and the surface that uses it is still being built. It grants nothing yet. |
No API surface | Deliberate — see the note on the row. |
Retired | Still honoured on tokens that hold it, refused on new ones. |
Projects
| Ability | Enforced on |
|---|---|
project:create | REST + MCP |
project:delete | REST + MCP |
project:update | REST + MCP |
project:view | REST + MCP |
project:view-any | REST + MCP |
Project resources
| Ability | Enforced on |
|---|---|
project-access-code:create | REST + MCP |
project-access-code:delete | REST |
project-access-code:update | Coming |
project-access-code:view | Coming |
project-access-code:view-any | REST + MCP |
project-connector:create | REST + MCP |
project-connector:delete | REST + MCP |
project-connector:update | REST + MCP |
project-connector:view | REST + MCP |
project-connector:view-any | REST + MCP |
project-coupon:create | REST + MCP |
project-coupon:delete | REST + MCP |
project-coupon:update | REST + MCP |
project-coupon:view | REST + MCP |
project-coupon:view-any | REST + MCP |
project-payment-method:create | Coming |
project-payment-method:delete | REST + MCP |
project-payment-method:update | REST + MCP |
project-payment-method:view | REST + MCP |
project-payment-method:view-any | REST + MCP |
project-recovery:create | REST + MCP |
project-recovery:delete | REST + MCP |
project-recovery:update | REST + MCP |
project-recovery:view | REST + MCP |
project-recovery:view-any | REST + MCP |
project-resource:create | REST + MCP |
project-resource:delete | REST + MCP |
project-resource:update | REST + MCP |
project-resource:view | REST + MCP |
project-resource:view-any | REST + MCP |
project-subscription-plan:create | REST + MCP |
project-subscription-plan:delete | REST + MCP |
project-subscription-plan:update | REST + MCP |
project-subscription-plan:view | REST + MCP |
project-subscription-plan:view-any | REST + MCP |
project-subscription:create | Coming |
project-subscription:delete | Coming |
project-subscription:update | REST + MCP |
project-subscription:view | REST + MCP |
project-subscription:view-any | REST + MCP |
project-user:create | Coming |
project-user:delete | Coming |
project-user:update | REST + MCP |
project-user:view | REST + MCP |
project-user:view-any | REST + MCP |
Support inbox
| Ability | Enforced on |
|---|---|
support-canned-reply:create | REST + MCP |
support-canned-reply:delete | REST + MCP |
support-canned-reply:update | REST + MCP |
support-canned-reply:view-any | REST + MCP |
support-conversation:create | Coming |
support-conversation:delete | Coming |
support-conversation:update | REST + MCP |
support-conversation:view | REST + MCP |
support-conversation:view-any | REST + MCP |
Teams
| Ability | Enforced on |
|---|---|
team-member:invite | REST + MCP |
team-member:remove | REST + MCP |
team-member:update-role | REST + MCP |
team-member:view | REST |
team-member:view-any | REST + MCP |
team:create | REST + MCP |
team:delete | REST + MCP |
team:update | REST + MCP |
team:view | REST + MCP |
team:view-any | REST + MCP |
Roles & groups
| Ability | Enforced on |
|---|---|
group:create | REST + MCP |
group:delete | REST + MCP |
group:update | REST + MCP |
group:view | REST |
group:view-any | REST + MCP |
role:create | REST + MCP |
role:delete | REST + MCP |
role:update | REST + MCP |
role:view | REST |
role:view-any | REST + MCP |
Webhooks
| Ability | Enforced on |
|---|---|
webhook-delivery:retry | REST + MCP |
webhook-delivery:view-any | REST + MCP |
webhook-endpoint:create | REST + MCP |
webhook-endpoint:delete | REST + MCP |
webhook-endpoint:manage | Retired — Split into the five webhook-endpoint verbs plus the two webhook-delivery abilities. Still grants all seven on tokens that carry it; cannot be granted to a new one. |
webhook-endpoint:update | REST + MCP |
webhook-endpoint:view | REST + MCP |
webhook-endpoint:view-any | REST + MCP |
API tokens
| Ability | Enforced on |
|---|---|
token:create | REST |
token:delete | REST + MCP |
token:view | REST |
token:view-any | REST + MCP |
Payments
| Ability | Enforced on |
|---|---|
payment:refund | Coming |
payment:view | Coming |
payment:view-any | Coming |
Passes
| Ability | Enforced on |
|---|---|
pass-window:create | REST + MCP |
pass-window:delete | REST + MCP |
pass-window:update | REST + MCP |
pass-window:view | REST + MCP |
pass-window:view-any | REST + MCP |
A token holding project-subscription-plan:view-any also satisfies pass-window:view-any, because the window list gated on the plan ability before the pass-window family had a surface of its own; tokens minted for n8n or the MCP docs keep working, and new tokens should carry pass-window:view-any explicitly.
Broadcast
| Ability | Enforced on |
|---|---|
broadcast:send | Coming |
Billing
| Ability | Enforced on |
|---|---|
billing:manage | No API surface — The creator's own Subscriby billing is deliberately dashboard-only. |
billing:read | No API surface — Subscribes an endpoint to the billing.* webhook events. The creator's own Subscriby billing has no REST surface to read. |
Account
| Ability | Enforced on |
|---|---|
account:read | REST — GET /v1/me/identities |
account:write | REST — DELETE /v1/me/identities/{identity} |
Analytics
| Ability | Enforced on |
|---|---|
dashboard:read | REST + MCP |
Activity log
| Ability | Enforced on |
|---|---|
activity:read | REST + MCP |
Distribution links
| Ability | Enforced on |
|---|---|
distribution:read | REST + MCP |
Machine-readable export
GET https://api.subscriby.net/abilities.jsonRegenerated on every deploy from the same enum the application checks against, so it cannot drift. Each entry carries value, category, status and, where one applies, a note.
Choosing abilities when minting
Least privilege, in practice:
- Read-only tooling — the
:view-anyand:viewabilities for the entities you read, and nothing else. - Automation that creates plans — add
project-subscription-plan:createand:update. - An assistant over MCP — add every ability for the tools you want it to run. Start with reads; the tools reference maps each tool to its ability.
- Zapier and n8n triggers — add
webhook-endpoint:createandwebhook-endpoint:delete; subscribing to events registers and removes an endpoint behind the scenes. - A token that mints other tokens — add
token:create, and read attenuation first. A token can only grant what it already holds, and can never pass ontoken:create.
Team and project scope entries
Alongside abilities, every token carries one required and zero-to-many optional scope entries:
scope:team:<uuid>— required. Frozen at mint time; the token can never act outside this team.scope:project:<uuid>— optional, repeatable. If present, the token is restricted to the listed project ids even when the user owns more projects inside the team.
These are stored in the same array as abilities but are not abilities, and the Tokens API reports them separately under scopes for that reason. See tenancy and scopes for how they combine with tenant isolation at request time.
How is this guide?