Skip to content

Publish a draft

POST
/categories/{category}/pages/{page}/contents/{pageContent}/publish
curl --request POST \
--url https://flow.work.optidata.cloud/api/categories/993/pages/2927/contents/4508/publish \
--header 'Authorization: Bearer <token>'

Makes the draft {pageContent} the page’s published version: the page’s status becomes published, page_content_id points to this version and last_content_published_at is set. The caller must be able to edit the page.

Publishing also notifies the members of the category, records the people mentioned in the text, and indexes the text for search; semantic search picks it up shortly after. A version can only be published once.

category
required
integer

Id of the category. Read it from GET /categories.

page
required
integer

Id of a page of that category.

pageContent
required
integer

Id of a version of that page — a page’s page_content_id, or the id returned when saving a new draft.

The page, now pointing to the published version.

Media typeapplication/json

A page right after one of its versions is published.

object
id
integer
category_id
integer
parent_id

Id of the page this one is nested under, or null for a top-level page.

integer | null
user_id

Id of the page’s author.

integer
title
string
identifier

Short public identifier of the page.

string
page_content_id

The page’s current version — its published version once it has one.

integer | null
status

published once a version has been published.

string
Allowed values: draft published
last_content_published_at

When a version was last published.

string | null format: date-time
is_cover

true for the category’s Overview page.

boolean
position

Sort position among its siblings.

integer
visibility

The page’s own visibility as stored — null when it inherits the category’s.

string | null
Allowed values: public
display_visibility

A page’s own visibility. inherit follows the category; public shares the page with anyone who has its link, whatever the category’s visibility.

string
Allowed values: inherit public
effective_visibility

Who can see a category. restricted: only the people and groups it is shared with. internal: everyone in the company. public: anyone with the link, including people who are not signed in.

string
Allowed values: restricted internal public
is_public

Whether the page is reachable by anyone with its link.

boolean
type
string
meta

Reserved. Always null for pages created through the API.

object | null
published_at

Not used — read last_content_published_at.

string | null format: date-time
created_at
string format: date-time
updated_at
string format: date-time
deleted_at

Set when the page is in the trash.

string | null format: date-time
category
object
id
required
integer
name
required
string
slug
required

URL-friendly form of the name.

string
description
string | null
visibility
required

Who can see a category. restricted: only the people and groups it is shared with. internal: everyone in the company. public: anyone with the link, including people who are not signed in.

string
Allowed values: restricted internal public
is_public
required

Shortcut for visibility == public.

boolean
identifier

Short public identifier of the category.

string | null
user_id

Id of the user who owns the category, when it has one.

integer | null
group_id

Set when the category mirrors a group: it is shared with the group’s members, and its name and description follow the group’s.

integer | null
cuid

Identifier of the company the category belongs to.

string
created_at
string format: date-time
updated_at
string format: date-time
deleted_at

Set when the category is in the trash.

string | null format: date-time
user

The author of a page.

object
id
integer
uuid
string format: uuid
cuid
string
username
string
email
string format: email
name
string
company_name
string | null
role
string
status
string
avatar_url
string | null
settings

Display preferences of the author.

object | null
remember_token

Internal. Not meaningful to API clients.

string | null
created_at
string format: date-time
updated_at
string format: date-time
deleted_at
string | null format: date-time
permissions
Array<object>

A grant on the page to one user or group.

object
id
integer
page_id
integer
actions

What the member may do with the page.

string
Allowed values: view edit manage
member_type

Kind of member — a user or a group.

string
member_id
integer
member

The member, when loaded.

object
id
integer
name
string
email
string | null
uuid
string | null
guid
string | null
status
string | null
avatar_url
string | null
deleted_at
string | null format: date-time
created_at
string format: date-time
updated_at
string format: date-time
Examples
Examplepublished
{
"id": 2927,
"category_id": 993,
"user_id": 20,
"title": "Onboarding checklist",
"type": "text",
"meta": null,
"created_at": "2026-10-19T13:50:45.000000Z",
"updated_at": "2026-10-19T13:51:39.000000Z",
"deleted_at": null,
"parent_id": null,
"position": 1451,
"page_content_id": 4508,
"status": "published",
"published_at": null,
"identifier": "dDbBQQtcKr",
"is_cover": false,
"visibility": null,
"last_content_published_at": "2026-10-19T13:51:39.000000Z",
"effective_visibility": "restricted",
"display_visibility": "inherit",
"is_public": false,
"category": {
"id": 993,
"cuid": "7f3c2a10-5b8e-4d21-9c6a-0e4f1b2d3c4a",
"name": "Onboarding",
"slug": "onboarding",
"description": "Everything a new hire needs in the first month.",
"created_at": "2026-10-19T13:50:38.000000Z",
"updated_at": "2026-10-19T13:50:38.000000Z",
"deleted_at": null,
"visibility": "restricted",
"user_id": 20,
"identifier": "jYpV3A",
"group_id": null,
"is_public": false
},
"user": {
"id": 20,
"uuid": "2d9e8f70-1a3b-4c5d-8e9f-a0b1c2d3e4f5",
"cuid": "7f3c2a10-5b8e-4d21-9c6a-0e4f1b2d3c4a",
"username": "ana.souza@example.com",
"email": "ana.souza@example.com",
"name": "Ana Souza",
"company_name": "Acme",
"role": "user",
"status": "active",
"created_at": "2024-03-25T19:47:41.000000Z",
"updated_at": "2026-09-16T17:25:41.000000Z",
"deleted_at": null,
"remember_token": null,
"avatar_url": null,
"settings": {
"language": "en",
"language_source": "company",
"theme": "light",
"timezone": null,
"user_id": 214
}
},
"permissions": [
{
"id": 2045,
"page_id": 2927,
"actions": "manage",
"created_at": "2026-10-19T13:50:45.000000Z",
"updated_at": "2026-10-19T13:50:45.000000Z",
"member_type": "App\\Models\\User",
"member_id": 20
}
]
}

No authentication key was sent.

Media typeapplication/json

Authentication failures use an error key rather than message.

object
error
required
string
Examples
Examplemissing

No bearer token sent

{
"error": "JWT passport exception: Missing bearer token in request"
}

The caller lacks the access this operation needs.

Media typeapplication/json

Generic error envelope used by permission, lookup and framework failures.

object
message
required
string
Examples
Exampledenied
{
"message": "This action is unauthorized."
}

No such resource — or it does not belong to the category or page in the path.

Media typeapplication/json

Generic error envelope used by permission, lookup and framework failures.

object
message
required
string
Examples
Examplemissing
{
"message": "No query results for model [App\\Models\\Page] 999999"
}

The version is already published.

Media typeapplication/json

A rule enforced by Papers itself — a version that can no longer change, a special page. status repeats the HTTP status; help is a hint for the end user and is often empty.

object
error
required
string
status
required
integer
help
required
string
Examples
ExamplealreadyPublished
{
"error": "Page has been published already, unable to publish it again.",
"status": 409,
"help": ""
}

The authentication key is expired or not recognised. Get a fresh one and retry.

Media typeapplication/json

Authentication failures use an error key rather than message.

object
error
required
string
Examples
Exampleexpired
{
"error": "JWT passport expired: Passport expired"
}