Publish the shared draft

Embed
Preview of the card
<a href="https://forumulate.com/reference/forumulate-api-forumtaxonomy-publishshareddraft"><img src="https://forumulate.com/reference/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/8042f004-e3d9-445f-b7a4-b6c1f86836e6/pages/b8fa845e-7361-4dc8-994f-ea35af0a1919/social-card.svg?v=3e7ae33eec8b" alt="Publish the shared draft" width="600" height="315"></a>
POSThttps://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/shared-drafts/{id}/publish

Requires token scope: write (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
orgIdstringpathrequired
spaceIdstringpathrequired
idstringpathrequired
forumulate-versionstringheader
API 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:
Idempotency-Keystringheader
Makes this write safe to retry. Optional — send any unique string (a UUID is ideal) and the first request runs while its response is remembered under that key for 24 hours; an identical retry replays that same status and body instead of acting twice, so a timeout or a 5xx from the edge can be retried without creating a second row. A retry sent while the first request is still in flight is refused with 409. The key is scoped to the method and path, so the same key on a different endpoint is a different request. Error responses of 5xx are never cached — those retries re-run. A key is bound to the BODY it was first used with: reusing it with a different body is a 409 idempotency.key_reused, not a replay, because replaying would tell you a write landed that never ran. Generate one key per request, never per process or per session.
Code samples
cURL
curl -X POST "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/shared-drafts/{id}/publish" \
  -H "forumulate-version: <value>" \
  -H "Idempotency-Key: <value>"
TypeScript
const res = await fetch('https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/shared-drafts/{id}/publish', {
  method: 'POST',
  headers: {
    'forumulate-version': '<value>',
    'Idempotency-Key': '<value>',
  },
});
const data = await res.json();
Python
import requests

res = requests.request(
    "POST",
    "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/shared-drafts/{id}/publish",
    headers={
    "forumulate-version": "<value>",
    "Idempotency-Key": "<value>",
    },
)
data = res.json()
Go
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	req, _ := http.NewRequest("POST", "https://forumulate.com/api/orgs/{orgId}/spaces/{spaceId}/forum/shared-drafts/{id}/publish", nil)
	req.Header.Set("forumulate-version", "<value>")
	req.Header.Set("Idempotency-Key", "<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}/forum/shared-drafts/{id}/publish');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['forumulate-version: <value>', 'Idempotency-Key: <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}/forum/shared-drafts/{id}/publish')
req = Net::HTTP::Post.new(uri)
req['forumulate-version'] = '<value>'
req['Idempotency-Key'] = '<value>'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
  http.request(req)
end
puts res.body
Java
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}/forum/shared-drafts/{id}/publish"))
    .header("forumulate-version", "<value>")
    .header("Idempotency-Key", "<value>")
    .method("POST", BodyPublishers.noBody())
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Responses
200 Success.
Example
{
  "topic": {
    "answerCount": 0,
    "answerPostId": "string",
    "assignedGroupId": "string",
    "assigneeId": "string",
    "authorAvatarSeed": "string",
    "authorAvatarUrl": "string",
    "authorId": "string",
    "authorKind": "anonymous",
    "authorName": "string",
    "authorPoints": 0,
    "authors": [
      {
        "name": "string",
        "userId": "string"
      }
    ],
    "authorTitle": "string",
    "authorUsername": "string",
    "bookmarked": true,
    "byline": {
      "avatarUrl": "string",
      "name": "string",
      "url": "string"
    },
    "bylines": [
      {
        "author": null,
        "avatarUrl": null,
        "bio": null,
        "handle": "string",
        "name": "string",
        "role": null,
        "url": null,
        "userId": null
      }
    ],
    "categoryId": "string",
    "commentsEnabled": true,
    "contentChangedAt": "2024-01-01T00:00:00Z",
    "coverUrl": "string",
    "customization": {
      "customCss": "string",
      "jsonLd": "string",
      "ogDescription": "string",
      "ogTitle": "string",
      "shareImageUrl": "string",
      "theme": {
        "accentColor": null,
        "bodyFontFamily": null,
        "changelog": null,
        "colorScheme": null,
        "components": null,
        "contentWidth": null,
        "customFontFamily": null,
        "font": null,
        "headingFontFamily": null,
        "layout": null,
        "monoFontFamily": null,
        "motion": null,
        "palette": null,
        "paletteDark": null,
        "post": null,
        "primaryColor": null,
        "typography": null
      },
      "twitterCard": "summary"
    },
    "deletedAt": "2024-01-01T00:00:00Z",
    "excerpt": "string",
    "expiresAt": "2024-01-01T00:00:00Z",
    "featured": true,
    "featuredLink": "string",
    "fields": {},
    "firstImageUrl": "string",
    "furtherReading": [
      {
        "href": "string",
        "label": "string"
      }
    ],
    "id": "string",
    "isNew": true,
    "kind": "ARTICLE",
    "lastActivityAt": "2024-01-01T00:00:00Z",
    "lastPostedAt": "string",
    "lastPosterName": "string",
    "likeCount": 0,
    "linkedTopics": [
      {
        "createdAt": "2024-01-01T00:00:00Z",
        "fromPostNumber": 0,
        "id": "string",
        "slug": "string",
        "title": "string"
      }
    ],
    "listed": true,
    "mergedIntoId": "string",
    "number": 0,
    "onThisPage": "always",
    "op": {
      "actionCode": "string",
      "actionData": {},
      "authorAvatarSeed": "string",
      "authorAvatarUrl": "string",
      "authorBadges": [
        {
          "icon": null,
          "name": null,
          "slug": null
        }
      ],
      "authorBadgeTiers": {
        "bronze": 0,
        "gold": 0,
        "silver": 0
      },
      "authorFlair": {
        "bgColor": null,
        "color": null,
        "icon": null,
        "label": "string"
      },
      "authorId": "string",
      "authorKind": "anonymous",
      "authorName": "string",
      "authorPoints": 0,
      "authorRole": "moderator",
      "authorStatus": {
        "emoji": null,
        "message": null
      },
      "authorTitle": "string",
      "authorTrust": 0,
      "authorUsername": "string",
      "content": {
        "type": "doc",
        "content": [
          {
            "type": "heading",
            "attrs": {
              "level": 1
            },
            "content": [
              {
                "type": "text",
                "text": "Getting started"
              }
            ]
          },
          {
            "type": "paragraph",
            "content": [
              {
                "type": "text",
                "text": "Install the SDK, then create your first page."
              }
            ]
          },
          {
            "type": "codeBlock",
            "attrs": {
              "language": "bash"
            },
            "content": [
              {
                "type": "text",
                "text": "npm i @forumulate/sdk"
              }
            ]
          }
        ]
      },
      "createdAt": "2024-01-01T00:00:00Z",
      "editedAt": "2024-01-01T00:00:00Z",
      "flagCount": 0,
      "id": "string",
      "isOp": true,
      "likeCount": 0,
      "parentAuthorName": "string",
      "parentPostId": "string",
      "parentPostNumber": 0,
      "postNumber": 0,
      "reactions": {},
      "status": "hidden",
      "voteCount": 0,
      "whisper": true,
      "wiki": true
    },
    "pinned": true,
    "pinnedGlobally": true,
    "pinnedUntil": "2024-01-01T00:00:00Z",
    "posters": [
      {
        "avatarSeed": "string",
        "avatarUrl": null,
        "kind": "anonymous",
        "name": "string",
        "role": "frequent",
        "username": null
      }
    ],
    "promotedPage": {
      "id": "string",
      "spaceId": "string",
      "title": "string"
    },
    "promotedPageId": "string",
    "publishedAt": "2024-01-01T00:00:00Z",
    "readingMinutes": 0,
    "releaseVersion": "string",
    "replies": [
      {
        "actionCode": null,
        "actionData": null,
        "authorAvatarSeed": "string",
        "authorAvatarUrl": "string",
        "authorBadges": [
          null
        ],
        "authorBadgeTiers": {
          "bronze": null,
          "gold": null,
          "silver": null
        },
        "authorFlair": {
          "bgColor": null,
          "color": null,
          "icon": null,
          "label": null
        },
        "authorId": null,
        "authorKind": "anonymous",
        "authorName": "string",
        "authorPoints": 0,
        "authorRole": "moderator",
        "authorStatus": {
          "emoji": null,
          "message": null
        },
        "authorTitle": "string",
        "authorTrust": 0,
        "authorUsername": "string",
        "content": {
          "type": "doc",
          "content": [
            {
              "type": "heading",
              "attrs": {
                "level": 1
              },
              "content": [
                {
                  "type": "text",
                  "text": "Getting started"
                }
              ]
            },
            {
              "type": "paragraph",
              "content": [
                {
                  "type": "text",
                  "text": "Install the SDK, then create your first page."
                }
              ]
            },
            {
              "type": "codeBlock",
              "attrs": {
                "language": "bash"
              },
              "content": [
                {
                  "type": "text",
                  "text": "npm i @forumulate/sdk"
                }
              ]
            }
          ]
        },
        "createdAt": "2024-01-01T00:00:00Z",
        "editedAt": null,
        "flagCount": 0,
        "id": "string",
        "isOp": true,
        "likeCount": 0,
        "parentAuthorName": "string",
        "parentPostId": null,
        "parentPostNumber": 0,
        "postNumber": 0,
        "reactions": {},
        "status": "hidden",
        "voteCount": 0,
        "whisper": true,
        "wiki": true
      }
    ],
    "replyCount": 0,
    "replyPreviews": [
      {
        "author": "string",
        "authorAvatar": null,
        "authorSeed": "string",
        "text": "string"
      }
    ],
    "review": {
      "note": "string",
      "requestedAt": "2024-01-01T00:00:00Z",
      "requestedBy": "string",
      "reviewedAt": "2024-01-01T00:00:00Z",
      "reviewedBy": "string",
      "state": "approved"
    },
    "roadmapStatus": "string",
    "scheduledFor": "2024-01-01T00:00:00Z",
    "seo": {
      "noindex": true,
      "seoDescription": "string",
      "seoTitle": "string"
    },
    "series": "string",
    "shippedTopicIds": [
      "string"
    ],
    "slowModeSeconds": 0,
    "slug": "string",
    "state": "ARCHIVED",
    "status": "archived",
    "subtitle": "string",
    "tagInfo": [
      {
        "color": null,
        "colorDark": null,
        "coverUrl": null,
        "description": null,
        "gradient": null,
        "icon": "string",
        "label": "string",
        "pagePalette": null,
        "pageScheme": "dark",
        "slug": "string",
        "textColor": null,
        "textColorDark": null
      }
    ],
    "tags": [
      "string"
    ],
    "title": "string",
    "unread": 0,
    "updatedAt": "2024-01-01T00:00:00Z",
    "viewCount": 0,
    "voteCount": 0
  }
}
Schema
topicobjectrequired
Show child parameters
answerCountnumber
answerPostIdstringrequired
assignedGroupIdstringrequired
assigneeIdstringrequired
authorAvatarSeedstring
authorAvatarUrlstring
authorIdstringrequired
authorKindstring
anonymous | guest | member | persona | service | staged
authorNamestringrequired
authorPointsnumber
authorsobject[]required
Show child parameters
namestringrequired
userIdstringrequired
authorTitlestring
authorUsernamestring
bookmarkedboolean
bylineBylinerequired
Show child parameters
avatarUrlstring
namestring
urlstring
bylinesBylineView[]
Show child parameters
authorstringrequired
avatarUrlstringrequired
biostringrequired
handlestring
namestringrequired
rolestringrequired
urlstringrequired
userIdstringrequired
categoryIdstringrequired
commentsEnabledbooleanrequired
contentChangedAtstring
coverUrlstringrequired
customizationPieceCustomizationrequired
Show child parameters
customCssstring
jsonLdstring
ogDescriptionstring
ogTitlestring
shareImageUrlstring
themeobject
twitterCardstring
summary | summary_large_image
deletedAtstring
excerptstringrequired
expiresAtstring
featuredbooleanrequired
featuredLinkstringrequired
fieldsobjectrequired
firstImageUrlstring
furtherReadingobject[]required
Show child parameters
hrefstringrequired
labelstringrequired
idstringrequired
isNewboolean
kindstringrequired
ARTICLE | DISCUSSION | FEATURE | QUESTION | RELEASE
lastActivityAtstringrequired
lastPostedAtstring
lastPosterNamestring
likeCountnumber
linkedTopicsLinkedTopic[]required
Show child parameters
createdAtstringrequired
fromPostNumbernumberrequired
idstringrequired
slugstringrequired
titlestringrequired
listedbooleanrequired
mergedIntoIdstringrequired
numbernumberrequired
onThisPagestringrequired
always | auto | never
opobjectrequired
Show child parameters
actionCodestringrequired
actionDataobjectrequired
authorAvatarSeedstring
authorAvatarUrlstring
authorBadgesobject[]
authorBadgeTiersobject
authorFlairobject
authorIdstringrequired
authorKindstring
anonymous | guest | member | persona | service | staged
authorNamestringrequired
authorPointsnumber
authorRolestring
moderator | staff
authorStatusobject
authorTitlestring
authorTrustnumberrequired
authorUsernamestring
contentobjectrequired
A page as a block document: TipTap/ProseMirror JSON, the canonical content model shared by the editor, the reader and the Markdown converters. Send this as content when creating a page or on PUT /pages/{pageId}/content. It is the shape GET /pages/{pageId}/markdown round-trips from. Author in Markdown instead by sending body (whole page) or sections (Markdown per named slot) — use exactly ONE of the three. Every block has a Markdown spelling: :::name{attrs} directives for callouts, tabs, cards, steppers, columns and buttons, listed at GET /docs/markdown-dialect.
createdAtstringrequired
editedAtstringrequired
flagCountnumberrequired
idstringrequired
isOpbooleanrequired
likeCountnumber
parentAuthorNamestring
parentPostIdstringrequired
parentPostNumbernumber
postNumbernumberrequired
reactionsobjectrequired
statusstringrequired
hidden | pending | visible
voteCountnumberrequired
whisperbooleanrequired
wikibooleanrequired
pinnedbooleanrequired
pinnedGloballybooleanrequired
pinnedUntilstringrequired
postersForumPoster[]
Show child parameters
avatarSeedstringrequired
avatarUrlstringrequired
kindstringrequired
anonymous | guest | member | persona | service | staged
namestringrequired
rolestringrequired
frequent | latest | op
usernamestringrequired
promotedPageobjectrequired
Show child parameters
idstringrequired
spaceIdstringrequired
titlestringrequired
promotedPageIdstringrequired
publishedAtstringrequired
readingMinutesnumberrequired
releaseVersionstringrequired
repliesPostSummary[]required
Show child parameters
actionCodestringrequired
actionDataobjectrequired
authorAvatarSeedstring
authorAvatarUrlstring
authorBadgesobject[]
authorBadgeTiersobject
authorFlairobject
authorIdstringrequired
authorKindstring
anonymous | guest | member | persona | service | staged
authorNamestringrequired
authorPointsnumber
authorRolestring
moderator | staff
authorStatusobject
authorTitlestring
authorTrustnumberrequired
authorUsernamestring
contentobjectrequired
A page as a block document: TipTap/ProseMirror JSON, the canonical content model shared by the editor, the reader and the Markdown converters. Send this as content when creating a page or on PUT /pages/{pageId}/content. It is the shape GET /pages/{pageId}/markdown round-trips from. Author in Markdown instead by sending body (whole page) or sections (Markdown per named slot) — use exactly ONE of the three. Every block has a Markdown spelling: :::name{attrs} directives for callouts, tabs, cards, steppers, columns and buttons, listed at GET /docs/markdown-dialect.
createdAtstringrequired
editedAtstringrequired
flagCountnumberrequired
idstringrequired
isOpbooleanrequired
likeCountnumber
parentAuthorNamestring
parentPostIdstringrequired
parentPostNumbernumber
postNumbernumberrequired
reactionsobjectrequired
statusstringrequired
hidden | pending | visible
voteCountnumberrequired
whisperbooleanrequired
wikibooleanrequired
replyCountnumberrequired
replyPreviewsReplyPreview[]
Show child parameters
authorstringrequired
authorAvatarstringrequired
authorSeedstringrequired
textstringrequired
reviewobject
Show child parameters
notestringrequired
requestedAtstringrequired
requestedBystringrequired
reviewedAtstringrequired
reviewedBystringrequired
statestringrequired
approved | changes_requested | in_review
roadmapStatusstringrequired
scheduledForstringrequired
seoobjectrequired
Show child parameters
noindexboolean
seoDescriptionstring
seoTitlestring
seriesstringrequired
shippedTopicIdsstring[]required
slowModeSecondsnumber
slugstringrequired
statestringrequired
ARCHIVED | CLOSED | DRAFT | PUBLISHED
statusstringrequired
archived | closed | draft | published
subtitlestring
tagInfoTagDisplay[]
Show child parameters
colorstringrequired
colorDarkstringrequired
coverUrlstringrequired
descriptionstringrequired
gradientarrayrequired
iconstring
labelstringrequired
pagePaletteobjectrequired
pageSchemestringrequired
dark | light
slugstringrequired
textColorstringrequired
textColorDarkstringrequired
tagsstring[]required
titlestringrequired
unreadnumber
updatedAtstringrequired
viewCountnumberrequired
voteCountnumberrequired
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
errorobjectrequired
Show child parameters
codestringrequired
Stable, machine-readable error code, e.g. rbac.forbidden.
401 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