API Versioning
The Roam API is versioned by date so we can evolve response and webhook payload shapes over time without breaking existing integrations. Your integration is pinned to a single version and never changes shape underneath you — you adopt new versions deliberately, when you're ready.
This page explains how versions work and what you need to do. If you're moving from the v0 Alpha API, start with the Migration Guide: v0 to v1 first — that's a one-time, larger jump. This page is about the ongoing, incremental versions within v1.
How versions are named
Versions are dates, in YYYY-MM-DD form. The current version is:
2026-08-20
/v1 in the base URL (https://api.ro.am/v1) is the API generation — a stable namespace that
won't churn. The dated version is the revision within it that controls the exact shape of
responses and webhook payloads. We will not mint a /v2 URL for routine shape changes; those ship
as new dated versions.
v0 is the previous generation (
https://api.ro.am/v0). It is frozen and not part of the dated-version scheme. See the Migration Guide.
Your integration's version
Every integration (API key, OAuth app, or Personal Access Token) has a default version, set once when the integration is created and pinned there:
- New integrations are created on the latest version available at that time.
- Existing integrations stay on the version they were created with.
- Your version never advances automatically. A new Roam API version shipping does not change your integration's behavior. You upgrade when you choose to.
This is the key guarantee: code written against the version you're on keeps working, byte-for-byte, until you decide to move.
You can confirm which version a response was rendered with — every API response includes a header matching the version that shaped the body. For a client on the current default:
Roam-Version: 2026-08-20
(Older integrations still pinned to earlier versions receive those pins — for example
Roam-Version: 2026-07-23 or the baseline 2026-06-01 — and the corresponding shapes.)
Overriding the version per request
To try a different version for a single request without changing your default, send the
Roam-Version request header. Example — force the baseline shape while your client default is
newer:
curl https://api.ro.am/v1/chat.history?chatId=88bebce7-6cbb-4666-96f9-5c02d73e6661 \
-H "Authorization: Bearer $ROAM_TOKEN" \
-H "Roam-Version: 2026-06-01"
Or target the current version explicitly:
curl https://api.ro.am/v1/chat.history?chatId=88bebce7-6cbb-4666-96f9-5c02d73e6661 \
-H "Authorization: Bearer $ROAM_TOKEN" \
-H "Roam-Version: 2026-08-20"
Resolution order for a REST request:
- The
Roam-Versionrequest header, if present. - Otherwise, your integration's pinned default version.
- If neither is set (pre-versioning clients), the baseline version
2026-06-01.
Sending an unsupported version returns 400 with the list of supported versions.
Most integrations never send the header — they rely on their pinned default. Use the header to test a different version before adopting it.
Webhook versions
Webhooks are versioned too, but because Roam initiates the delivery there is no request to carry a header. Instead, the version is fixed on the subscription:
- When you create a subscription with
webhook.subscribe, it captures your integration's default version (or an explicitapiVersionyou pass in the request body), and that subscription delivers that shape from then on. - Each delivery includes the
Roam-Versionheader — and, from version2026-07-07onward, the envelope'sapiVersionfield — so your handler can confirm the shape it's receiving.
To move a subscription to a newer payload shape, create a new subscription on the new version (optionally alongside the old one) and retire the old one once you've cut over.
What changes between versions — and what doesn't
We make backward-compatible (additive) changes at any time, on every version, without a new version number. Write your integration to tolerate them. Specifically, you should expect and safely ignore:
- New fields in responses and webhook payloads.
- New endpoints and new webhook event types.
- New optional request parameters.
- New values in existing enum-style fields.
Build defensively: ignore unknown fields, and don't assume an enum will only ever return the values you've seen. An integration that rejects unexpected fields or values will break on a non-breaking change.
A new dated version is only introduced for backward-incompatible changes, such as:
- Removing or renaming a field.
- Changing a field's type or structure (for example, wrapping a payload in an envelope).
- Changing a default behavior.
Because these only land in a new version, and your integration is pinned, they never reach you until you opt in.
Version history
| Version | Highlights |
|---|---|
2026-08-20 (current default) | Chat membership for v1 push and most REST: organization apps hear a group only if they are a member; personal tokens ride the owner's membership (every message in those chats, not mention-only). {mention:true} restores mention-only. Organization chat.post and chat.startStream to a public group without joining remain allowed. Organization chat.search includes unjoined public groups in the bot's roam. New API keys, OAuth apps, and PATs pin here. |
2026-08-07 | Slack mention grammar in message text on reads: groups render as <!subteam^uuid> (previously <@uuid>) and the broadcast as <!channel> (previously <@all>). Principals stay <@uuid>. The mentions list is unchanged. |
2026-07-23 | Same delivery shapes as 2026-07-07. |
2026-07-07 | Common webhook event envelope: type, eventId, timestamp, apiVersion, data. Route on type; business fields live under data. |
2026-06-01 (baseline) | First dated v1 pin. Webhook payloads are bare (no envelope). Pre-versioning clients that send no pin resolve here. |
Subscriptions pinned to 2026-06-01 keep bare payload shapes byte-for-byte. Subscriptions on
2026-07-07 or newer receive the envelope. Moving a 2026-07-07 client to 2026-07-23 requires
no code changes. Moving to 2026-08-07 changes only how mention tokens render in message text
on reads (chat.history, chat.search, chat.link.resolve, and the chat.message
webhook). Moving to 2026-08-20 applies membership to v1 chat push and most REST
(organization chat.post / chat.startStream to public groups stay allowed
without joining; organization chat.search includes unjoined public groups).
Writes are not versioned:
every version accepts both mention grammars (plus Slack-style |label suffixes and the
legacy <@all> broadcast alias) on chat.post and chat.update.
Additive changes (all v1 pins, no new date): principal hydration / type fields, optional
sender display overrides on message reads, and similar. Strict JSON decoders must ignore unknown
properties. See Identity & Principals and
Sender Profiles.
The v0 → v1 generation jump (IDs, endpoint renames, event names) is separate from dated pins — use the Migration Guide.
Adopting a new version
- Review the version history (and migration notes for the target pin).
- Test against it using the
Roam-Versionheader (REST) or a secondwebhook.subscribeon the new version (webhooks), without touching production. - Update your code to the new shapes.
- Update your integration's pinned default to the new version, and migrate any webhook subscriptions.
There's no rush — see the support window below.
Deprecation policy
- Each version is supported for at least 12 months after a newer version is released.
- As a version approaches end of life, REST responses include
DeprecationandSunsetheaders with the shutdown date. - After a version is sunset, REST requests pinned to it return
410 Gone. We will contact you well before this happens; no version is retired while integrations are still using it.
Best practices
- Pin explicitly in code you care about. Relying on your account default is fine, but sending
Roam-Versionmakes the shape your integration expects unambiguous and self-documenting. - Tolerate additive changes. Ignore unknown fields and unrecognized enum values rather than failing.
- Check the delivery header on webhooks. Use
Roam-Versionto route payloads if you ever run more than one version. - Treat cursors and webhook timestamps as opaque. Pagination cursors are server-issued tokens —
pass
nextCursorback ascursorunchanged. Invalid cursors returnerror: "invalid_cursor". See Responses and Errors. - Version pin is stamped at client creation. New API keys, OAuth apps, and PATs receive the
latest published version at registration time (currently
2026-08-20). The pin does not change when you redeploy or when Roam ships a newer version.
Questions?
Contact us via Roam Support Chat or email developer@ro.am.