Automation
Chinaski exposes a JSON REST API so scripts, cron jobs, and AI assistants can read your content, create and update it, dispatch builds, and run batch jobs: everything you’d normally click in the admin area, minus deletion. This page is the orientation for automating against it; endpoint-by-endpoint reference is elsewhere in the Reference section, and the AI-assistant surface has its own MCP page.
Authentication
Automated access uses API keys, created by an admin under Settings → API Keys. Each key is named, has its own expiry date (optional), and is either read or write scoped:
- Read keys can fetch but never modify content.
- Write keys can create and update, explicitly required for any POST/PUT call, regardless of what the handler would do.
- Requests identify themselves with an
X-API-Keyheader. Missing or expired keys get a 401; a read key attempting a write gets a 403.
API access can be switched off entirely from the admin API Keys tab; with it off, every API request answers 503 “API access is disabled”.
Rate limiting is per key, per 60 seconds, defaulting to 100 requests per minute (configurable in Settings). Exceeding it returns a 429 with a Retry-After header telling you how long to wait.
Every key use is recorded in the audit trail with the HTTP method and path, and the last-used timestamp is tracked per key, helpful for finding keys that should be retired.
What the API can do
- Read: published pages, posts, blocks, snippets, categories, documents, navigation, redirects, authors, custom fields, translation coverage and workflows, keyword search, content-gap reports, and all non-secret settings. Lists are paginated (
dataplus ametablock with total/page/limit/pages) and trimmed down unless you ask for full rows. - Create and update: POST/PUT for pages, posts, blocks, snippets, categories, documents, authors, and nav items, including
upsertvariants that create-or-update by slug and language, plus webhook configuration and settings writes. Secret settings values are encrypted on the way in, unknown keys are rejected per item, and webhook URL values are validated for safety. - Build: POST a trigger to rebuild the static site (answer reports dispatched / already-busy / missing), then GET build status for per-language progress: pages and posts done vs. total, current item, and error message.
- Deletion is not in the API: there are no DELETE endpoints; permanent or trash deletion happens in the admin UI. Scripts that need to retire content should publish/flag rather than delete, or do the deletion by hand.
Batch jobs
For heavy lifting, submit an asynchronous job instead of many single calls:
- Submit: POST
/api/jobswith a type (bulk_upsert_pages,bulk_upsert_posts, orbulk_create_blocks) and a non-emptyitemsarray. - Poll: GET
/api/jobs/:idreturns the job status, progress (total and done), and the result payload once finished.
Monitoring: GET /build/status-style status is also exposed; and GET /api/health is the unauthenticated health endpoint your uptime monitor can hit: it reports status, the count of published pages, the last build time, and whether a build is in progress, and flags a warning if there were pages published but never a build.
AI-assisted workflows
The built-in MCP server is the intended gateway for AI assistants like Claude Code: it launches locally as a JSON-RPC-over-stdio process, talks to this same REST API using an API key, and exposes higher-level tools on top, one-call page/post creation with blocks, content translation with automatic gap auditing, bulk import/upsert, orphan-block cleanup, and content-quality audits. Point it at your CMS URL and a write-capable API key and your assistant works directly against the API.
Good habits for scripts
- Give scripts their own named API keys so audit entries identify them distinctly, and set an expiry on keys that are temporary. Key usage updates
last_used_ataudited; clean up unused ones from the API Keys tab. - Treat the read/write split seriously: a key that only reads shouldn’t hold write permission “just in case”.
- Own secrets: settings fetched through the API never include secret values (SMTP password, webhook secrets are always omitted), and the write path encrypts new secret values properly.