Get the roadmap in a space
GET
https://forumulate.com/api /orgs/{orgId}/spaces/{spaceId}/roadmap Requires token scope: read (the coarse method gate) for Atlas key (ak_), Personal Access Token (cft_) or OAuth (cfo_) auth — in addition to any catalog scope (GET /pats/scopes) the route’s capability needs. Session/cookie auth is governed by RBAC capabilities instead.
Parameters
orgIdstringpathrequiredspaceIdstringpathrequiredlimitintegerqueryItems per LANE — not lanes. The lanes are the status enum this board shows, so there is no page two of them;
cursor goes one page deeper in every lane at once. Defaults to 100. 100 is the most this endpoint serves — a larger value is capped, not refused. A value that is not a whole number of 1 or more is a 422, never a silent default.cursorstringquerypageintegerqueryWhich page of results to return, 1-based. Out-of-range pages return an empty list.
forumulate-versionstringheaderAPI version negotiation. Send
forumulate-version: 2026-12-01 on every request from a new integration; it is optional only so that integrations written before versioning keep working. Each version includes everything before it:Code samples
cURL
curl -X GET "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/roadmap?limit=&cursor=&page=" \
-H "forumulate-version: <value>"TypeScript
const res = await fetch('https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/roadmap?limit=&cursor=&page=', {
method: 'GET',
headers: {
'forumulate-version': '<value>',
},
});
const data = await res.json();Python
import requests
res = requests.request(
"GET",
"https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/roadmap?limit=&cursor=&page=",
headers={
"forumulate-version": "<value>",
},
)
data = res.json()Go
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/roadmap?limit=&cursor=&page=", nil)
req.Header.Set("forumulate-version", "<value>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/roadmap?limit=&cursor=&page=');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['forumulate-version: <value>']);
$response = curl_exec($ch);
curl_close($ch);
echo $response;Ruby
require 'net/http'
require 'uri'
uri = URI('https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/roadmap?limit=&cursor=&page=')
req = Net::HTTP::Get.new(uri)
req['forumulate-version'] = '<value>'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts res.bodyJava
import java.net.URI;
import java.net.http.*;
import java.net.http.HttpRequest.BodyPublishers;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/roadmap?limit=&cursor=&page="))
.header("forumulate-version", "<value>")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());Responses
200 Success.
Example
{
"lanes": [
{
"items": [
null
],
"status": null
}
]
}Option 1
lanesobject[]requiredShow child parameters
itemsArticleSummary[]requiredShow child parameters
answerCountnumberanswerPostIdstringrequiredauthorAvatarSeedstringauthorAvatarUrlstringauthorIdstringrequiredauthorKindstringauthorNamestringrequiredauthorPointsnumberauthorTitlestringauthorUsernamestringbookmarkedbooleanbylineBylinerequiredbylinesBylineView[]categoryIdstringrequiredcommentsEnabledbooleanrequiredcoverUrlstringrequiredcustomizationPieceCustomizationrequireddeletedAtstringexcerptstringrequiredexpiresAtstringfeaturedbooleanrequiredfeaturedLinkstringrequiredfirstImageUrlstringfurtherReadingobject[]requiredidstringrequiredisNewbooleankindstringrequiredlastActivityAtstringrequiredlastPostedAtstringlastPosterNamestringlikeCountnumberlistedbooleanrequiredmergedIntoIdstringrequirednumbernumberrequiredonThisPagestringrequiredpinnedbooleanrequiredpinnedGloballybooleanrequiredpinnedUntilstringrequiredpostersForumPoster[]promotedPageIdstringrequiredpublishedAtstringrequiredreadingMinutesnumberrequiredreleaseVersionstringrequiredreplyCountnumberrequiredreplyPreviewsReplyPreview[]reviewobjectroadmapStatusstringrequiredscheduledForstringrequiredseriesstringrequiredshippedTopicIdsstring[]requiredslugstringrequiredstatestringrequiredstatusstringrequiredsubtitlestringtagInfoTagDisplay[]tagsstring[]requiredtitlestringrequiredunreadnumberupdatedAtstringrequiredviewCountnumberrequiredvoteCountnumberrequiredstatusstringrequired{
"lanes": [
{
"items": [
{
"answerCount": null,
"answerPostId": null,
"authorAvatarSeed": null,
"authorAvatarUrl": null,
"authorId": null,
"authorKind": null,
"authorName": null,
"authorPoints": null,
"authorTitle": null,
"authorUsername": null,
"bookmarked": null,
"byline": null,
"bylines": null,
"categoryId": null,
"commentsEnabled": null,
"coverUrl": null,
"customization": null,
"deletedAt": null,
"excerpt": null,
"expiresAt": null,
"featured": null,
"featuredLink": null,
"firstImageUrl": null,
"furtherReading": null,
"id": null,
"isNew": null,
"kind": null,
"lastActivityAt": null,
"lastPostedAt": null,
"lastPosterName": null,
"likeCount": null,
"listed": null,
"mergedIntoId": null,
"number": null,
"onThisPage": null,
"pinned": null,
"pinnedGlobally": null,
"pinnedUntil": null,
"posters": null,
"promotedPageId": null,
"publishedAt": null,
"readingMinutes": null,
"releaseVersion": null,
"replyCount": null,
"replyPreviews": null,
"review": null,
"roadmapStatus": null,
"scheduledFor": null,
"series": null,
"shippedTopicIds": null,
"slug": null,
"state": null,
"status": null,
"subtitle": null,
"tagInfo": null,
"tags": null,
"title": null,
"unread": null,
"updatedAt": null,
"viewCount": null,
"voteCount": null
}
],
"status": "SUBMITTED"
}
]
}Option 2
lanesobject[]requiredShow child parameters
itemsArticleSummary[]requiredShow child parameters
answerCountnumberanswerPostIdstringrequiredauthorAvatarSeedstringauthorAvatarUrlstringauthorIdstringrequiredauthorKindstringauthorNamestringrequiredauthorPointsnumberauthorTitlestringauthorUsernamestringbookmarkedbooleanbylineBylinerequiredbylinesBylineView[]categoryIdstringrequiredcommentsEnabledbooleanrequiredcoverUrlstringrequiredcustomizationPieceCustomizationrequireddeletedAtstringexcerptstringrequiredexpiresAtstringfeaturedbooleanrequiredfeaturedLinkstringrequiredfirstImageUrlstringfurtherReadingobject[]requiredidstringrequiredisNewbooleankindstringrequiredlastActivityAtstringrequiredlastPostedAtstringlastPosterNamestringlikeCountnumberlistedbooleanrequiredmergedIntoIdstringrequirednumbernumberrequiredonThisPagestringrequiredpinnedbooleanrequiredpinnedGloballybooleanrequiredpinnedUntilstringrequiredpostersForumPoster[]promotedPageIdstringrequiredpublishedAtstringrequiredreadingMinutesnumberrequiredreleaseVersionstringrequiredreplyCountnumberrequiredreplyPreviewsReplyPreview[]reviewobjectroadmapStatusstringrequiredscheduledForstringrequiredseriesstringrequiredshippedTopicIdsstring[]requiredslugstringrequiredstatestringrequiredstatusstringrequiredsubtitlestringtagInfoTagDisplay[]tagsstring[]requiredtitlestringrequiredunreadnumberupdatedAtstringrequiredviewCountnumberrequiredvoteCountnumberrequiredstatusstringrequiredpageobjectrequiredThe paging envelope a collection carries when the caller states
Forumulate-Version. Each operation’s own response schema says whether it has one: a collection either carries page, or answers both this and its pre-envelope shape and picks by the header. No listing pages with keys of its own any more — the allowlists in openapi-collection-shape.test.ts are empty, which is what stops a new one from appearing. Read hasMore and nextCursor: the snake_case pair beside them is deprecated and is not sent to a caller who states 2026-11-01 or later.Show child parameters
limitintegerrequiredThe limit this page was built with — what was asked for, capped. NOT the number of rows returned: a final page under the limit is normal, and
hasMore is the only thing that says whether to keep walking.hasMorebooleanrequiredWhether another page follows this one.
nextCursorstringrequiredPass back as
cursor to continue. Null on the last page.has_morebooleandeprecatedThe same value as
hasMore. These two are the only snake_case keys in the API. Sent to callers who state 2026-09-01 or no version at all; ABSENT from 2026-11-01 onwards. Read hasMore instead — it is sent on every version.next_cursorstringdeprecatedThe same value as
nextCursor. Absent from 2026-11-01 onwards; read nextCursor.totalintegerRows in the whole collection — the size of the set, not of this page, and not of what you have seen so far. ABSENT where the source cannot count the collection: the append-only logs (staff actions, automation runs, connector activity, ingested questions, chat history) grow without bound and are not counted on every page view. Walk on
hasMore, which is exact on every answer; read total only to show a size, and handle its absence.dataobject[]requiredThe same rows as the key named after them (
topics, articles, pages, monitors, …), under a key that is the same on every paged list — so one parser reads every collection. The SAME array, not a different selection: read either. Present whenever page is, i.e. when you state Forumulate-Version (or send a cursor); the unversioned shape does not carry it.Show child parameters
itemsArticleSummary[]requiredShow child parameters
answerCountnumberanswerPostIdstringrequiredauthorAvatarSeedstringauthorAvatarUrlstringauthorIdstringrequiredauthorKindstringauthorNamestringrequiredauthorPointsnumberauthorTitlestringauthorUsernamestringbookmarkedbooleanbylineBylinerequiredbylinesBylineView[]categoryIdstringrequiredcommentsEnabledbooleanrequiredcoverUrlstringrequiredcustomizationPieceCustomizationrequireddeletedAtstringexcerptstringrequiredexpiresAtstringfeaturedbooleanrequiredfeaturedLinkstringrequiredfirstImageUrlstringfurtherReadingobject[]requiredidstringrequiredisNewbooleankindstringrequiredlastActivityAtstringrequiredlastPostedAtstringlastPosterNamestringlikeCountnumberlistedbooleanrequiredmergedIntoIdstringrequirednumbernumberrequiredonThisPagestringrequiredpinnedbooleanrequiredpinnedGloballybooleanrequiredpinnedUntilstringrequiredpostersForumPoster[]promotedPageIdstringrequiredpublishedAtstringrequiredreadingMinutesnumberrequiredreleaseVersionstringrequiredreplyCountnumberrequiredreplyPreviewsReplyPreview[]reviewobjectroadmapStatusstringrequiredscheduledForstringrequiredseriesstringrequiredshippedTopicIdsstring[]requiredslugstringrequiredstatestringrequiredstatusstringrequiredsubtitlestringtagInfoTagDisplay[]tagsstring[]requiredtitlestringrequiredunreadnumberupdatedAtstringrequiredviewCountnumberrequiredvoteCountnumberrequiredstatusstringrequired{
"lanes": [
{
"items": [
{
"answerCount": null,
"answerPostId": null,
"authorAvatarSeed": null,
"authorAvatarUrl": null,
"authorId": null,
"authorKind": null,
"authorName": null,
"authorPoints": null,
"authorTitle": null,
"authorUsername": null,
"bookmarked": null,
"byline": null,
"bylines": null,
"categoryId": null,
"commentsEnabled": null,
"coverUrl": null,
"customization": null,
"deletedAt": null,
"excerpt": null,
"expiresAt": null,
"featured": null,
"featuredLink": null,
"firstImageUrl": null,
"furtherReading": null,
"id": null,
"isNew": null,
"kind": null,
"lastActivityAt": null,
"lastPostedAt": null,
"lastPosterName": null,
"likeCount": null,
"listed": null,
"mergedIntoId": null,
"number": null,
"onThisPage": null,
"pinned": null,
"pinnedGlobally": null,
"pinnedUntil": null,
"posters": null,
"promotedPageId": null,
"publishedAt": null,
"readingMinutes": null,
"releaseVersion": null,
"replyCount": null,
"replyPreviews": null,
"review": null,
"roadmapStatus": null,
"scheduledFor": null,
"series": null,
"shippedTopicIds": null,
"slug": null,
"state": null,
"status": null,
"subtitle": null,
"tagInfo": null,
"tags": null,
"title": null,
"unread": null,
"updatedAt": null,
"viewCount": null,
"voteCount": null
}
],
"status": "SUBMITTED"
}
],
"page": {
"limit": 0,
"hasMore": true,
"nextCursor": "string",
"has_more": true,
"next_cursor": "string",
"total": 0
},
"data": [
{
"items": [
{
"answerCount": null,
"answerPostId": null,
"authorAvatarSeed": null,
"authorAvatarUrl": null,
"authorId": null,
"authorKind": null,
"authorName": null,
"authorPoints": null,
"authorTitle": null,
"authorUsername": null,
"bookmarked": null,
"byline": null,
"bylines": null,
"categoryId": null,
"commentsEnabled": null,
"coverUrl": null,
"customization": null,
"deletedAt": null,
"excerpt": null,
"expiresAt": null,
"featured": null,
"featuredLink": null,
"firstImageUrl": null,
"furtherReading": null,
"id": null,
"isNew": null,
"kind": null,
"lastActivityAt": null,
"lastPostedAt": null,
"lastPosterName": null,
"likeCount": null,
"listed": null,
"mergedIntoId": null,
"number": null,
"onThisPage": null,
"pinned": null,
"pinnedGlobally": null,
"pinnedUntil": null,
"posters": null,
"promotedPageId": null,
"publishedAt": null,
"readingMinutes": null,
"releaseVersion": null,
"replyCount": null,
"replyPreviews": null,
"review": null,
"roadmapStatus": null,
"scheduledFor": null,
"series": null,
"shippedTopicIds": null,
"slug": null,
"state": null,
"status": null,
"subtitle": null,
"tagInfo": null,
"tags": null,
"title": null,
"unread": null,
"updatedAt": null,
"viewCount": null,
"voteCount": null
}
],
"status": "SUBMITTED"
}
]
}400 The request could not be understood — a malformed header, path or query value (
request.malformed). A value that was understood but is not acceptable is a 422 validation.failed.Example
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}Schema
errorobjectrequired401 No credential, or one that is expired or revoked (
auth.required). Send a Bearer token or the session cookie.{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}403 Authenticated, and not allowed — always
rbac.forbidden, whether what is missing is the capability, the token scope, or a resource the token is pinned away from. The message names the capability and, for a scope refusal, the scopes that would grant it. A refusal because of the PLAN is a 402 with quota.exceeded, not this.{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}404 No such thing — one of the ids in the path does not resolve, or resolves to something this caller may not see (
*.not_found).{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}429 Rate limited — see the RateLimit-* headers.
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}default Error — the stable { error: { code, message } } envelope.
{
"error": {
"code": "string",
"message": "string",
"details": {},
"docs": "string",
"reason": "string",
"slugs": [
"string"
],
"conflict": {
"etag": "string",
"ops": [
null
]
}
},
"requestId": "string"
}The Forumulate teamUpdated