Skip to main content

Scopes

Scopes are the unit of authorization on Roam API tokens (API keys, OAuth grants, and Personal Access Tokens). Request them at OAuth consent (space-separated scope query parameter) or when creating a PAT / API key in Developer settings.

Canonical names and descriptions are defined in the server scope registry (common/apiScopes.json). Endpoint pages restate the Required scope for each operation; if a page and this catalog disagree, trust the running API and file a docs bug.

Requesting scopes

OAuth authorize URL — space-separated list:

scope=chat:history%20chat:send_message%20user:read

PAT creation UI — choose PAT groups (below). Groups expand to concrete scopes stored on the token.

Aliases: the only documented alias today is groups:read → canonical group:read. Comparisons always use the canonical form. Some write endpoints also accept the legacy alternate chat:write as a synonym for chat:send_message at the require-scope check (it is not a separately grantable scope in the registry).

OAuth / API key scopes

ScopeDescription
addr:infoRead information about a chat participant (historical spelling; public resolution is user.info / group.info)
admin:compliance:readRead certain compliance data exports
admin:meetings:readOrg only. View all meetings, recordings, and transcripts in this Roam (see Meeting width)
calendar:readRead events from a user's connected calendars (calendar.list)
calendar:writeCreate and update calendar events
chat:historyRead messages from public chats, or chats the app has been added to
chat:joinJoin public chats
chat:readList public chats, or ones the bot has been added to
chat:send_messageSend chat messages (also accepted as chat:write on write endpoints)
commandsSlash commands and message actions (interactivity; limited public surface today)
group:readView public groups (groups:read is a legacy alias)
group:writeCreate and manage groups; group.join (self-join a public group)
item:readView item / attachment details
item:writeCreate items / uploads
links:readReceive links shared in chats the app can see (chat.link.shared)
links:writeAttach rich previews via chat.unfurl
lobby:readView lobbies and lobby bookings
magicast:readView Magicasts
meetinglink:readView meeting links
meetinglink:writeCreate / update meeting links
meetings:readView meetings the app has access to (see Meeting width; calendar:read for calendars)
onair:readView On-Air events, guests, and hosts
onair:writeCreate and manage On-Air events, guests, and hosts
recordings:readView meeting recordings the app has access to (legacy recording.list surface)
transcript:readView meeting transcripts the app has access to (prefer meetings:read on v1)
user:readList / resolve users
user:read.emailInclude user email addresses
user:read.statusView member check-in status and will-return times; required for user.status.update webhooks
user:writeCreate and update users
userauditlog:readRead user audit logs
webhook:readList webhook subscriptions and failed deliveries
webhook:writeSubscribe / unsubscribe webhooks; lifecycle events

Hidden / legacy registry entries (create_tags, meeting:write, hidden groups:read) may appear in older grants; prefer the canonical names above.

calendar:read and meetings:read

Reading a user's connected calendars (calendar.list, and the calendar_list MCP tool) requires calendar:read. That access used to fall under meetings:read.

Client registeredScope that grants calendar access
Before 2026-07-29T00:00Zmeetings:read (grandfathered) or calendar:read
On or after 2026-07-29T00:00Zcalendar:read only

A client registered on or after the cutoff that holds only meetings:read gets 403 / missing_scope naming calendar:read when it calls calendar.list. Existing grants keep working; new authorizations should request calendar:read. Requesting both is harmless if one codebase serves grants from either side of the cutoff.

This affects calendar access only — meetings:read is unchanged for meetings, transcripts, participants, search, and prompt.

Personal Access Tokens created with the pat:meetings:read group are unaffected on either side of the cutoff: the group expands to include calendar:read.

Meeting width (admin:meetings:read)

meetings:read / recordings:read / transcript:read are the capability to call those APIs and subscribe to those events. They do not mean every meeting in the Roam. Width is:

CredentialMeetings, recordings, transcripts, and those webhooks
PersonalMeetings the token owner participated in. Personal tokens never get roam-wide access — admin:meetings:read is stripped on authorize and is not in any PAT group.
Org without admin:meetings:readMeetings the install's bot already has access to. This set is usually empty unless the bot was a participant on the saved meeting.
Org with admin:meetings:readEvery meeting, recording, and transcript in the installed Roam.

API keys default admin:meetings:read on in Developer Settings when you enable a meeting scope (the Sales Ops / CRM path: an admin-issued key should see every recording). OAuth apps default it off (the app developer is not the installing account). Adding the scope to an OAuth app does not widen existing tokens until they re-authorize.

Existing API keys that already had roam-wide meeting access keep it without the new scope. There is no Meeting Access toggle — that control is gone.

/v0/meeting.list, /v1/conversation.list, and /v1/recording.list cannot filter by bot access today. Org clients without roam-wide meeting access get 403; use /meeting.list instead.

This is the same split chat already has: ordinary scopes for “what you can see,” admin:compliance:read for company-wide export. All-recordings is the original public API, not a compliance product.

Vocab notes (honest)

  • addr:info is a historical spelling (not address:info). Public principal and group resolution is user.info / group.info.
  • meetings:read / recordings:read use plural nouns; most other scopes are singular (group:read, user:read).
  • chat:write is accepted by many write handlers alongside chat:send_message but is not a first-class grantable name in the scope picker registry.

Webhook event → required scope

Subscribe requires the listed scope (and delivery enforces it). Enrichment scopes (e.g. user:read.email) are additional when noted on the event page.

EventRequired scope
chat.messagechat:history
chat.reactionchat:history
chat.link.sharedlinks:read
meeting.startedmeetings:read (width: Meeting width)
meeting.endedmeetings:read (width: Meeting width)
user.status.updateuser:read.status (not user:read alone)
lobby.bookedlobby:read
magicast.createdmagicast:read
onair.event.createdonair:read
onair.event.updatedonair:read
onair.event.canceledonair:read
onair.guest.addedonair:read
onair.guest.rsvponair:read
token.revokedwebhook:write
app.uninstalledwebhook:write

Personal Access Token groups

PAT creation offers grouped scopes that expand server-side:

PAT groupExpands to (canonical)
pat:chat:readchat:read, chat:history, item:read, addr:info, user:read, user:read.email, group:read, webhook:read, webhook:write
pat:chat:writechat:send_message, item:write, user:read, user:read.email, group:read, webhook:read, webhook:write
pat:meetings:readmeetings:read, calendar:read, recordings:read, transcript:read, meetinglink:read, lobby:read, user:read, user:read.email, webhook:read, webhook:write
pat:magicast:readmagicast:read, user:read, user:read.email, webhook:read, webhook:write
pat:calendar:writecalendar:write, user:read, user:read.email, webhook:read, webhook:write
pat:groups:writegroup:write, group:read, user:read, user:read.email, webhook:read, webhook:write

token.info reports the expanded OAuth scopes on the credential, not the pat:* group names.

pat:meetings:read does not include admin:meetings:read. Personal tokens cannot hold roam-wide meeting access.

Missing scope errors

When a token lacks a required scope, the API returns HTTP 403 with error: "missing_scope" and machine-readable needed / provided arrays. See Responses and Errors.