Roadmap spaces
A Roadmap space is a voting board: members suggest items, readers vote, and the board arranges the items by status. This guide covers everything a board can look like and do: its looks and how to mix them, the pages around the board (tags, statuses, the submit page, feeds, the widget), one item's own overrides, the theme-component outlets, and the behaviour settings with their defaults. The basics of lanes, voting and anonymous votes are summarised in Roadmap and Status spaces.
Everything under theme.roadmap lives in the space theme you already set with PUT or PATCH /orgs/{orgId}/spaces/{spaceId}/theme. Every key is optional, and like every theme object it is strict: a misspelt key is a 422 that names it, never a silent default.
Layers: theme, space, item
What a reader sees is built in this order, and every key you set wins over the layer under it:
the default layer of the look you picked (never stored);
the site theme, when the board is part of a site;
the space theme (
theme.roadmap);one item's own
customization.theme.roadmap(its page only).
GET …/theme answers with what you stored, never the resolved theme, so you can send it back whole without freezing the defaults into it.
Looks are patches
theme.roadmap.look picks a starting point. A look is not a mode: it is a handful of independent keys laid under your own, so any key you set still wins, and any key a look sets can be set alone under another look.
Look | What it is | The keys it sets |
|---|---|---|
| Panels in the site's reading column | The default layer below |
| The plain board, exactly as it drew before the type had a look | Nothing: no layer at all. Note that |
| GitHub's or Linear's project board: every lane side by side, scrolling sideways |
|
| Canny's quiet list of requests |
|
| Productboard's portal: a hero over the board |
|
The default layer (what default is, and what every other look but paper patches over):
width: column, so the board's title lines up with every other page on the site;lanes:style: panel,glyph: dot,overflow: fit,empty: collapse,countStyle: pill,phone: tabs, and tones (Submitted and Declined neutral, Planned info, In progress warning, Shipped success);card:meta: [comments, target],progress: bar,cover: top;vote:style: pill,glyph: chevron,position: start;header:subtitlePlacement: under-title,subscribe: true;submit:sections: [problem, proposal],rich,similar,tagsandthemeall on;filters:sort: [top, new, trending],tags: true,mine: true;item: a side rail (vote,voters,follow,facts,share,actions),voters: stack, andactivity,response,shippedIn,commentSortControl,reactions,replies,staffBadgeandmergedRequestson, withmerged: redirect.
Each of those is one key, so an owner who wants one of them back sets that key alone.
Combinations no look gives you
The minimal list with the portal's hero over it:
curl -X PATCH "https://forumulate.com/api/orgs/$ORG/spaces/$SPACE/theme" \
-H "Authorization: Bearer $FORUMULATE_TOKEN" -H 'content-type: application/json' \
-d '{ "roadmap": {
"look": "minimal",
"header": { "layout": "hero", "hero": { "eyebrow": "Product roadmap", "align": "center" } }
} }'The kanban board in the reading column, with votes counted but not shown:
{ "roadmap": { "look": "kanban", "width": "column", "lanes": { "overflow": "fit" }, "vote": { "count": "hide" } } }The portal look on dark cards, numbered like issues:
{
"roadmap": {
"look": "portal",
"card": { "eyebrow": "number", "numberPrefix": "RFC" },
"colors": {
"card": { "color": "#111827", "colorDark": "#0b0f19" },
"cardTitle": { "color": "#f9fafb" }
}
}
}Presets: board, list, timeline
The preset is the board's arrangement, set with PUT /orgs/{orgId}/spaces/{spaceId}/preset ({"preset": "timeline"}) or in the studio's Look fold.
Preset | What it draws |
|---|---|
| Columns by status, cards within them |
| One column grouped by status, read top to bottom. Best for long boards |
| Items along their horizons (Now, Next, Later, or Q1, Q2 …), left to right: when, not what state. Its rail and dots take |
A timeline reads best on a board whose lanes are horizons: set groupBy: "target" and horizons on the settings door (below).
The board keys
lanes
Key | Default | What it does |
|---|---|---|
|
|
|
| off | A hairline under each lane's head |
| Space between lanes, 0–48 px | |
| A lane's narrowest width, 160–480 px ( | |
|
|
|
|
| An empty lane is |
| "Nothing here yet" | What an empty lane says, in your words |
|
|
|
|
| Under 768px: |
|
| Every lane's mark: |
| see above | Each stock state's colour: |
| Each stock state's own |
A status the board added carries its colour, mark and description on the status itself (the settings door's statuses), because a theme cannot know a key a board invented.
card
Key | Default | What it does |
|---|---|---|
| The shared card surface (surface, radius, padding, shadow) | |
|
| |
| none | The line above the title: |
|
| The footer, in order: |
| Up to 6 of the space's own public fields by key, after | |
| never clipped | 1–4 |
| 2 | 0–4; 0 hides it |
|
| The item's |
|
| The item's cover across the card; |
| "roadmap" → "roadmap #24" | |
| none | How a pinned item says so: |
vote
Key | Default | What it does |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
| What a cast vote fills with: |
|
|
|
| off | "3 votes left" beside the control, on a board with a vote budget |
header, filters and colors
Key | Default | What it does |
|---|---|---|
|
|
|
|
| |
| the stock line | The line under the title. It is also the board's meta description and its feeds' description |
|
|
|
| on | A Subscribe control beside the title: the board's moves by email, its feed, and Follow for members |
|
| The sort row: |
|
| The order the board opens in. |
| tags and mine on | Rows of tags, of lanes, and "My votes" |
|
|
|
|
|
|
| One colour per element: |
Filtering is done on the server through the address (?sort=&tag=&status=&mine=1&q=), so a filtered board is a link a reader can share.
submit
The public "suggest" form. sections names the shape's slots it asks for, in order (problem, proposal; a key the shape does not have is skipped); rich offers the rich editor behind a "Formatting" switch; similar lists requests that look like the one being typed, so the duplicate gets a vote instead of a twin; tags and theme let the author pick from the board's own.
The item page
theme.roadmap.item shapes one item's page.
Key | Default | What it does |
|---|---|---|
| side rail |
|
| every allowed one |
|
|
|
|
| on | The item's history: every lane it moved through, and when |
| on | The team's latest answer in a panel under the title |
| on | "Shipped in v2.4" for an item a published changelog release cites |
|
| The comment order, and a Newest/Oldest switch |
| on | Reactions, one-level replies, a "Team" chip on staff comments |
|
| A merged request either sends its address on to the survivor (308) or keeps its page with a "Merged into" |
| on | The survivor lists what was merged into it, with their votes |
|
|
|
|
|
|
|
| The byline: |
|
|
|
|
|
|
| on | The "Back to roadmap" link |
| off | The item's tags as chips, each linking to its tag page |
| none |
|
|
| Where the languages row sits: |
|
| |
| all off | What a printed item keeps beyond its head and body: |
|
|
One item's own overrides
A moderator can give one item its own look: anything a piece may carry (CSS, token keys, a share image, og title and description, JSON-LD) plus theme.roadmap, which a roadmap item's page reads over the space's. Send it under customization on POST …/roadmap or PATCH …/roadmap/{topicId}; keys merge and null clears. It needs forum.moderate (a 403 naming the key from anyone else). Another type's namespace (theme.post, theme.faq, …) is refused with a 422 that names it, because no roadmap page would draw it.
curl -X PATCH "https://forumulate.com/api/orgs/$ORG/spaces/$SPACE/roadmap/$TOPIC" \
-H "Authorization: Bearer $FORUMULATE_TOKEN" -H 'content-type: application/json' \
-d '{ "customization": { "theme": { "roadmap": {
"item": { "cover": "banner", "titleSize": "xl", "rail": { "layout": "stacked" } }
} } } }'In the studio it is Page look & sharing on the item. The general rules are in Theme your site → Per-page customization.
Pages around the board
Address (under the board's mount) | What it is |
|---|---|
| An item. |
| The submit form on its own page, the address to link a "Request a feature" menu item to |
| Every tag with its count, and every request with one tag |
| Every lane with its count, and every request in one lane. The slug is the status key in lower case with |
| The reader's own activity on the board |
| The board's feeds |
| The feedback widget (below) |
tag, status and new are therefore reserved: no item can take those slugs. The hub pages and every public lane are in the sitemap, and an item with published translations is served at /<lang>/<slug> with hreflang naming each language (see Translations everywhere). Any board or item address with ?embed=1 renders bare, for an iframe.
Feeds
theme.roadmap.feed sets the feeds' words: title (unset: the board's name), description (unset: header.subtitle, then the name) and statusPrefix ("[Planned] …" before each entry, on). Channel text is in the board's language, with <language> set.
The feedback widget
A floating "Feedback" launcher a customer puts in their own product. It lists the most-wanted requests, what shipped lately, or both, and a "Suggest an idea" link to /new:
<script src="https://acme.com/roadmap/widget.js" async></script>Its defaults come from theme.roadmap.widget:
Key | Default | What it does |
|---|---|---|
|
|
|
|
|
|
| 5 | Items listed, 1–10 |
| "Feedback" | The launcher's words |
| A tone with a dark twin | |
| 12 | 0–24 px |
| on | A count of what shipped since the reader last opened it |
| on | "Suggest an idea" in the panel |
|
|
|
The script tag can override any of them per page with data-position, data-show, data-accent, data-scheme, data-locale and data-label; data-trigger="#my-button" opens the panel from your own button instead of drawing a launcher.
Outlets
Theme components (Theme components) can be placed in these roadmap outlets:
Outlet | Page | Context | What it is |
|---|---|---|---|
| board | Above the board | |
| board | Below the board | |
| board (repeats) |
| Under the heading of every lane |
| board (repeats) |
| The foot of every card |
| item |
| Between the title and facts and the description |
| item | same | Under the vote and status card |
| item | same | After the description, before the discussion |
None of them wraps reader content: each adds beside it.
Behaviour settings
Board behaviour lives on GET/PUT /orgs/{orgId}/spaces/{spaceId}/roadmap-settings. Every field resolves the same way: this board's value, then the organization's default where one exists, then today's behaviour.
Field | Default | What it does |
|---|---|---|
| off (org default | Logged-out readers may vote. See how an anonymous vote is counted |
| the stock words (org default | This board's words for the five stock lanes |
| none | Up to 10 lanes of your own: |
| stock order | The order lanes render in. An ordering, not a filter: lanes left out are appended |
| none | Lanes not drawn. Their items 404 to readers unless the lane is also in |
| none | Hidden lanes whose items still open by their own link |
| none | Lanes whose items take no more votes |
|
| What a lane is: |
| free text | Up to 12 horizons in order ("Now", "Next", "Later"), written as the |
|
|
|
| 0 (unlimited) | How many items one voter may back at once, 0–100 |
| equal | Five numbers, one per trust level 0–4, each 0–10. Anonymous votes always count one |
| off | Members may vote against an item. Never anonymous readers: an anonymous vote is demand, not a veto |
| off | Hold every public submission, signed in or not, for review |
Who may post is a community setting, on PATCH …/forum/settings (whoCanPost), with the organization default community.who_can_post. SHIPPED is reserved: a release that ships an item moves it there, whatever the lane is called.
curl -X PUT "https://forumulate.com/api/orgs/$ORG/spaces/$SPACE/roadmap-settings" \
-H "Authorization: Bearer $FORUMULATE_TOKEN" -H 'content-type: application/json' \
-d '{ "groupBy": "target", "horizons": ["Now", "Next", "Later"],
"statuses": [{ "key": "UNDER_REVIEW", "label": "Under review", "tone": { "tone": "info" }, "glyph": "ring" }],
"closedStatuses": ["SHIPPED", "DECLINED"], "voteBudget": 10 }'The team's priority order
filters.defaultSort: "manual" (or ?sort=manual) orders each lane the way your team placed it, with anything never placed following by votes. Set a lane's order with PUT /orgs/{orgId}/spaces/{spaceId}/roadmap/lanes/{status}/order and {"ids": [...]} (needs forum.moderate), or move cards up and down on the studio's board.
Front-door switches
On PUT …/preset under frontDoor: showVotes, showLaneCounts and showEmptyLanes (all on), badgeStyle (the lane heads and status chip, pill by default), and subscribeStyle (menu).
In the studio
Look fold: the preset, the Board look picker, the front-door switches, and every
theme.roadmapkey, which also opens by double-clicking its part on the page.Pages fold → Board: the items, their moves between lanes, and their order within a lane.
Settings fold → Lanes and voting: lane names, your own statuses with their colours and marks, hidden, public and closed lanes, grouping and horizons, vote mode, budget, weights, downvotes and review.
Settings fold → Network access: the IP allow-list (below).
An item → Page look & sharing: its own overrides.
Restricting a board to your network
settings.networkAccess.ipAllowList limits every public read of the board (pages, feeds, markdown, JSON and the widget) to a list of IP addresses and CIDR blocks; readers elsewhere see "Not available from this network". An empty list means everyone. See Network allow-list.
Importing from Canny or Featurebase
POST /orgs/{orgId}/imports/roadmap with {"source": "canny" | "featurebase", "data": …} turns an export (CSV text or JSON) into a board: statuses mapped onto the five lanes, ETA as target, category as theme, named voters as votes and the rest as anonymous votes. It is re-runnable by slug. Details in Importers.
Templates
Six official roadmap templates start a board with a look and sample items: Lanyard (bordered lane panels, square vote box), Fernway (four open columns with marks and descriptions), Gridlane (a dense sideways-scrolling project board), Horizon (Now / Next / Later), Slate (a dark, dense list) and Milepost (a timeline in the team's own priority order, minimal look, pin marks). Each is only keys and settings, so every one of them can be changed afterwards like any board.
What you need to set up
Nothing on a roadmap needs an account or a credential. A few parts stay empty until their data exists:
"Shipped in" appears only once a published changelog release cites the item.
Cover and progress on cards draw only for items with
coverUrlorprogressset.The vote budget chip (
vote.budget) shows only on a board with avoteBudget.Item languages appear only once the item has a published translation in one of the space's languages.
Network access is open to everyone until you add an address.
In the API
Every operation below is also reachable from the other surfaces without a dedicated command. forumulate api <Operation> calls it from the CLI, the JavaScript SDK has a typed method for each one (the last column names it; the Python and Go clients are generated from the same spec), and an agent reaches the organization-scoped ones through the MCP call_api tool. Where a CLI command or MCP tool exists too, the last column names it. Operation names link to the API reference.
Roadmap
Operation | Request | What it does | Shortcuts |
|---|---|---|---|
| Replace the order in a space |
| |
| Get the roadmap in a space |
| |
| Create the roadmap in a space |
| |
| Get the roadmap |
| |
| Update the roadmap |
| |
| Create the vote in a space (roadmap) |
| |
| Create a comment in a space (roadmap) |
| |
| List proxy votes in a space |
| |
| Create a proxy vote in a space |
| |
| Delete the proxy vote |
| |
| Merge the roadmap |
| |
| Create the status in a space (roadmap) |
|