Guest Badges
A Guest Badge lets a workspace member host an email that is not a member of the Roam. The guest can visit that host; they do not become a provisioned user (that is SCIM) and they are not an On-Air event guest.
| Action | Endpoint |
|---|---|
| Grant a badge | POST /guest.badge.create |
| List issued badges | GET /guest.badge.list |
| Update visit permission | POST /guest.badge.update |
| Revoke a badge | POST /guest.badge.revoke |
group.add can attach the same email to a channel. It
does not mint a Guest Badge or send the invite. Typical CSM onboarding:
guest.badge.createwith the client's email and a hostgroup.addif they should also land in a channelguest.badge.updateif you need to flipvisitPermissionafter createguest.badge.revoketo offboard
Authorization
| Credential | Who you can host as | Scope |
|---|---|---|
| Organization API key / org OAuth | Any member, via hostUserId (UUID or member email) | guest:write (create / update / revoke); guest:read (list) |
| Personal Access Token | The token owner only | pat:guests:write (expands to guest:write and guest:read) |
| Personal OAuth | The token owner only | guest:write / guest:read |
Naming another host on a personal token returns 403 access_mode_not_supported.
A host who is not allowed to grant badges (account grant level /
canGrantAccessBadge) returns 403 guest_badge_forbidden. Unknown hosts
return 404 user_not_found.
Organization keys issued with only guest:write cannot list until
guest:read is added. PATs with pat:guests:write already include both.
Create
curl -X POST https://api.ro.am/v1/guest.badge.create \
-H "Authorization: Bearer $ROAM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "alex@client.example",
"hostUserId": "3f1c0b2a-8d4e-4c91-9a7b-2e6f1d8c0a11"
}'
hostUserId may be a member UUID or email (same as group.create
members[].userId). Personal tokens may omit it. visitPermission defaults
to true. Repeating the same host and email returns the existing row without
changing visitPermission or re-sending mail.
The response hostUserId is always a UUID. userId is the guest's chat
address when one has been provisioned.
List
curl "https://api.ro.am/v1/guest.badge.list?email=alex@client.example" \
-H "Authorization: Bearer $ROAM_TOKEN"
Organization tokens see every issued badge in the workspace. Personal tokens
see only badges they issued. Optional email (alias-aware) and hostUserId
filters; limit (default 50, max 100) and opaque cursor for pagination.
Update visit permission
Create does not change visitPermission on an existing grant. To flip
on-map access:
curl -X POST https://api.ro.am/v1/guest.badge.update \
-H "Authorization: Bearer $ROAM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "alex@client.example",
"hostUserId": "3f1c0b2a-8d4e-4c91-9a7b-2e6f1d8c0a11",
"visitPermission": false
}'
visitPermission is required. A missing grant is 404 not_found. If
several hosts granted the same email, pass hostUserId to pick one.
Revoke
curl -X POST https://api.ro.am/v1/guest.badge.revoke \
-H "Authorization: Bearer $ROAM_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "alex@client.example"
}'
{ "revoked": true } means a matching grant was deleted. { "revoked": false }
means there was nothing to revoke. If several hosts granted the same email,
pass hostUserId to pick one.
Archiving a host already deletes the badges they granted. You can still name
that host on revoke (it will not 404); the result is typically revoked: false.