Blog API
18 operations. Authentication, errors and pagination work as described in the REST API overview.
Published blog posts, or your own
GET/api/v1/postsToken optional
Live posts newest first (tag, author handle, series slug, q), keyset-paginated with cursor. scope=mine lists the caller's own posts in every state (draft, in review, scheduled, published, rejected, unpublished).
| Name | Type | Description |
|---|---|---|
scope query | "published" | "mine" | |
tag query | string | |
author query | string | |
series query | string | |
q query | string | |
cursor query | string | |
limit query | integer (1–50) |
Responses: 200 OK304, 400, 404, 429
Response fields
| Name | Type | Description |
|---|---|---|
itemsrequired | object[] | |
nextCursorrequired | string | null | Opaque cursor for the next page; null at the end |
curl 'https://incantory.ai/api/v1/posts' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Create a draft post
POST/api/v1/postsToken required
Owned by the caller; tags must exist; the slug is derived from the title unless given. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
Request body
| Name | Type | Description |
|---|---|---|
titlerequired | string | |
subtitle | string | |
body | string | |
slug | string | |
tags | string[] | |
seriesId | string | null | |
coverMediaId | string | null | |
canonicalUrl | string | null |
Responses: 201 OK400, 401, 403, 404, 409, 422, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string | |
titlerequired | string | |
subtitlerequired | string | |
excerptrequired | string | |
statusrequired | "draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished" | |
statusLabelrequired | string | |
publishedAtrequired | string | null | |
updatedAtrequired | string | ISO 8601 timestamp (UTC) |
createdAtrequired | string | ISO 8601 timestamp (UTC) |
readingMinutesrequired | integer (-9007199254740991–9007199254740991) | |
authorrequired | object | |
tagsrequired | string[] | |
coverrequired | object | null | A media view |
seriesrequired | object | null | |
starCountrequired | integer (-9007199254740991–9007199254740991) | |
commentCountrequired | integer (-9007199254740991–9007199254740991) | |
hasPendingRevision | boolean | Owner view only |
bodyrequired | string | Markdown |
canonicalUrlrequired | string | null | |
canonicalPathrequired | string | |
scheduledrequired | boolean | |
liverequired | boolean | |
deletedrequired | boolean | |
commentsLockedrequired | boolean | |
reviewNotesrequired | string | null | |
pendingrequired | object | null | |
workingCopyrequired | object | null | |
featuredrequired | boolean | |
viewerrequired | object | |
toc | object[] | With toc=1 |
curl -X POST 'https://incantory.ai/api/v1/posts' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"title"}'Get one post
GET/api/v1/posts/{id}Token optional
By id or slug. Drafts, posts in review and scheduled posts are visible to their author and moderators only. toc=1 adds the h2/h3 outline with the ids the page uses.
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
toc query | "0" | "1" | "true" | "false" |
Responses: 200 OK400, 404, 410, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string | |
titlerequired | string | |
subtitlerequired | string | |
excerptrequired | string | |
statusrequired | "draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished" | |
statusLabelrequired | string | |
publishedAtrequired | string | null | |
updatedAtrequired | string | ISO 8601 timestamp (UTC) |
createdAtrequired | string | ISO 8601 timestamp (UTC) |
readingMinutesrequired | integer (-9007199254740991–9007199254740991) | |
authorrequired | object | |
tagsrequired | string[] | |
coverrequired | object | null | A media view |
seriesrequired | object | null | |
starCountrequired | integer (-9007199254740991–9007199254740991) | |
commentCountrequired | integer (-9007199254740991–9007199254740991) | |
hasPendingRevision | boolean | Owner view only |
bodyrequired | string | Markdown |
canonicalUrlrequired | string | null | |
canonicalPathrequired | string | |
scheduledrequired | boolean | |
liverequired | boolean | |
deletedrequired | boolean | |
commentsLockedrequired | boolean | |
reviewNotesrequired | string | null | |
pendingrequired | object | null | |
workingCopyrequired | object | null | |
featuredrequired | boolean | |
viewerrequired | object | |
toc | object[] | With toc=1 |
curl 'https://incantory.ai/api/v1/posts/{id}' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Edit a post
PATCH/api/v1/posts/{id}Token required
Author or admin. For a published post, title/subtitle/body become the working copy (savedTo: "working_copy"): the live text changes only when a submitted revision is approved. A new slug 301s the old URL. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
Request body
| Name | Type | Description |
|---|---|---|
title | string | |
subtitle | string | |
body | string | |
slug | string | |
tags | string[] | |
seriesId | string | null | |
seriesPosition | integer (1–10000) | null | |
coverMediaId | string | null | |
canonicalUrl | string | null |
Responses: 200 OK400, 401, 403, 404, 409, 410, 422, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string | |
titlerequired | string | |
subtitlerequired | string | |
excerptrequired | string | |
statusrequired | "draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished" | |
statusLabelrequired | string | |
publishedAtrequired | string | null | |
updatedAtrequired | string | ISO 8601 timestamp (UTC) |
createdAtrequired | string | ISO 8601 timestamp (UTC) |
readingMinutesrequired | integer (-9007199254740991–9007199254740991) | |
authorrequired | object | |
tagsrequired | string[] | |
coverrequired | object | null | A media view |
seriesrequired | object | null | |
starCountrequired | integer (-9007199254740991–9007199254740991) | |
commentCountrequired | integer (-9007199254740991–9007199254740991) | |
hasPendingRevision | boolean | Owner view only |
bodyrequired | string | Markdown |
canonicalUrlrequired | string | null | |
canonicalPathrequired | string | |
scheduledrequired | boolean | |
liverequired | boolean | |
deletedrequired | boolean | |
commentsLockedrequired | boolean | |
reviewNotesrequired | string | null | |
pendingrequired | object | null | |
workingCopyrequired | object | null | |
featuredrequired | boolean | |
viewerrequired | object | |
toc | object[] | With toc=1 |
savedTorequired | "post" | "working_copy" | "none" |
curl -X PATCH 'https://incantory.ai/api/v1/posts/{id}' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'Delete a post (soft)
DELETE/api/v1/posts/{id}Token required
Author or admin; the page answers 410. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
Request body (optional)
| Name | Type | Description |
|---|---|---|
reason | string |
Responses: 204 OK400, 401, 403, 404, 410, 429
curl -X DELETE 'https://incantory.ai/api/v1/posts/{id}' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'Save the working copy (editor autosave)
PUT/api/v1/posts/{id}/autosaveToken required
Drafts change in place; published posts get a revision. Kept as history (coalesced, newest 50). 409 while in review. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
Request body
| Name | Type | Description |
|---|---|---|
title | string | |
subtitle | string | |
body | string |
Responses: 200 OK400, 401, 403, 404, 409, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string | |
savedTorequired | "post" | "working_copy" | "none" | |
atrequired | string | ISO 8601 timestamp (UTC) |
curl -X PUT 'https://incantory.ai/api/v1/posts/{id}/autosave' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'Revision history
GET/api/v1/posts/{id}/revisionsToken required
Author or admin. Newest first; bodies via the single-revision route.
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
Responses: 200 OK400, 401, 403, 404, 429
Response fields
| Name | Type | Description |
|---|---|---|
itemsrequired | object[] |
curl 'https://incantory.ai/api/v1/posts/{id}/revisions' \
-H "Authorization: Bearer $INCANTORY_TOKEN"One revision with its body
GET/api/v1/posts/{id}/revisions/{revisionId}Token required
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
revisionId pathrequired | string | PostRevision id |
Responses: 200 OK400, 401, 403, 404, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
kindrequired | string | |
titlerequired | string | |
subtitlerequired | string | |
bodyrequired | string | |
atrequired | string | ISO 8601 timestamp (UTC) |
curl 'https://incantory.ai/api/v1/posts/{id}/revisions/{revisionId}' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Restore a revision as the working text
POST/api/v1/posts/{id}/revisions/{revisionId}/restoreToken required
Author or admin. A published post gets a new working copy (submit it to go live). Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
revisionId pathrequired | string | PostRevision id |
Responses: 200 OK400, 401, 403, 404, 409, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string | |
savedTorequired | "post" | "working_copy" | "none" |
curl -X POST 'https://incantory.ai/api/v1/posts/{id}/revisions/{revisionId}/restore' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Submit for review (or publish, for trusted authors)
POST/api/v1/posts/{id}/submitToken required
Drafts/rejected/unpublished → in review; a published post → a pending revision. Trusted authors publish directly; a future publishAt schedules. Spam and rate checks apply. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
Request body (optional)
| Name | Type | Description |
|---|---|---|
publishAt | any | |
title | string | |
subtitle | string | |
body | string |
Responses: 200 OK400, 401, 403, 404, 409, 422, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string | |
statusrequired | "draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished" | |
outcomerequired | "in_review" | "published" | "scheduled" | "revision_in_review" | "revision_published" | |
publishedAtrequired | string | null | |
reviewItemIdrequired | string | null |
curl -X POST 'https://incantory.ai/api/v1/posts/{id}/submit' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'Unpublish a post
POST/api/v1/posts/{id}/unpublishToken required
Author, moderator or admin; a moderator's reason is sent to the author. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
Request body (optional)
| Name | Type | Description |
|---|---|---|
reason | string |
Responses: 200 OK400, 401, 403, 404, 409, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
statusrequired | "draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished" |
curl -X POST 'https://incantory.ai/api/v1/posts/{id}/unpublish' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'Withdraw a submission
POST/api/v1/posts/{id}/withdrawToken required
Author. Back to draft (or the working copy for a pending revision). Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Post id or slug |
Responses: 200 OK400, 401, 403, 404, 409, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
statusrequired | "draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished" |
curl -X POST 'https://incantory.ai/api/v1/posts/{id}/withdraw' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Your series
GET/api/v1/posts/seriesToken required
Responses: 200 OK400, 401, 403, 404, 429
Response fields
| Name | Type | Description |
|---|---|---|
itemsrequired | object[] |
curl 'https://incantory.ai/api/v1/posts/series' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Create a series
POST/api/v1/posts/seriesToken required
Series slugs are globally unique (/blog/series/{slug}). Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
Request body
| Name | Type | Description |
|---|---|---|
titlerequired | string | |
slug | string | |
description | string |
Responses: 201 OK400, 401, 403, 404, 409, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string |
curl -X POST 'https://incantory.ai/api/v1/posts/series' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"title"}'One series with its published posts in order
GET/api/v1/posts/series/{id}Token optional
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Series id (GET: slug) |
Responses: 200 OK400, 404, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string | |
titlerequired | string | |
descriptionrequired | string | |
authorrequired | object | |
postsrequired | object[] | |
updatedAtrequired | string | ISO 8601 timestamp (UTC) |
curl 'https://incantory.ai/api/v1/posts/series/{id}' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Edit a series
PATCH/api/v1/posts/series/{id}Token required
Owner or admin; a new slug 301s the old URL. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Series id (GET: slug) |
Request body
| Name | Type | Description |
|---|---|---|
title | string | |
slug | string | |
description | string |
Responses: 200 OK400, 401, 403, 404, 409, 429
Response fields
| Name | Type | Description |
|---|---|---|
idrequired | string | |
slugrequired | string |
curl -X PATCH 'https://incantory.ai/api/v1/posts/series/{id}' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'Delete a series
DELETE/api/v1/posts/series/{id}Token required
Its posts stay published, outside any series. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Series id (GET: slug) |
Responses: 204 OK400, 401, 403, 404, 429
curl -X DELETE 'https://incantory.ai/api/v1/posts/series/{id}' \
-H "Authorization: Bearer $INCANTORY_TOKEN"Reorder a series
POST/api/v1/posts/series/{id}/reorderToken required
postIds in reading order; every id must be in the series. Needs a signed-in session or an admin:mcp token (posts are not writable with a plain write token, PLAN §3).
| Name | Type | Description |
|---|---|---|
id pathrequired | string | Series id (GET: slug) |
Request body
| Name | Type | Description |
|---|---|---|
postIdsrequired | string[] |
Responses: 200 OK400, 401, 403, 404, 422, 429
Response fields
| Name | Type | Description |
|---|---|---|
okrequired | true |
curl -X POST 'https://incantory.ai/api/v1/posts/series/{id}/reorder' \
-H "Authorization: Bearer $INCANTORY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"postIds":["postIds"]}'