Set a user's external activity
POST/user.activity.set
Paint a badge (and optional glow) on a user's seat for work happening
outside Roam — a phone call, a browser meeting, a CRM session. Pass
dnd: true to also put their assigned office in Do Not Disturb.
The integration owns the lifecycle: set when the session starts,
clear when it ends. Re-posting the same externalId is the heartbeat
for long-running sessions — it refreshes expiresAt and, unless you
send startedAt, keeps the original start time. Roam stamps expiry
itself (default 10 minutes, maximum 60) so a dropped "ended" webhook
cannot leave a permanent glow.
externalId is unique per (integration, user). Two apps can hold
activities on the same person at once; you can only update or clear
your own rows.
See External activity for display, DND, TTL, stacking, and where the indicator appears on the map.
Access: Organization and Personal. Organization tokens may target any user in the workspace. Personal tokens (OAuth or PAT) may target only the token owner.
Required scope: user:write.activity. Personal Access Tokens skip
this check; personal-mode OAuth installs must still request the scope.
OpenAPI Spec: chat-v1.json
Request
Responses
- 200
- 400
- 401
- 403
- 404
- 405
- 500
Activity saved. Body is the live item (same shape .list returns
per entry), including the server-stamped startedAt / expiresAt.
Bad request. Common causes:
- Missing
userId,externalId,display.emoji, ordisplay.title externalIdlonger than 128 code points, or display fields over their capsdisplay.colornot in the curated palettettlSecondsandexpiresAtboth sent (invalid_arguments)ttlSecondsnot positive, orexpiresAtin the past
Presented invalid authentication credentials.
Forbidden. Common causes:
- Missing
user:write.activity(OAuth / API key) - Personal token targeting a user other than the owner (
access_denied)
User not found, or not in this workspace (user_not_found).
An unsupported method was requested.
An internal error occurred.