From ghost
Create, edit, publish, schedule, and delete Ghost posts and pages via the Admin API. Covers Lexical content format, visibility gating, and email-only posts.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ghost:ghost-contentThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Posts and pages are managed via the Ghost Admin API. This skill covers the full lifecycle: drafting, publishing, scheduling, sending as email-only, and deleting.
Posts and pages are managed via the Ghost Admin API. This skill covers the full lifecycle: drafting, publishing, scheduling, sending as email-only, and deleting.
Prerequisite: Authentication configured — see ghost-admin-api-auth.
Base URL: https://{GHOST_ADMIN_URL}/ghost/api/admin/
Announce at start: "I'm using the ghost-content skill."
| Posts | Pages | |
|---|---|---|
| Appears in feeds | Yes | No |
| Reverse-chron ordering | Yes | No |
| Use for | Articles, newsletters | About, contact, landing pages |
| API path | /admin/posts/ | /admin/pages/ |
The API shape is identical — all examples below apply to both endpoints.
Minimum required field: title.
curl -X POST \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
-H "Content-Type: application/json" \
-d '{
"posts": [{
"title": "My First Post",
"status": "draft"
}]
}' \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/"
With HTML content (Ghost converts to Lexical automatically):
curl -X POST \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
-H "Content-Type: application/json" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/?source=html" \
-d '{
"posts": [{
"title": "My Post",
"html": "<p>First paragraph.</p><p>Second paragraph.</p>",
"status": "draft"
}]
}'
Important: ?source=html triggers HTML→Lexical conversion. To preserve raw HTML unchanged, wrap it in a card:
<!--kg-card-begin: html-->
<div class="custom-component">...</div>
<!--kg-card-end: html-->
| Status | Meaning |
|---|---|
draft | Not published, not visible publicly |
published | Live on the site |
scheduled | Will publish at published_at datetime |
sent | Email-only post that has been sent (terminal state) |
# First, get the post's current_data.updated_at (required to prevent conflicts)
POST_DATA=$(curl -H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/{POST_ID}/")
UPDATED_AT=$(echo $POST_DATA | jq -r '.posts[0].updated_at')
# Publish
curl -X PUT \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
-H "Content-Type: application/json" \
-d "{\"posts\": [{\"status\": \"published\", \"updated_at\": \"$UPDATED_AT\"}]}" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/{POST_ID}/"
Always include updated_at on PUT requests — Ghost uses it as an optimistic lock to prevent overwriting concurrent edits.
curl -X PUT \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
-H "Content-Type: application/json" \
-d '{
"posts": [{
"status": "scheduled",
"published_at": "2024-09-01T09:00:00.000Z",
"updated_at": "'"$UPDATED_AT"'"
}]
}' \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/{POST_ID}/"
published_at must be an ISO 8601 UTC datetime string. Ghost sends the post (and email if configured) automatically at that time.
An email-only post is sent to subscribers but never published to the website. Status becomes sent when delivery is complete (terminal — cannot be edited after).
curl -X POST \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
-H "Content-Type: application/json" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/?newsletter=weekly-digest" \
-d '{
"posts": [{
"title": "This Week in Review",
"html": "<p>...</p>",
"status": "published",
"email_only": true
}]
}'
The newsletter query param is the slug of the newsletter to send to (see ghost-newsletters for slug lookup).
To both publish to the website AND send as email:
curl -X PUT \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
-H "Content-Type: application/json" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/{POST_ID}/?newsletter=weekly-digest" \
-d '{
"posts": [{
"status": "published",
"email_segment": "all",
"updated_at": "'"$UPDATED_AT"'"
}]
}'
email_segment options: all, free, paid.
{
"visibility": "public"
}
| Value | Who can read |
|---|---|
public | Everyone |
members | Any logged-in member |
paid | Paid members only |
tiers | Specific tiers (use tiers array field) |
Enforcement is server-side — cannot be bypassed client-side.
Tags are created automatically if they don't exist. Use # prefix for internal (non-public) tags:
{
"tags": [
{"name": "Technology"},
{"name": "AI"},
{"name": "#newsletter-only"}
]
}
{
"title": "Post Title",
"slug": "post-title",
"status": "draft",
"featured": false,
"visibility": "public",
"published_at": null,
"email_only": false,
"tags": [],
"authors": [{"email": "[email protected]"}],
"excerpt": "Custom excerpt shown in cards",
"feature_image": "https://example.com/image.jpg",
"feature_image_alt": "Alt text",
"feature_image_caption": "Caption text",
"meta_title": "SEO title override",
"meta_description": "SEO description override",
"og_title": "Open Graph title",
"og_description": "Open Graph description",
"og_image": "https://example.com/og.jpg",
"twitter_title": "Twitter card title",
"twitter_description": "Twitter card description",
"twitter_image": "https://example.com/twitter.jpg",
"codeinjection_head": "<script>...</script>",
"codeinjection_foot": "<script>...</script>"
}
# Get a single post by ID
curl -H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/{POST_ID}/"
# Browse with filters
curl -H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/?filter=status:draft&limit=20&include=tags,authors"
curl -X DELETE \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/{POST_ID}/"
Returns 204 No Content on success.
curl -X POST \
-H "Authorization: Ghost $TOKEN" \
-H "Accept-Version: v5.0" \
"$GHOST_ADMIN_URL/ghost/api/admin/posts/{POST_ID}/copy/"
Creates a draft copy with "Copy of" prepended to the title.
ghost-admin-api-auth completed — $TOKEN and $GHOST_ADMIN_URL set?source=html when providing HTML contentupdated_at on all PUT requestsnewsletter slug param set when sending to email subscriberspublished_at is UTC ISO 8601 for scheduled posts# for internal-only tagsGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub thinkmorestupidless/claude-marketplace --plugin ghost