Incantory
Sign in

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).

listPosts parameters
NameTypeDescription
scope query"published" | "mine"
tag querystring
author querystring
series querystring
q querystring
cursor querystring
limit queryinteger (1–50)

Responses: 200 OK304, 400, 404, 429

Response fields
listPosts response fields
NameTypeDescription
itemsrequiredobject[]
nextCursorrequiredstring | nullOpaque cursor for the next page; null at the end
Example
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

createPost body fields
NameTypeDescription
titlerequiredstring
subtitlestring
bodystring
slugstring
tagsstring[]
seriesIdstring | null
coverMediaIdstring | null
canonicalUrlstring | null

Responses: 201 OK400, 401, 403, 404, 409, 422, 429

Response fields
createPost response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
titlerequiredstring
subtitlerequiredstring
excerptrequiredstring
statusrequired"draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished"
statusLabelrequiredstring
publishedAtrequiredstring | null
updatedAtrequiredstringISO 8601 timestamp (UTC)
createdAtrequiredstringISO 8601 timestamp (UTC)
readingMinutesrequiredinteger (-9007199254740991–9007199254740991)
authorrequiredobject
tagsrequiredstring[]
coverrequiredobject | nullA media view
seriesrequiredobject | null
starCountrequiredinteger (-9007199254740991–9007199254740991)
commentCountrequiredinteger (-9007199254740991–9007199254740991)
hasPendingRevisionbooleanOwner view only
bodyrequiredstringMarkdown
canonicalUrlrequiredstring | null
canonicalPathrequiredstring
scheduledrequiredboolean
liverequiredboolean
deletedrequiredboolean
commentsLockedrequiredboolean
reviewNotesrequiredstring | null
pendingrequiredobject | null
workingCopyrequiredobject | null
featuredrequiredboolean
viewerrequiredobject
tocobject[]With toc=1
Example
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.

getPost parameters
NameTypeDescription
id pathrequiredstringPost id or slug
toc query"0" | "1" | "true" | "false"

Responses: 200 OK400, 404, 410, 429

Response fields
getPost response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
titlerequiredstring
subtitlerequiredstring
excerptrequiredstring
statusrequired"draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished"
statusLabelrequiredstring
publishedAtrequiredstring | null
updatedAtrequiredstringISO 8601 timestamp (UTC)
createdAtrequiredstringISO 8601 timestamp (UTC)
readingMinutesrequiredinteger (-9007199254740991–9007199254740991)
authorrequiredobject
tagsrequiredstring[]
coverrequiredobject | nullA media view
seriesrequiredobject | null
starCountrequiredinteger (-9007199254740991–9007199254740991)
commentCountrequiredinteger (-9007199254740991–9007199254740991)
hasPendingRevisionbooleanOwner view only
bodyrequiredstringMarkdown
canonicalUrlrequiredstring | null
canonicalPathrequiredstring
scheduledrequiredboolean
liverequiredboolean
deletedrequiredboolean
commentsLockedrequiredboolean
reviewNotesrequiredstring | null
pendingrequiredobject | null
workingCopyrequiredobject | null
featuredrequiredboolean
viewerrequiredobject
tocobject[]With toc=1
Example
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).

updatePost parameters
NameTypeDescription
id pathrequiredstringPost id or slug

Request body

updatePost body fields
NameTypeDescription
titlestring
subtitlestring
bodystring
slugstring
tagsstring[]
seriesIdstring | null
seriesPositioninteger (1–10000) | null
coverMediaIdstring | null
canonicalUrlstring | null

Responses: 200 OK400, 401, 403, 404, 409, 410, 422, 429

Response fields
updatePost response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
titlerequiredstring
subtitlerequiredstring
excerptrequiredstring
statusrequired"draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished"
statusLabelrequiredstring
publishedAtrequiredstring | null
updatedAtrequiredstringISO 8601 timestamp (UTC)
createdAtrequiredstringISO 8601 timestamp (UTC)
readingMinutesrequiredinteger (-9007199254740991–9007199254740991)
authorrequiredobject
tagsrequiredstring[]
coverrequiredobject | nullA media view
seriesrequiredobject | null
starCountrequiredinteger (-9007199254740991–9007199254740991)
commentCountrequiredinteger (-9007199254740991–9007199254740991)
hasPendingRevisionbooleanOwner view only
bodyrequiredstringMarkdown
canonicalUrlrequiredstring | null
canonicalPathrequiredstring
scheduledrequiredboolean
liverequiredboolean
deletedrequiredboolean
commentsLockedrequiredboolean
reviewNotesrequiredstring | null
pendingrequiredobject | null
workingCopyrequiredobject | null
featuredrequiredboolean
viewerrequiredobject
tocobject[]With toc=1
savedTorequired"post" | "working_copy" | "none"
Example
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).

