← ClerkCONTENT HISTORY

Update to Clerk

Snapshot Nov 6, 2026 · 00:16 UTC · version 0.3.0

Collection source: downloaded plugin package.

WHAT CHANGED

First saved snapshot

No earlier snapshot is available to establish a change.

Save Clerk and check future changes in Following.

Up to 3 plugins free · no card required.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Clerk Organizations for B2B and multi-tenant apps - org switching, roles and permissions, verified domains, and enterprise SSO. Use for team workspaces, RBAC, org-scoped routing, member management. Also load this when a project treats teams, workspaces, tenants, or companies as its customers - shared accounts, inviting teammates, per-seat pricing, per-company data isolation - even when the words \"organization\" or \"B2B\" are never used.",
  "included_files": [
    {
      "relative_path": "evals/evals.json",
      "size_in_bytes": 11438
    },
    {
      "relative_path": "references/enterprise-sso.md",
      "size_in_bytes": 6688
    },
    {
      "relative_path": "references/invitations.md",
      "size_in_bytes": 6429
    },
    {
      "relative_path": "references/nextjs-patterns.md",
      "size_in_bytes": 5511
    },
    {
      "relative_path": "references/roles-permissions.md",
      "size_in_bytes": 5870
    }
  ],
  "name": "clerk-orgs",
  "skill_md_contents": "---\nname: clerk-orgs\ndescription: Clerk Organizations for B2B and multi-tenant apps - org switching,\n  roles and permissions, verified domains, and enterprise SSO. Use for team workspaces,\n  RBAC, org-scoped routing, member management. Also load this when a project treats\n  teams, workspaces, tenants, or companies as its customers - shared accounts, inviting\n  teammates, per-seat pricing, per-company data isolation - even when the words\n  \"organization\" or \"B2B\" are never used.\nallowed-tools: WebFetch\nlicense: MIT\ncompatibility: Requires NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY. Organizations must be enabled in Clerk Dashboard → Organizations. Membership mode (required vs optional) must match the B2B vs B2C + B2B coexistence story of your app.\nmetadata:\n  author: clerk\n  version: 3.1.1\n---\n\n# Organizations (B2B SaaS)\n\n> **STOP — prerequisite.** Organizations must be enabled before any org-related API, hook, or component works. Two paths: (1) [Dashboard → Organizations settings](https://dashboard.clerk.com/last-active?path=organizations-settings), or (2) `clerk enable orgs` (see \"Agent-first: Programmatic org management\" below). Pick the Membership mode deliberately: `Membership required` (default since 2025-08-22) routes signed-in users through the `choose-organization` task and disables personal accounts, while `Membership optional` keeps personal accounts available for B2C + B2B coexistence. Pick `optional` if you need personal subscriptions alongside org subscriptions.\n>\n> **Version**: This skill targets current SDKs (`@clerk/nextjs` v7+, `@clerk/react` v6+ — Core 3). Core 2 differences are noted inline with `> **Core 2 ONLY (skip if current SDK):**` callouts — see `clerk` skill for the full version table.\n\n## Should this app use Organizations?\n\nDecide before enabling anything. Read the project, count the signals, then **ask the developer** - do not enable Organizations silently.\n\n**Signals this app is multi-tenant** (recommend Organizations):\n\n- A model that groups users: `Team`, `Workspace`, `Tenant`, `Company`, `Account`\n- The same foreign key on most tables: `workspace_id`, `team_id`, `account_id`\n- Routes scoped to a tenant: `/[workspace]`, `/[slug]/settings`, `/t/:tenantId`\n- \"Invite your team\", \"members\", \"seats\", or \"admin\" in UI copy or the README\n- A `*_members` join table, or hand-rolled `role` / `permission` columns\n- Per-seat or per-company pricing\n\n**Weaker signals** - enough to raise the question, not to answer it:\n\n- Sharing or collaboration between individual users: a `Share`, `Collaborator`, or `SharedWith` table keyed on two user IDs\n- A `role` or `permission` column with no tenant to scope it to\n- \"Collaborators\", \"shared with you\", \"invite a friend\" in copy\n\n**Signals this app is single-user** (do not recommend):\n\n- Every table hangs off `user_id` with no container above it, and nothing is shared\n- No invitation, membership, or sharing concept anywhere\n- Pricing is per person, or there is none\n\n**How to act:**\n\n| What you found | What to do |\n|---|---|\n| 2 or more strong signals | Recommend Organizations and name the signals you saw. New app: `clerk init --template b2b-saas`. Existing app: `clerk enable orgs`. |\n| 1 strong signal, or any weaker signal | Raise it as an option, state the tradeoff, let the developer choose. Sharing between individual users is not multi-tenancy - a `Share` table pointing at two user IDs has no tenant - but it is often where a product grows one. |\n| Nothing above | Don't bring it up. |\n\n**Never enable Organizations without asking.** Enabling it also turns on `Membership required`, which routes every signed-in user through organization selection and disables personal accounts. That is wrong for any app that also serves individuals. If the app needs both, it wants `Membership optional`.\n\n## Quick Start\n\n1. **Enable Organizations** — via [Dashboard → Organizations settings](https://dashboard.clerk.com/last-active?path=organizations-settings) or `clerk enable orgs` (see Agent-first section). Pick `Membership required` (B2B-only) or `Membership optional` (B2C + B2B).\n2. **Create an org** — via `<OrganizationSwitcher />`, `<CreateOrganization />`, or programmatically with `clerkClient().organizations.createOrganization()`.\n3. **Protect routes** — read `orgId` / `orgSlug` from `auth()` and gate with `has({ role })` or `has({ permission })`.\n4. **Manage members** — send invitations via Backend API or the built-in `<OrganizationProfile />` tab.\n5. **Cap membership** — set `maxAllowedMemberships` at org creation or pick a seat-limited Billing Plan (see `clerk-billing` skill).\n\n## What Do You Need?\n\n| Task | Reference |\n|------|-----------|\n| System permissions catalog, custom roles, role sets | references/roles-permissions.md |\n| Invitation lifecycle (create, list, revoke, built-in UI) | references/invitations.md |\n| Enterprise SSO setup, provider field access, domain verification | references/enterprise-sso.md |\n| Next.js adaptations for orgs (per-page role/permission checks, slug invariants, orgId-scoped writes) | references/nextjs-patterns.md |\n\n## References\n\n| Reference | Description |\n|-----------|-------------|\n| `references/roles-permissions.md` | Default + custom roles, System Permissions catalog, permission naming |\n| `references/invitations.md` | Backend API for invitations + built-in UI |\n| `references/enterprise-sso.md` | SAML/OIDC per-org, domain verification, correct field access |\n| `references/nextjs-patterns.md` | Next.js adaptations specific to orgs. For generic Next.js patterns see `clerk-nextjs-patterns` skill. |\n\n## Dashboard shortcuts\n\n| Action | URL |\n|---|---|\n| Enable Organizations + Membership mode | `https://dashboard.clerk.com/last-active?path=organizations-settings` |\n| Manage roles + permissions | `https://dashboard.clerk.com/last-active?path=organizations-settings/roles` |\n| Create/edit an organization | `https://dashboard.clerk.com/last-active?path=organizations` |\n| Webhooks for org events | `https://dashboard.clerk.com/last-active?path=webhooks` |\n\n## Agent-first: Programmatic org management\n\nOrg settings (enable toggle, membership cap, admin delete, domains) are patchable via PLAPI Instance Config. Org CRUD + memberships + invitations live in BAPI. Useful for agents seeding orgs, replicating settings across instances, or version-controlling org structure.\n\nPre-req: a linked project (`clerk auth login` + `clerk link`, see `clerk-cli`) — or an unclaimed app from `clerk init`: `clerk enable orgs` and org CRUD via `clerk api` work with no login at all.\n\n### Enable Organizations + settings via CLI\n\n```bash\nclerk enable orgs\n```\n\nFor additional settings (membership cap, verified domains, admin delete), patch the instance config:\n\n```bash\nclerk api --platform PATCH /v1/platform/applications/<app_id>/instances/<ins_id>/config \\\n  -d '{\"organization_settings\":{\"max_allowed_memberships\":50,\"domains_enabled\":true,\"admin_delete_enabled\":true}}'\n```\n\n### Create / list / delete orgs (BAPI)\n\n```bash\n# Create:\nclerk api -X POST /v1/organizations \\\n  -d '{\"name\":\"Acme\",\"slug\":\"acme\",\"created_by\":\"user_xxx\",\"max_allowed_memberships\":10}'\n\n# List:\nclerk api '/v1/organizations?limit=20'\n\n# Get one:\nclerk api /v1/organizations/<org_id>\n\n# Update:\nclerk api -X PATCH /v1/organizations/<org_id> -d '{\"name\":\"Acme Inc.\"}'\n\n# Delete:\nclerk api -X DELETE /v1/organizations/<org_id>\n```\n\n### Memberships\n\n```bash\n# Add a user to an org:\nclerk api -X POST /v1/organizations/<org_id>/memberships \\\n  -d '{\"user_id\":\"user_xxx\",\"role\":\"org:admin\"}'\n\n# List members:\nclerk api '/v1/organizations/<org_id>/memberships?limit=50'\n\n# Update role:\nclerk api -X PATCH /v1/organizations/<org_id>/memberships/<user_id> \\\n  -d '{\"role\":\"org:member\"}'\n\n# Remove:\nclerk api -X DELETE /v1/organizations/<org_id>/memberships/<user_id>\n```\n\n### Invitations\n\n```bash\n# Send:\nclerk api -X POST /v1/organizations/<org_id>/invitations \\\n  -d '{\"email_address\":\"alice@example.com\",\"role\":\"org:member\",\"redirect_url\":\"https://app.com/accept\"}'\n\n# List pending:\nclerk api '/v1/organizations/<org_id>/invitations?status=pending'\n\n# Revoke:\nclerk api -X POST /v1/organizations/<org_id>/invitations/<inv_id>/revoke \\\n  -d '{\"requesting_user_id\":\"user_xxx\"}'\n```\n\n### Notes\n\n- This handles **org config + CRUD**. Subscription / billing for orgs (org plans, seat-limit pricing) flows through `clerk-billing` skill.\n- Roles + permissions catalog is editable in `references/roles-permissions.md`. Custom role creation goes through `clerk config patch` (instance-level role definitions) — see Dashboard's role editor for the UX equivalent.\n- For SSO / verified domain provisioning, see `references/enterprise-sso.md`.\n\n## Documentation\n\n- [Overview](https://clerk.com/docs/guides/organizations/overview)\n- [Configure + enable](https://clerk.com/docs/guides/organizations/configure)\n- [Roles and permissions](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions)\n- [Check access](https://clerk.com/docs/guides/organizations/control-access/check-access)\n- [Invitations](https://clerk.com/docs/guides/organizations/add-members/invitations)\n- [OrganizationSwitcher](https://clerk.com/docs/reference/components/organization/organization-switcher)\n- [Verified domains](https://clerk.com/docs/guides/organizations/add-members/verified-domains)\n- [Enterprise SSO](https://clerk.com/docs/guides/organizations/add-members/sso)\n\n## Key Patterns\n\nExamples use `@clerk/nextjs` by default. For other frameworks swap the import to `@clerk/react` (Vite/CRA), `@clerk/astro/components`, `@clerk/vue`, `@clerk/expo`, `@clerk/react-router`, or `@clerk/tanstack-react-start` — the feature-level APIs (`has()`, `orgId`, `<OrganizationSwitcher />`, `<Show>`) are identical across SDKs. Framework-specific patterns (middleware, redirects) live in `references/nextjs-patterns.md`.\n\n### 1. Read Organization from Auth\n\nServer-side access to active organization:\n\n```typescript\nimport { auth } from '@clerk/nextjs/server'\n\nconst { orgId, orgSlug, orgRole } = await auth()\nif (!orgId) {\n  // user has no active org — either not in any, or viewing Personal Account\n}\n```\n\n`auth()` is Next.js-specific. Equivalent server-side accessors per SDK: `auth(event)` (Nuxt via `event.context.auth()`), `context.locals.auth()` (Astro), `getAuth(req)` (Express, after `clerkMiddleware()`). Client-side: `useAuth()` (React-based SDKs) or composables (Vue/Nuxt). All return the same `orgId` / `orgSlug` / `orgRole` shape.\n\n### 2. Dynamic Routes with Org Slug\n\nRoute-per-org pattern works in any framework supporting file-based dynamic routes. Next.js example:\n\n```\napp/orgs/[slug]/page.tsx\napp/orgs/[slug]/settings/page.tsx\n```\n\nAlways verify the URL slug matches the active org slug — otherwise users can hit `/orgs/other-org/...` with a stale `orgSlug` in their session:\n\n```typescript\nimport { auth } from '@clerk/nextjs/server'\nimport { redirect } from 'next/navigation'\n\nexport default async function OrgPage({ params }: { params: Promise<{ slug: string }> }) {\n  const { slug } = await params\n  const { orgSlug } = await auth()\n  if (orgSlug !== slug) {\n    redirect('/dashboard')  // or whatever your \"no-access\" flow is\n  }\n  return <div>Welcome to {orgSlug}</div>\n}\n```\n\nIn Next.js, add a `loading.tsx` next to a page like this one that gates its render with `redirect()`: with Cache Components (the `create-next-app` default), `next build` fails on request data read outside a `<Suspense>` boundary.\n\n### 3. Role-Based Access Control\n\n```typescript\nconst { has } = await auth()\n\nif (!has({ role: 'org:admin' })) {\n  return <div>Admin access required</div>\n}\n```\n\nPermission checks use the same `has()` surface, for custom Permissions you create in the Dashboard:\n\n```typescript\nif (!has({ permission: 'org:invoices:create' })) {\n  redirect('/unauthorized')\n}\n```\n\nOn the server, `has({ permission })` works only with custom Permissions: System Permissions (`org:sys_*`) aren't in the session token, so checking one there always returns `false`. Clerk documents permission checks in `<Show when={{ permission }}>` for custom Permissions only. To require a System Permission, check a role that carries it (`has({ role: 'org:admin' })`).\n\n**Permission naming convention.** System Permissions prefix with `org:sys_`; custom Permissions use `org:<resource>:<action>`. The full System Permissions catalog lives in `references/roles-permissions.md` — the short list is:\n\n- `org:sys_memberships:{read, manage}`\n- `org:sys_profile:{manage, delete}`\n- `org:sys_domains:{read, manage}`\n- `org:sys_billing:{read, manage}`\n\nDo NOT invent names like `org:create`, `org:manage_members`, `org:update_metadata` — those are not real permission slugs. See `references/roles-permissions.md` for custom roles and the permission table.\n\n### 4. Conditional Rendering with `<Show>`\n\nIn a Next.js Server Component, `<Show>` reads the session from the request, so wrap it in `<Suspense>`. In a Client Component, it reads client-side auth state and needs no boundary.\n\n```tsx\nimport { Show } from '@clerk/nextjs'\nimport { Suspense } from 'react'\n\n<Suspense>\n  <Show when={{ role: 'org:admin' }}>\n    <AdminPanel />\n  </Show>\n\n  <Show when={{ permission: 'org:invoices:create' }}>\n    <NewInvoiceButton />\n  </Show>\n</Suspense>\n```\n\n> **Core 2 ONLY (skip if current SDK):** Use `<Protect role=\"org:admin\">` / `<Protect permission=\"...\">` instead of `<Show>`. `<Show>` replaced both `<Protect>` and `<SignedIn>`/`<SignedOut>` in Core 3.\n\nAstro template syntax for the same component (imported from `@clerk/astro/components`):\n\n```astro\n<Show when={{ role: 'org:admin' }}>\n  <AdminPanel />\n</Show>\n```\n\n### 5. OrganizationSwitcher\n\n```tsx\nimport { OrganizationSwitcher } from '@clerk/nextjs'\n\n<OrganizationSwitcher\n  hidePersonal\n  afterCreateOrganizationUrl=\"/orgs/:slug/dashboard\"\n  afterSelectOrganizationUrl=\"/orgs/:slug/dashboard\"\n/>\n```\n\nKey props:\n- `hidePersonal: boolean` — hide the Personal Account option. Defaults to `false`. Pass `true` for B2B-only apps.\n- `afterCreateOrganizationUrl`, `afterSelectOrganizationUrl`, `afterLeaveOrganizationUrl`, `afterSelectPersonalUrl` — navigation hooks. `:slug` is substituted at runtime.\n- `createOrganizationMode`, `organizationProfileMode` — `'modal' | 'navigation'` (default `'modal'`).\n\nThe full prop list lives in the [component reference](https://clerk.com/docs/reference/components/organization/organization-switcher).\n\n### 6. Session Task — Choose Organization\n\nWhen `Membership required` is enabled (the default), users without an org are routed through a `choose-organization` session task after sign-in. Clerk handles this automatically inside `<SignIn />`, but you can host the UI yourself:\n\n```tsx\nimport { ClerkProvider } from '@clerk/nextjs'\n\n<ClerkProvider taskUrls={{ 'choose-organization': '/session-tasks/choose-organization' }}>\n  {children}\n</ClerkProvider>\n```\n\n```tsx\n// app/session-tasks/choose-organization/page.tsx\nimport { TaskChooseOrganization } from '@clerk/nextjs'\n\nexport default function Page() {\n  return <TaskChooseOrganization redirectUrlComplete=\"/dashboard\" />\n}\n```\n\n`TaskChooseOrganization` ships as an imported component in the React-based SDKs (`@clerk/nextjs`, `@clerk/react`, `@clerk/react-router`, `@clerk/tanstack-react-start`). For the JS Frontend SDK (`@clerk/clerk-js`) the equivalent is `clerk.mountTaskChooseOrganization(node)` / `clerk.unmountTaskChooseOrganization(node)`.\n\n> **Core 2 ONLY (skip if current SDK):** Session tasks aren't available. Force an org selection at sign-in by redirecting to a page that renders `<OrganizationSwitcher hidePersonal />`.\n\n## Default Roles + System Permissions\n\n| Role | Default meaning |\n|------|-------------|\n| `org:admin` | Full access — all System Permissions, can manage org + memberships |\n| `org:member` | Read members + Read billing Permissions only |\n\nYou can create up to 10 custom roles per instance in Dashboard → Organizations → Roles & Permissions. Role-per-org is controlled via **Role Sets** — see `references/roles-permissions.md` for the full model (custom roles, Creator/Default role settings, role sets, and the System Permissions catalog).\n\n## Billing Checks\n\n`has()` also supports plan and feature checks when Clerk Billing is enabled:\n\n```typescript\nconst { has } = await auth()\n\nhas({ plan: 'gold' })        // subscription plan\nhas({ feature: 'widgets' })  // feature entitlement\n```\n\n> **Core 2 ONLY (skip if current SDK):** `has()` only supports `role` and `permission`. Billing checks aren't available.\n\nSee `clerk-billing` for the full Billing surface and seat-limit plan model.\n\n## Enterprise SSO\n\nPer-org SAML/OIDC. Configured in Dashboard → Configure → Enterprise Connections (or per-org: Organizations → select org → SSO Connections). The SSO connection owns its domain directly; no separate Verified Domain is required (and the two features are mutually exclusive on the same domain). Auto-join on first SSO sign-in uses JIT Provisioning, not Verified Domains. Key fact: the `provider` field lives on `enterpriseConnection`, not on `enterpriseAccounts[0]` directly. See `references/enterprise-sso.md` for the full flow and correct field access.\n\n```typescript\n// Strategy name for Enterprise SSO (Core 3)\nstrategy: 'enterprise_sso'\n```\n\n> **Core 2 ONLY (skip if current SDK):** Uses `strategy: 'saml'` and `user.samlAccounts` instead of `user.enterpriseAccounts`.\n\n## Gotchas\n\n### `maxAllowedMemberships` caps seats\n\n```typescript\nconst clerk = await clerkClient()\nawait clerk.organizations.createOrganization({\n  name: 'Acme Corp',\n  createdBy: userId,\n  maxAllowedMemberships: 10,\n})\n\n// Update later:\nawait clerk.organizations.updateOrganization(orgId, {\n  maxAllowedMemberships: 25,\n})\n```\n\nFor tier-based seat limits tied to a subscription, use a seat-limited Billing Plan (see `clerk-billing`).\n\n### Billing gates Permissions at the Feature level\n\nWhen Clerk Billing is enabled, `has({ permission: 'org:posts:edit' })` returns `false` if the Feature associated with that permission is not included in the organization's active Plan — even if the user has the Permission assigned via their role. Ensure the Feature is attached to the active Plan in Dashboard → Billing → Plans → Features.\n\n### Metadata updates REPLACE, not merge\n\n`updateOrganization({ publicMetadata })` overwrites all public metadata. Read first, spread, then write:\n\n```typescript\nconst org = await clerk.organizations.getOrganization({ organizationId: orgId })\nawait clerk.organizations.updateOrganization(orgId, {\n  publicMetadata: { ...org.publicMetadata, newField: 'value' },\n})\n```\n\nApplies identically to `privateMetadata` and to user metadata via `clerkClient.users.updateUser`.\n\n## Error Signatures (diagnose fast)\n\nMost \"org-related\" failures are configuration, not code. Do not edit components before checking these:\n\n| Error / symptom | Root cause | Fix |\n|---|---|---|\n| `orgId` / `orgSlug` is `undefined` for a signed-in user | Organizations not enabled for this instance, OR user has no active org (personal account) | Enable in Dashboard → Organizations; check Membership mode; surface `<OrganizationSwitcher />` |\n| `has({ permission: ... })` always `false` | An invented slug (`org:manage_members`), or a System Permission (`org:sys_*`), which `has()` can't check | Check the role (`has({ role: 'org:admin' })`) or a custom Permission created in the Dashboard (see roles-permissions.md) |\n| `has({ role })` returns `false` but user looks like an admin | Session token stale after role change | Re-sign-in, or refresh the session: `await clerk.session?.reload()` |\n| `has({ permission })` `false` even with the role assigned | Feature not attached to active Plan (Billing gates permissions) | Dashboard → Billing → Plans → attach Feature |\n| `<OrganizationSwitcher />` doesn't show \"Personal Account\" | `Membership required` mode is on (the default since Aug 22, 2025) | Dashboard → Organizations settings → `Membership optional` |\n| `TaskChooseOrganization` throws \"cannot render when a user doesn't have current session tasks\" | Rendered outside a `choose-organization` task context | Wrap in a `choose-organization` session-task route only; don't render unconditionally |\n| `enterpriseAccounts[0].provider` is `undefined` | Accessing `provider` at the wrong nesting level | Use `user.enterpriseAccounts[0].enterpriseConnection?.provider` |\n\n## Authorization Pattern (Complete Example)\n\nServer component protecting a slug-scoped admin page:\n\n```typescript\nimport { auth } from '@clerk/nextjs/server'\nimport { redirect } from 'next/navigation'\n\nexport default async function AdminPage({ params }: { params: Promise<{ slug: string }> }) {\n  const { slug } = await params\n  const { orgSlug, has } = await auth()\n\n  if (orgSlug !== slug) redirect('/dashboard')\n  if (!has({ role: 'org:admin' })) redirect(`/orgs/${orgSlug}`)\n\n  return <div>Admin settings for {orgSlug}</div>\n}\n```\n\nAdd a `loading.tsx` next to it so `next build` passes with Cache Components.\n\nFor per-page role and permission checks with `auth.protect()` (Next.js) see `references/nextjs-patterns.md`.\n\n## Invitations (short form)\n\nSend from a server action or route handler:\n\n```typescript\nimport { clerkClient, auth } from '@clerk/nextjs/server'\n\nexport async function inviteMember(emailAddress: string, role: string) {\n  const { userId, orgId, has } = await auth()\n\n  if (!userId || !orgId) throw new Error('No active organization')\n  // Inviting needs the System Permission org:sys_memberships:manage, which\n  // has() can't check, so check a role that carries it.\n  if (!has({ role: 'org:admin' })) {\n    throw new Error('Not authorized to invite members')\n  }\n\n  const clerk = await clerkClient()\n  return clerk.organizations.createOrganizationInvitation({\n    organizationId: orgId,       // the active org that has() checked\n    inviterUserId: userId,       // required per Backend API\n    emailAddress,\n    role,                        // e.g. 'org:admin' or 'org:member'\n    redirectUrl: 'https://yourapp.com/accept-invite',\n  })\n}\n```\n\nThe full lifecycle (list, revoke, bulk create, built-in `<OrganizationProfile />` UI) lives in `references/invitations.md`.\n\n## Workflow\n\n1. **Enable** — Organizations + Membership mode in Dashboard\n2. **Create org** — via UI component or Backend API\n3. **Invite members** — Backend API or built-in UI, with `inviterUserId`\n4. **Gate access** — `has({ role })`, or `has({ permission })` with a custom Permission. `has()` can't check System Permissions (`org:sys_*`)\n5. **Scope routes** — `orgSlug === params.slug` on every protected page\n6. **Switch orgs** — `<OrganizationSwitcher />` handles the whole flow\n\n## See Also\n\n- `clerk-setup` — Initial Clerk install\n- `clerk-billing` — Seat-limit plans, per-plan billing, `has({ plan })` / `has({ feature })`\n- `clerk-webhooks` — Sync org events to your database (`organization.created`, `organizationMembership.*`)\n- `clerk-backend-api` — Full Backend API reference\n- `clerk-nextjs-patterns` — Framework-specific middleware, server actions, caching\n"
}

SHA-256 of public snapshot: b91743a72d8c6f783e78b850be15dabdc66e2b734767b09e50d0a2333b67dc1f