| name | ghost-admin-api |
| description | Interact with Ghost CMS Admin API — publish posts, manage pages/tags/members, upload images, send newsletters. |
| version | 2.0.0 |
| license | MIT |
| tags | ["ghost","cms","blog","publishing","api","newsletter"] |
Ghost Admin API Skill
Manage Ghost CMS via Admin API — publish posts, manage content, upload images, send newsletters. Works with any self-hosted Ghost 5.x/6.x instance.
When to Use
- Publish/update/delete blog posts
- Create or manage pages, tags, members
- Upload images to Ghost media library
- Send or schedule newsletters
- Read site stats and analytics
Setup
Prerequisites
- Ghost Admin API Key (format:
{24hex}:{64hex})
- Get it: Ghost Admin → Settings → Integrations → Add Custom Integration → Copy Admin API Key
- PyJWT:
pip install PyJWT
Environment
GHOST_ADMIN_URL=https://your-ghost-domain.com/ghost/api/admin
GHOST_ADMIN_KEY=24hex_id:64hex_secret
Module
The GhostAdmin class is documented here but NOT installed as a pip package. Copy it from references/code_examples.md inline into your script.
Verify
g = GhostAdmin()
print(g.site_info())
Quick Reference
| Operation | Method | Path |
|---|
| Create post | POST | /posts/?source=html |
| List posts | GET | /posts/ |
| Update post | PUT | /posts/{id}/?source=html |
| Delete post | DELETE | /posts/{id}/ |
| Upload image | POST | /images/upload/ |
| List tags | GET | /tags/ |
| Create tag | POST | /tags/ |
| List members | GET | /members/ |
| Site info | GET | /site/ |
| Send newsletter | PUT | /posts/{id}/?newsletter={slug}&email_segment=all |
Full endpoint reference → references/api_endpoints.md
Authentication
Ghost Admin API uses JWT tokens generated from the Admin API Key:
import jwt, time
def make_token(key_id, key_secret):
return jwt.encode(
{"iat": int(time.time()), "exp": int(time.time()) + 300, "aud": "/admin/"},
bytes.fromhex(key_secret), algorithm="HS256", headers={"kid": key_id}
)
Required headers for every request:
Authorization: Ghost {jwt_token}
Accept-Version: v6.27
Content-Type: application/json
User-Agent: YourApp/1.0
Key Rules
User-Agent header required — Cloudflare blocks without it (1010 error)
Accept-Version — must match your Ghost version
- Nested format —
{"posts": [...]}, {"tags": [...]}, etc.
updated_at required for PUT — always GET first to prevent conflicts
?source=html is CRITICAL — without it, html field is silently ignored → empty post
- Newsletter = 2-step — create draft, then PUT with query params
?formats=html,lexical — default GET returns empty html field
- Max 100 results per request (
?limit=all caps at 100)
- JWT expires in 5 min — regenerate per request
- DELETE returns 204 — empty body, do NOT
json.loads()
- ⚠️ ALWAYS VERIFY after publish — GET post back, verify
html is non-empty
newsletter field in POST body is silently ignored — use PUT query params instead
Content Formats
| Format | How to Send | Notes |
|---|
| HTML (recommended) | ?source=html + "html": "..." | Auto-converts to Lexical |
| Lexical (native) | "lexical": "..." | Full fidelity — see references/content-formats.md |
Styled HTML (<div>, style, class) requires <!--kg-card-begin: html--> wrapper.
Lexical Builder
For programmatic post building, use references/lexical_builder.py — copy functions inline into your script:
from lexical_builder import text_node, heading_node, build_lexical, rich_paragraph
blocks = [
heading_node("Section Title"),
rich_paragraph(["Normal text ", ("bold text", "bold"), ("linked", "https://example.com")]),
]
lexical_json = build_lexical(blocks)
References
| File | Description |
|---|
references/api_endpoints.md | Complete API endpoint reference (all resources, params, bodies) |
references/code_examples.md | GhostAdmin Python class + usage examples |
references/workflows.md | Common workflows: publish, schedule, newsletter, bulk audit |
references/pitfalls.md | Common errors, gotchas, and fixes |
references/content-formats.md | Lexical format details and HTML conversion |
references/lexical_builder.py | Python helper functions to build Lexical JSON |