Appearance
API Reference
The whiz.pub REST API is available at https://api.whiz.pub/v1. All requests and responses use JSON.
Interactive API documentation (ReDoc) is available at api.whiz.pub/v1.
Authentication
Most endpoints require a Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_KEYYou receive an API key when you sign up (via the web dashboard, CLI, or API). You can also find it on your settings page at /app/settings.
Auth Levels
| Level | Description | Endpoints |
|---|---|---|
| Public | No authentication required | POST /v1/signup, POST /v1/auth/login, POST /v1/auth/verify-otp, GET /health |
| Verified | Requires API key with verified email | All other endpoints |
New accounts receive a one-time code via email. Verify the code to complete signup and receive your API key. Returning users can log in by requesting a new code via POST /v1/auth/login.
Endpoints
| Method | Path | Auth Level | Description |
|---|---|---|---|
POST | /v1/signup | Public | Create an account and blog |
POST | /v1/auth/login | Public | Request a login code via email |
POST | /v1/auth/verify-otp | Public | Verify email code and get API key |
POST | /v1/posts | Verified | Create or update a post (upsert by slug) |
GET | /v1/posts | Verified | List posts (?limit=, ?offset=, ?tag=, ?status=) |
GET | /v1/posts/:slug | Verified | Get a specific post |
PUT | /v1/posts/:slug | Verified | Update a post (supports slug rename) |
DELETE | /v1/posts/:slug | Verified | Delete a post |
GET | /v1/dashboard | Verified | Per-tenant dashboard statistics |
POST | /v1/domains | Verified | Add a custom domain |
DELETE | /v1/domains | Verified | Remove custom domain |
POST | /v1/domains/:domain/verify | Verified | Verify domain DNS records |
GET | /v1/theme | Verified | Get theme and appearance settings |
PUT | /v1/theme | Verified | Update theme, fonts, custom CSS |
PUT | /v1/headless | Verified | Enable or disable headless mode |
GET | /v1/tags | Verified | List all tags with post counts |
POST | /v1/tags | Verified | Create a tag (with optional description) |
PUT | /v1/tags/:tag | Verified | Rename a tag and/or update description |
DELETE | /v1/tags/:tag | Verified | Delete a tag from all posts |
GET | /v1/settings | Verified | Get all blog settings |
PUT | /v1/settings/seo | Verified | Update display name, description |
PUT | /v1/settings/title-pattern | Verified | Update title pattern |
PUT | /v1/settings/ai-access | Verified | Toggle AI access (llms.txt) |
PUT | /v1/settings/blog | Verified | Update blog display settings (posts per page) |
PUT | /v1/settings/landing-page | Verified | Toggle custom landing page |
POST | /v1/apikey/regenerate | Verified | Regenerate API key |
DELETE | /v1/apikey | Verified | Revoke API key |
POST | /v1/cache/clear | Verified | Clear all cached blog pages |
DELETE | /v1/account | Verified | Delete account and all data |
POST | /v1/images | Verified | Upload an image (stored at original size) |
POST | /v1/images/og | Verified | Upload an OG/featured image (resized to 1200x630) |
POST | /v1/favicon | Verified | Upload a custom favicon (PNG/ICO/SVG, max 512 KB) |
POST | /v1/favicon/reset | Verified | Reset favicon to auto-generated |
POST | /v1/import | Verified | Import posts (multipart upload) |
GET | /v1/export | Verified | Export posts (?format=whiz|jekyll|hugo|ghost|wordpress|bearblog|markdown) |
POST | /v1/preview | Verified | Preview markdown as HTML |
GET | /v1/saved-themes | Verified | List saved themes |
POST | /v1/saved-themes | Verified | Save a theme configuration |
DELETE | /v1/saved-themes/:id | Verified | Delete a saved theme |
POST | /v1/saved-themes/:id/apply | Verified | Apply a saved theme to live blog |
GET | /v1/webhooks | Verified | List outbound webhooks |
POST | /v1/webhooks | Verified | Create an outbound webhook |
GET | /v1/webhooks/:id | Verified | Get webhook details |
PUT | /v1/webhooks/:id | Verified | Update webhook configuration |
DELETE | /v1/webhooks/:id | Verified | Delete a webhook |
POST | /v1/webhooks/:id/regenerate-secret | Verified | Regenerate webhook signing secret |
GET | /v1/webhooks/:id/deliveries | Verified | List recent webhook deliveries |
POST | /v1/webhooks/:id/test | Verified | Send a test ping event |
GET | /health | Public | Health check |
Pages
Posts support a post_type field: "post" (default) or "page". Pages are standalone content (e.g., About, Contact) that don't appear in the blog index or RSS feed.
- Create a page:
POST /v1/postswith"post_type": "page"in the body - List pages:
GET /v1/posts?type=page - List posts only:
GET /v1/posts?type=post(default)
Pages render at /{slug} on the public blog just like posts, but are excluded from the index, RSS feed, and tag listings.
Rate Limiting
The signup endpoint is rate-limited to 5 requests per minute per IP address. Other endpoints are not currently rate-limited but may be in the future.
Error Format
Errors return an appropriate HTTP status code with a JSON body:
json
{
"error": "email already registered"
}Common status codes:
| Code | Meaning |
|---|---|
400 | Invalid request body or parameters |
401 | Missing or invalid API key |
403 | Email not verified (for verified-only endpoints) |
404 | Resource not found |
429 | Rate limit exceeded |
500 | Internal server error |
Examples
Create a post
bash
curl -X POST https://api.whiz.pub/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "My First Post",
"slug": "my-first-post",
"content": "Hello, world! This is **markdown**.",
"tags": ["intro", "blogging"],
"status": "published",
"summary": "A short excerpt for the index and RSS feed.",
"featured_image": "https://example.com/social.jpg",
"pinned": false,
"date": "2025-01-15T10:30:00Z",
"metadata": {"series": "Getting Started", "episode": 1}
}'The post endpoint performs an upsert — if a post with the given slug already exists, it is updated.
Optional post fields:
summary: custom excerpt. If omitted, whiz generates one from the content.featured_image: HTTPS image URL for post-level social previews.pinned: when true, the post appears before regular posts on the public index.date: RFC3339 timestamp to override the publication date (e.g.2025-01-15T10:30:00Z). Use to backdate or forward-date posts. Controls sorting order, display date, and RSS/sitemap timestamps. Defaults to the current time when omitted.metadata: arbitrary JSON object (max 16 KB) stored with the post. Returned in all API responses, MCP tool outputs, and CLI. Also rendered in the post's JSON-LD structured data on the public blog. Useful for custom fields, integrations, CMS extensions, or agent-specific data.
List posts
bash
curl https://api.whiz.pub/v1/posts?limit=10&offset=0 \
-H "Authorization: Bearer YOUR_API_KEY"Query parameters:
| Parameter | Type | Description |
|---|---|---|
limit | int | Max results per page (default 20) |
offset | int | Pagination offset (default 0) |
tag | string | Filter by tag name |
status | string | Filter by status: draft or published |
type | string | Post type: post (default) or page |
The response is a wrapped object with the posts array and total count:
json
{
"posts": [...],
"total": 43
}All listing endpoints now return a total count alongside the results, enabling clients to implement pagination.
Get a single post
bash
curl https://api.whiz.pub/v1/posts/my-first-post \
-H "Authorization: Bearer YOUR_API_KEY"Public blogs also expose reader-facing discovery endpoints:
/rss.xml: RSS feed for published posts./tag/{tag}: HTML index of published posts with a matching tag.
Delete a post
bash
curl -X DELETE https://api.whiz.pub/v1/posts/my-first-post \
-H "Authorization: Bearer YOUR_API_KEY"Upload an image
Upload an image for use in blog posts (stored at original size):
bash
curl -X POST https://api.whiz.pub/v1/images \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "image=@photo.jpg"Returns {"url": "https://..."}. Use the URL in markdown: .
Max file size: 3 MB. Accepted types: JPEG, PNG, GIF, WebP. SVG is not supported.
Upload an OG / featured image
Upload an image for use as an OG image or featured image. The server resizes it to 1200x630 and stores it as JPEG:
bash
curl -X POST https://api.whiz.pub/v1/images/og \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "image=@hero.png"Returns {"url": "https://..."}. Use the URL as featured_image on a post or as the site-wide og_image in SEO settings.
Max input size: 10 MB. Accepted types: JPEG, PNG, GIF, WebP.
Auto-generated OG images
When a post is published without a featured_image, whiz automatically generates a 1200x630 OG image using the blog's theme colors and the post title. Similarly, a site-level OG image is generated on signup using the blog name and description. Custom images uploaded via the dashboard or API always take priority.
Sign up
bash
curl -X POST https://api.whiz.pub/v1/signup \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"subdomain": "yourname"
}'A one-time verification code is sent to your email. Verify it to complete signup and receive your API key.
Log in
Request a one-time login code for an existing account:
bash
curl -X POST https://api.whiz.pub/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com"
}'Verify OTP
Submit the code from your email to authenticate and receive your API key:
bash
curl -X POST https://api.whiz.pub/v1/auth/verify-otp \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"code": "123456"
}'The response includes your API key. Use it in subsequent requests.
Saved Themes
List all saved themes:
bash
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.whiz.pub/v1/saved-themesSave the current theme configuration:
bash
curl -X POST https://api.whiz.pub/v1/saved-themes \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "My Dark Theme",
"theme_preset": "ocean",
"body_font": "inter"
}'Apply a saved theme to the live blog:
bash
curl -X POST https://api.whiz.pub/v1/saved-themes/THEME_ID/apply \
-H "Authorization: Bearer YOUR_API_KEY"Delete a saved theme:
bash
curl -X DELETE https://api.whiz.pub/v1/saved-themes/THEME_ID \
-H "Authorization: Bearer YOUR_API_KEY"Enable headless mode
bash
curl -X PUT https://api.whiz.pub/v1/headless \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'When headless mode is enabled, the blog's public pages (subdomain, sitemap, robots.txt, etc.) return 404. The API, CLI, and MCP continue to work normally. Your subdomain remains reserved. Headless mode cannot be enabled while a custom domain is configured — remove the domain first.
Dashboard
bash
curl https://api.whiz.pub/v1/dashboard \
-H "Authorization: Bearer YOUR_API_KEY"Returns per-tenant dashboard statistics:
json
{
"total_posts": 43,
"published_posts": 38,
"draft_posts": 5,
"total_pages": 3,
"total_tags": 12
}Update blog display settings
bash
curl -X PUT https://api.whiz.pub/v1/settings/blog \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"posts_per_page": 15}'| Field | Type | Description |
|---|---|---|
posts_per_page | int | Number of posts per page on the blog index (5-100, default 10) |
Controls pagination on the public blog index and tag pages.
Webhooks
whiz supports outbound webhooks that notify external URLs when content changes. Each webhook has a signing secret for HMAC-SHA256 signature verification.
Supported events: post.created, post.updated, post.deleted, page.created, page.updated, page.deleted
Limits: 3 webhooks per tenant (10 for donors). Last 5 deliveries are stored per webhook.
Create a webhook
bash
curl -X POST https://api.whiz.pub/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhook",
"events": ["post.created", "post.updated", "post.deleted"],
"description": "My custom UI"
}'The response includes the signing secret (shown only once). Save it to verify webhook signatures.
List webhooks
bash
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.whiz.pub/v1/webhooksDelete a webhook
bash
curl -X DELETE https://api.whiz.pub/v1/webhooks/WEBHOOK_ID \
-H "Authorization: Bearer YOUR_API_KEY"View delivery history
bash
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.whiz.pub/v1/webhooks/WEBHOOK_ID/deliveriesSend a test event
bash
curl -X POST https://api.whiz.pub/v1/webhooks/WEBHOOK_ID/test \
-H "Authorization: Bearer YOUR_API_KEY"Webhook payload format
Each delivery sends a POST request with the following JSON body:
json
{
"event": "post.created",
"timestamp": "2026-05-15T12:00:00Z",
"data": {
"slug": "my-post",
"title": "My Post",
"status": "published",
"post_type": "post",
"tags": ["go", "web"]
}
}Verifying signatures
Each request includes these headers:
| Header | Description |
|---|---|
X-Whiz-Event | Event type (e.g. post.created) |
X-Whiz-Signature | HMAC-SHA256 signature: sha256=<hex> |
X-Whiz-Timestamp | Unix timestamp used in signature |
X-Whiz-Delivery | Unique delivery ID |
To verify: compute HMAC-SHA256(secret, timestamp + "." + raw_body) and compare with the signature header.