On this page

Community blog posts. Every route is also served under /api/communities/communityId/blogs (same handlers, same rules; {blogId} there, {id} here). A router-level gate returns 403 FEATURE_NOT_AVAILABLE on a plan without blogs, reads included.

Reads are optionalAuth and follow the community's read scope:

  • An APPROVED member reads published posts. A moderator also reads drafts and archived posts (?status=).
  • A guest, or a signed-in non-member, reads only posts opted into guest preview, in a PUBLIC community whose plan includes blogs.
  • Anyone else gets an empty list or 404. Author objects carry the community name and avatar, never an email.

Writes need an APPROVED member. Editing or deleting ANY post needs blogs:manage or blogs:moderate. The author may edit and delete their own. blogs:create lets you create and edit your own, never anyone else's.

9 endpoints.

MethodPathSummary
GET/api/blogsList posts
POST/api/blogsCreate a post (blogs:manage | blogs:create)
DELETE/api/blogs/{id}Delete a post (author, or blogs:manage | blogs:moderate)
GET/api/blogs/{id}One post
PUT/api/blogs/{id}Edit a post (author, or blogs:manage | blogs:moderate)
POST/api/blogs/{id}/likeToggle your like (members only)
GET/api/blogs/{id}/like-statusDid I like this post (members only)
GET/api/blogs/{id}/likesWho liked a post (members only)
PATCH/api/blogs/{id}/toggle-visibilitySwitch a post between DRAFT and PUBLISHED (blogs:manage | blogs:moderate)

Auth: optional — a token changes what you can see (see "Who may read what").

Parameters

NameInRequiredTypeDescription
communityIdquerynostring (uuid)—
qquerynostring—
categoryIdquerynostring (uuid)—
sectionIdquerynostring (uuid)—
statusquerynoenum: DRAFT, PUBLISHED, ARCHIVEDModerators only; everyone else is pinned to PUBLISHED. Invalid → 400
pagequerynointeger—
pageSizequerynointeger—

Responses

StatusDescriptionBody
200success, data: [Blog], pagination — each post has isLiked for the caller—
400Invalid status or pagination—

The community is the one the guards checked. A body communityId that disagrees is refused with 400 COMMUNITY_MISMATCH. The header image and inline images count against storage, and a new post is refused over the cap. Rate limited.

Auth: Bearer JWT required.

Request body (required) — multipart/form-data

FieldTypeRequiredDescription
titlestringyes—
contentHtmlstringyesRich text; sanitized; inline data-URI images are uploaded and rewritten
statusenum: DRAFT, PUBLISHED, ARCHIVEDno—
slugstringno—
allowCommentsbooleannoAlso accepts "true"/"false" from forms
categoryIdsstringnoJSON array of blog-category ids
newCategoriesstringnoJSON array of names to create
sectionIdstring (uuid)no—
isGuestVisiblebooleanno—
headerImagestring (binary)no—

Responses

StatusDescriptionBody
201success, data: Blog—
400Missing title/contentHtml—
403Not a member—

Soft delete. The post also leaves the home feed. Auth: Bearer JWT required.

Responses

StatusDescriptionBody
200success—

A post the caller may not read answers 404, exactly as a missing id does. The response includes isLiked and the author's avatar. Auth: optional — a token changes what you can see (see "Who may read what").

Responses

StatusDescriptionBody
200success, data: Blog—
404Not found or not visible to this caller—

Same fields as create, all optional. Bytes are recorded, but an edit is never refused over the storage cap. Auth: Bearer JWT required.

Responses

StatusDescriptionBody
200success, data: Blog—
404Not found—

Auth: Bearer JWT required.

Parameters

NameInRequiredTypeDescription
idpathyesstring (uuid)—

Responses

StatusDescriptionBody
200success, data: { liked, likeCount }—
404No such published post—

Auth: Bearer JWT required.

Parameters

NameInRequiredTypeDescription
idpathyesstring (uuid)—

Responses

StatusDescriptionBody
200success, hasLiked—

Auth: Bearer JWT required.

Parameters

NameInRequiredTypeDescription
idpathyesstring (uuid)—

Responses

StatusDescriptionBody
200success, data: [{ userId, firstName, familyName, avatar, createdAt }] — community names, at most 100—

Auth: Bearer JWT required.

Parameters

NameInRequiredTypeDescription
idpathyesstring (uuid)—

Responses

StatusDescriptionBody
200success, data: Blog—