Capabilities
How Capabilities, Roles, RoleAssignments, and Scopes compose into authority, and where API keys differ
Authority is composed from four nouns and one rule.
| Noun | What it is |
|---|---|
| Capability | One named action, such as events.publish or payments.refund |
| Role | An Organization-defined named set of Capabilities |
| RoleAssignment | One Role granted to one Member at one Scope |
| Scope | The resource subtree a grant applies to |
The rule: effective Capabilities are the additive union of every active assignment that applies. There is no deny, no priority order, and no nested Role.
Scopes and inheritance
Allowed scopes are Organization, EventGroupSeries, EventSeries, EventGroup, Event, and CheckInSession. Three ancestry paths exist:
Diagram source
flowchart TD
O[Organization] --> GS[EventGroupSeries]
GS --> G[EventGroup]
G --> GE[Event]
O --> RS[EventSeries]
RS --> SE[Event]
O --> ST[Standalone Event]
GE --> C[CheckInSession]
SE --> C
ST --> CA grant at any level reaches everything beneath it on its path. An Event that belongs to both an EventGroup and an EventSeries inherits from both, plus the Organization and the Event itself.
EventSession and Pass operations inherit Event scope, so a Pass is never a grant target.
Scope is stored, but domain operations do not yet honour it. Role assignment and API-key issuance resolve a grant against the target ancestry. Every domain service — publishing, registration, payments, requirements, check-in — authorizes from Organization-scoped assignments only. An Event-scoped grant therefore does not currently authorize work on that Event.
Moving an Event between groups changes the ancestry immediately, because ancestry is read live. The move itself is an ordinary Event update: no confirmation and no audit record.
The catalog
Capability names are stable and versioned in code, and the catalog is exposed for the Role editor.
| Family | Examples |
|---|---|
| Organization and access | organization.read, organization.update, members.invite, roles.assign, domains.verify, sso.manage, api_keys.create |
| Publishing | events.read, events.create, events.update, events.publish, events.cancel, event_sessions.delete, passes.update, passes.cancel, coupons.manage |
| Participation | registrations.read, registrations.create, registrations.cancel, participants.remove, registration_approvals.review |
| Money | orders.read, orders.export, payments.refund, ledger.read, payouts.manage |
| Admission | checkin_sessions.create, checkin_sessions.operate |
| Reporting and gating | audit.read, notifications.read, requirements.manage |
| Integration | webhooks.create, webhooks.replay |
Seeded Roles
Organizations begin with reviewed Roles; custom Roles use the same catalog.
| Role | Reaches | Notes |
|---|---|---|
| Owner | Everything | Protected wildcard; its invariants cannot be edited away |
| Administrator | The whole catalog | The practical "run the Organization" Role |
| Event Manager | Events, Sessions, Passes, coupons, applications, Registrations, Participants, approvals, Orders read and export, Check-In | No refunds, ledger, payouts, or audit |
| Finance Viewer | Organization read, Orders, payments, ledger, payouts, exports | Read-only |
| Check-in Operator | Organization read, Check-In read and operate, PassIssue read, Teams read | The narrowest door Role |
Wildcards are reserved for protected Roles and platform operations; platform capabilities are never assignable by an Organization user.
Separations that exist on purpose
Some Capabilities are split because the money or the risk differs.
| Separation | Why it exists |
|---|---|
audit.read from organization.read | Reading the Organization does not grant reading who changed what. |
registrations.transfer from registrations.switch | Transferring who holds a Registration on the same Pass is money-neutral. Moving a Registration to another Pass is a switch; a switch that credits also calls the refund path, so it additionally needs payments.refund. A switch that charges needs no extra capability. |
participants.transfer | Catalogued for person-in-place roster moves. No operation checks it today: a roster replacement checks participants.remove for an organizer, or the buyer's own authority. |
| Report and Insight reads | Gated by the domain read Capability of the data they present: Orders for revenue, checkin_sessions.read for attendance, events.read for traffic and attribution, audit.read for the activity log. |
Human principals and API-key principals
A browser session acts as a human Account. An API key acts as itself.
Account (Member)
- Authority source — Organization-scoped RoleAssignments
- Lifetime — follows membership
- Narrowing — change the Role or assignment
- Key management — allowed with
api_keys.read,.create, or.revoke - Expiry — not applicable
API key
- Authority source — its own Capability and Scope set
- Lifetime — independent of the issuer once created
- Narrowing — change its capabilities, change its Scope, revoke, or reissue
- Key management — forbidden, whatever it declares
- Expiry — optional; a key with no expiry never expires
Four rules follow from that difference.
- Issue time. A key's Capabilities and Scope must be a subset of the issuer's authority at that Scope.
- Afterwards. The issuer's departure or demotion does not revoke it.
api_keys.readcan inspect it, andapi_keys.revokecan revoke it independently of the issuer. - Suspension. Organization suspension rejects every key;
API_KEYS_SUSPENDEDis a platform kill-switch. - Key management. Session-only and human; no key can create, read, update, or revoke a key.
How authorization is applied
An API operation resolves the principal, the explicit Organization, the Capability, and the target resource; an API-key request also resolves the key's declared Scope. The server decides; UI visibility is convenience only.
API-key authorization checks the key's Capability and walks the target's ancestry to confirm its Scope covers the resource. Human authorization checks the Organization-scoped RoleAssignments only, as described above.
Capabilities are recomputed from the database on each request; there is no capability cache to invalidate.
Unauthorized reads of another tenant's resource are indistinguishable from missing ones.
Does `organization.read` let me read the audit log?
No. audit.read is separate and is not implied by reading the Organization.
What happens to an API key when the person who issued it leaves?
It survives. A key's authority becomes independent of the human issuer after creation; administrators holding api_keys.read can inspect it and api_keys.revoke can revoke it.
Can an API key create, read, or revoke another API key?
No. Key management is session-only and human, whatever the key declares.
Do I need a separate permission to read revenue?
No separate taxonomy exists: report and Insight reads are gated by the domain read Capability of the data they present, so revenue needs Orders access and attendance needs Check-In access.
Related
- Organizations — the owner above all of this
- Invite your team — the administrative walkthrough
- Requirements — the other additive hierarchy