SaaS workspaces and teams
Model workspaces as /workspaces/{id}. Add people to groups such as group:acme-admins and grant the group a role on the workspace, so joining or leaving a team is one membership change.
How groups workPermio is an authorization API for multi-tenant apps: role-based access control with inheritance, so a grant on a workspace covers everything in it. Add it to Next.js, Node, Python, Go or Rust, by hand or with AI coding tools.
Free plan, no payment details needed to start.
Your first permission check in five minutes

Without Permio
if (user.role === 'admin' || user.id === project.ownerId)if user.is_staff or user.plan == "pro":{isAdmin && <DeleteButton />}Role checks copied into every service, drifting apart.
With Permio
Define once
document.read document.edit editor
Grant on a resource
editor to user_42 on /projects/123
Flows down to everything under it.
Check from anywhere
Resources are paths. Grant a role once and it flows down the tree. Your app signs people in; Permio tells it what each of them is allowed to do.
Resources
/projects /projects/123 grant: editor → user_42/projects/123/docs/7 inherited/projects/123/docs/9 inherited/projects/123/invoices/2 inherited/projects/999 no access/projects/999/docs/1 no accessChecks for user_42 · document.edit
/projects/123/docs/9 /projects/999/docs/1 Anything without a matching grant is denied. Checks fail closed.
Name the actions your code checks, such as document.read, and bundle them into roles like editor.
Give a user, service or group a role on /projects/123. Everything below it is covered, including things created later.
One call returns allowed or denied, with the missing permissions when it’s a no.
Install the SDK and make one call per request.
TypeScript · permio SDK on npm
// npm install permio
import { Permio } from 'permio';
const permio = new Permio({ apiKey: process.env.PERMIO_API_KEY!, project: 'default' });
const allowed = await permio.check({
principal: user.id,
resource: `/documents/${docId}`,
permission: 'document.read',
});
if (!allowed) return new Response('Forbidden', { status: 403 });TypeScript, Python, Go, Rust and Java have official SDKs. Any other language can call the REST API directly. Read the quickstart
Give Sam a role somewhere in this workspace, then check a few docs. You’ll see the answer, why, and the call your backend would make.
/projects /projects/acme editor → sam /projects/acme/docs/42 inherits editor /projects/acme/docs/43 inherits editor /projects/globex /projects/globex/docs/7 Last check
/projects/acme/docs/42 doc.edit for sam
Inherited from editor on /projects/acme.
Check · the same call with the permio SDK
await permio.check({
principal: 'sam',
resource: '/projects/acme/docs/42',
permission: 'doc.edit',
}); // true
Nothing here talks to a server: it’s the same rules running in your browser. Grants cover
everything below them, so /projects/globex stays
out of reach of a grant on /projects/acme.
The pieces teams usually build by hand, already built and tested.
Grant on any resource path. A grant on /projects/123 covers every document below it.
Grant to group:editors once and every member holds it. Add or remove people without touching grants.
Show each user only what they can see: listAccess gives you a database filter, and whoHasAccess powers “shared with” lists.
See exactly why access was allowed or denied, with the grants and inheritance that decided it.
An activity feed of every change to permissions, roles, grants, groups and API keys.
Keys are check-only by default, with full access when you need it. Each key is shown once and stored hashed, and revoking it takes effect instantly.
Keep Auth0, Clerk, Firebase, Supabase or your own login. Your login says who someone is; Permio says what they’re allowed to do.
npm install permio, or call the JSON REST or gRPC API from any language. Batch up to 100 resources per call.
One model covers the patterns most apps need.
Model workspaces as /workspaces/{id}. Add people to groups such as group:acme-admins and grant the group a role on the workspace, so joining or leaving a team is one membership change.
How groups workShare a folder and its files follow through inheritance. Share one file with a single grant. whoHasAccess lists everyone who can open it, for the “shared with” panel.
Access queriesPut the tenant at the top of every URI, so a grant under /tenants/acme can never reach /tenants/globex. Use separate projects for dev and prod.
Multi-tenant patternGive each agent its own principal with only the grants its user allows, and a check-only key for its backend, so the agent can never do more than the user permits.
Permissions for AI agentsBuilding with Cursor, Claude Code or another coding assistant? Paste this prompt. It points the assistant at our machine-readable docs, keeps your existing login, and asks it to guard routes and filter lists properly.
Assistants can also read /llms.txt and /llms-full.txt directly.
Add authorisation to this app with Permio (perms.io), using the `permio` npm package.
Read these first:
- https://perms.io/llms-full.txt (model, APIs and SDK usage)
- https://docs.perms.io/sdk/typescript/
Then:
1. npm install permio, and create one server-side client: new Permio({ apiKey: process.env.PERMIO_API_KEY, project: "default" }). Never ship the key to the browser.
2. Keep our existing login. Use the authenticated user's ID as the Permio principal.
3. Design resource URIs from our data model, e.g. /workspaces/{id}/docs/{id}, built with the SDK's resource() helper. Propose permission names (e.g. doc.read, doc.write) and roles.
4. Guard every route or server action that reads or changes data with permio.check() or permio.assert(), and return 403 when denied.
5. Filter list endpoints with permio.listAccess() + toPrefixes() instead of loading everything.
6. List the permissions, roles and grants I need to create in the Permio dashboard. A principal is any user, service or agent you check or grant permissions for. Plans count active principals: each distinct principal used in a billing period counts once, however many calls it's in.
For trying Permio and side projects.
£0 a monthPrices in GBP, billed monthly. Free needs no payment details.
A principal is active in a billing period if it is checked (Check, BatchCheck or ListAccess), granted something or added to a group in that period. Checking or granting a group counts each of its members. Revoking access does not lower the count, and the count starts again each billing period. Free is a hard limit with no overage: once 1,000 principals are active in a billing period, granting to, or adding to a group, a principal with no existing grants or group memberships is refused until the next period. Checks and principals you already use keep working. How limits work
No. Permio does authorisation, not authentication. Keep your existing login (Auth0, Clerk, Firebase, Supabase or your own) and pass the user ID you already have to Permio as the principal.
Call listAccess with the principal, a permission and the part of the tree you are listing (for example "/docs"). It returns scopes; toPrefixes() turns them into URI prefixes you can use in a SQL, Prisma or MongoDB filter, so you query once instead of checking row by row. For a short list you already have, batchCheck answers up to 100 resources in one call.
Resources are paths such as /projects/123/docs/9. A grant on /projects/123 applies to that resource and everything below it, including things created later. Grants never flow upwards or sideways, so /projects/999 is untouched. A _ segment in a stored grant matches exactly one segment, for example /docs/_/comments.
A group is a named set of principals in a project, such as editors. Grant permissions or roles to its principal ID, group:editors, and every member holds them. Checks include a principal’s groups automatically.
There are official SDKs for TypeScript (npm install permio, which runs on Node 18+, edge runtimes and browsers), Python (pip install permio), Go (go get github.com/PrivateJAR/permio-go), Rust (cargo add permio) and Java (io.perms:permio), all open source under Apache-2.0. Any other language can call the REST (JSON) or gRPC / gRPC-web API directly.
There’s a free plan, and you don’t need to enter payment details to sign up. The paid plans are in the pricing section. Every plan is priced on active principals: the distinct users, services or agents you check or grant permissions for in a billing period.
A principal is active in a billing period if it is checked (Check, BatchCheck or ListAccess), granted something or added to a group in that period. Checking or granting a group counts each of its members. Revoking access does not lower the count, and the count starts again each billing period. Free is a hard limit with no overage: once 1,000 principals are active in a billing period, granting to, or adding to a group, a principal with no existing grants or group memberships is refused until the next period. Checks and principals you already use keep working. Starter and Growth have no hard limit; principals above the included amount are billed per principal. Details: https://docs.perms.io/concepts/plans-and-limits/
Yes. Connect an MCP client such as Claude Code, Cursor or VS Code to https://mcp.perms.io/mcp with a Permio API key in an Authorization: Bearer header. A check-only key can check access and read permissions, roles, groups and grants; a full-access key can also make changes. https://mcp.perms.io/mcp/read offers only the read tools whatever the key. Details: https://docs.perms.io/guides/mcp/
Permio’s services run on Google Cloud Run in the London region (europe-west2), and data is stored in MongoDB Atlas. Dashboard sign-in uses Firebase Authentication and payments use Stripe.
Hand-rolled checks tend to spread through the codebase as if-statements on roles. Permio gives you one model (permissions, roles, groups and grants on resource paths), one check call from every service, list filtering and “who has access” queries, an Access tester that explains each decision, and an audit log of changes, without building or maintaining any of it.
The quickstart takes you from sign-up to your first check.
Define it once, check it from anywhere.