The write side of the v1 API lets you manage your content from your own tools: publish from a Git repository, run an inbound migration script, or wire Writizzy into a custom editorial pipeline. It stays in the same /v1 contract as the read endpoints, no separate version.
Writing requires a write key. A read key can only read: any create, update, publish or upload request made with a read key returns 403. A write key includes read access, so a single script can fetch a post and then patch it.
Generate the write key from Blog Settings → Developer API, then pass it as a Bearer token like any other request:
POST /v1/blogs/yourblog/posts
Authorization: Bearer wz_yourblog_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
A post is always created as a draft. Publishing is a separate, explicit step. A typical flow is:
POST /posts to create the draft, you get back its id and final slugPATCH /posts/{id} to refine itPOST /posts/{id}/publish to make it visibleThe author of any post created through the API is the blog owner.
| Method | Path | Description |
|---|---|---|
POST | /v1/blogs/{subdomain}/posts | Create a draft |
PATCH | /v1/blogs/{subdomain}/posts/{id} | Update a post (partial) |
POST | /v1/blogs/{subdomain}/posts/{id}/publish | Publish a post |
POST | /v1/blogs/{subdomain}/posts/{id}/unpublish | Revert a post to draft |
POST | /v1/blogs/{subdomain}/media | Upload a media file |
title and content are required. slug is optional: when omitted it is generated from the title, and de-duplicated automatically if it collides with an existing post. Tags are created on the fly.
curl -X POST https://writizzy.com/v1/blogs/yourblog/posts \
-H "Authorization: Bearer wz_yourblog_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Getting started with Kotlin",
"content": "# Hello\n\nThis is my first post.",
"tags": ["kotlin", "tutorial"]
}'
The response is the full post, including the resolved slug and id. Keep them as your reference: creation is not idempotent, so a replayed request creates another post.
{
"id": "p_abc123",
"title": "Getting started with Kotlin",
"slug": "getting-started-with-kotlin",
"content": "# Hello\n\nThis is my first post.",
"publishedAt": null,
"accessMode": "FREE",
"...": "..."
}
Send only the fields you want to change, the rest are left untouched. This call never changes the publication state.
curl -X PATCH https://writizzy.com/v1/blogs/yourblog/posts/p_abc123 \
-H "Authorization: Bearer wz_yourblog_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "excerpt": "A short intro to Kotlin." }'
Changing the slug after publication is discouraged, it breaks the public URL. A slug collision returns 400.
Publishing makes the post visible. That is its only effect: no newsletter is sent and no cross-posting is triggered, those are separate, explicit actions. A future publishedAt schedules the post, and it defaults to today when omitted. Publishing an already-published post is a no-op.
curl -X POST https://writizzy.com/v1/blogs/yourblog/posts/p_abc123/publish \
-H "Authorization: Bearer wz_yourblog_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Unpublishing reverts the post to a draft. It is reversible and safe, and a no-op on a draft.
curl -X POST https://writizzy.com/v1/blogs/yourblog/posts/p_abc123/unpublish \
-H "Authorization: Bearer wz_yourblog_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Upload an image as multipart/form-data and get back its public CDN URL. Use that URL as a post coverImageUrl or inside the Markdown content.
curl -X POST https://writizzy.com/v1/blogs/yourblog/media \
-H "Authorization: Bearer wz_yourblog_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-F "file=@cover.png" \
-F "altText=Cover image"
{
"url": "https://cdn.writizzy.com/blogs/.../cover.png",
"filename": "cover.png",
"size": 48213
}
Uploads count against your plan's media storage quota. A request that would exceed it returns 403.
POST. Static pages are not editable through the API.