deletePost parameters
NameTypeDescription
id pathrequiredstringPost id or slug

Request body (optional)

deletePost body fields
NameTypeDescription
reasonstring

Responses: 204 OK400, 401, 403, 404, 410, 429

Example
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).

autosavePost parameters
NameTypeDescription
id pathrequiredstringPost id or slug

Request body

autosavePost body fields
NameTypeDescription
titlestring
subtitlestring
bodystring

Responses: 200 OK400, 401, 403, 404, 409, 429

Response fields
autosavePost response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
savedTorequired"post" | "working_copy" | "none"
atrequiredstringISO 8601 timestamp (UTC)
Example
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.

listPostRevisions parameters
NameTypeDescription
id pathrequiredstringPost id or slug

Responses: 200 OK400, 401, 403, 404, 429

Response fields
listPostRevisions response fields
NameTypeDescription
itemsrequiredobject[]
Example
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

getPostRevision parameters
NameTypeDescription
id pathrequiredstringPost id or slug
revisionId pathrequiredstringPostRevision id

Responses: 200 OK400, 401, 403, 404, 429

Response fields
getPostRevision response fields
NameTypeDescription
idrequiredstring
kindrequiredstring
titlerequiredstring
subtitlerequiredstring
bodyrequiredstring
atrequiredstringISO 8601 timestamp (UTC)
Example
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).

restorePostRevision parameters
NameTypeDescription
id pathrequiredstringPost id or slug
revisionId pathrequiredstringPostRevision id

Responses: 200 OK400, 401, 403, 404, 409, 429

Response fields
restorePostRevision response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
savedTorequired"post" | "working_copy" | "none"
Example
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).

submitPost parameters
NameTypeDescription
id pathrequiredstringPost id or slug

Request body (optional)

submitPost body fields
NameTypeDescription
publishAtany
titlestring
subtitlestring
bodystring

Responses: 200 OK400, 401, 403, 404, 409, 422, 429

Response fields
submitPost response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
statusrequired"draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished"
outcomerequired"in_review" | "published" | "scheduled" | "revision_in_review" | "revision_published"
publishedAtrequiredstring | null
reviewItemIdrequiredstring | null
Example
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).

unpublishPost parameters
NameTypeDescription
id pathrequiredstringPost id or slug

Request body (optional)

unpublishPost body fields
NameTypeDescription
reasonstring

Responses: 200 OK400, 401, 403, 404, 409, 429

Response fields
unpublishPost response fields
NameTypeDescription
idrequiredstring
statusrequired"draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished"
Example
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).

withdrawPost parameters
NameTypeDescription
id pathrequiredstringPost id or slug

Responses: 200 OK400, 401, 403, 404, 409, 429

Response fields
withdrawPost response fields
NameTypeDescription
idrequiredstring
statusrequired"draft" | "submitted" | "in_review" | "published" | "rejected" | "unpublished"
Example
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
listMySeries response fields
NameTypeDescription
itemsrequiredobject[]
Example
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

createSeries body fields
NameTypeDescription
titlerequiredstring
slugstring
descriptionstring

Responses: 201 OK400, 401, 403, 404, 409, 429

Response fields
createSeries response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
Example
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

getSeries parameters
NameTypeDescription
id pathrequiredstringSeries id (GET: slug)

Responses: 200 OK400, 404, 429

Response fields
getSeries response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
titlerequiredstring
descriptionrequiredstring
authorrequiredobject
postsrequiredobject[]
updatedAtrequiredstringISO 8601 timestamp (UTC)
Example
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).

updateSeries parameters
NameTypeDescription
id pathrequiredstringSeries id (GET: slug)

Request body

updateSeries body fields
NameTypeDescription
titlestring
slugstring
descriptionstring

Responses: 200 OK400, 401, 403, 404, 409, 429

Response fields
updateSeries response fields
NameTypeDescription
idrequiredstring
slugrequiredstring
Example
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).

deleteSeries parameters
NameTypeDescription
id pathrequiredstringSeries id (GET: slug)

Responses: 204 OK400, 401, 403, 404, 429

Example
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).

reorderSeries parameters
NameTypeDescription
id pathrequiredstringSeries id (GET: slug)

Request body

reorderSeries body fields
NameTypeDescription
postIdsrequiredstring[]

Responses: 200 OK400, 401, 403, 404, 422, 429

Response fields
reorderSeries response fields
NameTypeDescription
okrequiredtrue
Example
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"]}'