API Surfaces
The API is versioned under /api/v1. It has five surfaces with different access rules.
| Surface | Base path | Access |
|---|---|---|
| Public read API | /api/v1/public/* |
Unauthenticated, read-only for content, rate limited, edge cached |
| Authentication | /api/v1/auth/* |
Better Auth. Session cookie |
| Admin API | /api/v1/admin/* |
CMS-role session, allowed Origin, no writes for viewer |
| System | /api/v1/system/* |
Health, status, first-owner bootstrap, break-glass recovery |
| Plugin routes | /api/plugins/<id>/v1/* and /api/plugins/<id>/public/v1/* |
Admin routes need a session. Public plugin routes need none |
Only the public, authentication and public plugin surfaces are meant for a website. Never expose the admin API to a frontend. The same-origin proxy forwards only /api/v1/auth/*, /api/v1/public/* and /api/plugins/<id>/public/*.
Public read API
Section titled “Public read API”All responses are JSON (except media files). Only published content is returned, and a draft or unknown slug returns the same 404.
| Method and path | Returns |
|---|---|
GET /api/v1/public/{contentType} |
Published entries of a content type |
GET /api/v1/public/{contentType}/{slug} |
One published entry |
GET /api/v1/public/media/{id} |
Media metadata |
GET /api/v1/public/media/{id}/file |
The file |
GET /api/v1/public/media/folders/{slug} |
Items in a media folder |
GET /api/v1/public/global-variables |
Global variables as one map |
GET /api/v1/public/settings/{module} |
Structured settings: general, contact, social, navigation, footer, seo |
GET /api/v1/public/pages |
Published pages: id, route and title only |
GET /api/v1/public/pages/by-route?route=/about |
One published page with its block tree |
GET /api/v1/public/reusable-blocks/{id} |
A reusable block |
GET /api/v1/public/route-patterns |
{ contentTypeSlug, routePattern } pairs |
POST /api/v1/public/forms/{slug}/submissions |
Submit a form (JSON, or multipart for file fields) |
POST /api/v1/public/password-reset/request, /confirm |
Password reset |
POST /api/v1/public/recovery/redeem |
Redeem an Owner recovery code |
GET /api/v1/public/preview/{contentType}/{slug}?token=, /pages?route=&token= |
Signed draft preview |
curl https://your-cms-api.example.com/api/v1/public/blog-post/hello-worldContent responses are edge cached for 5 minutes and invalidated when content changes. Everything under /api/v1/public/* shares a 300-per-minute per-IP baseline limit. See Rate limiting.
Authentication routes
Section titled “Authentication routes”See Astro authentication. Auth is cookie-session based. There is no bearer-token mode.
Admin API
Section titled “Admin API”/api/v1/admin/* covers dashboard, content types, entries, entry folders, pages, templates, reusable blocks, media, media folders, forms, submissions, global variables, settings, structured settings, email, users, security, webhooks, plugins, cache, and the audit log. It is documented by the deployment’s own OpenAPI document, and is what the admin dashboard itself uses. It is not a stable integration surface for websites.
Plugin routes
Section titled “Plugin routes”Each enabled plugin mounts at /api/plugins/<id>/v1/* (session required) and, if it declares them, /api/plugins/<id>/public/v1/* (unauthenticated, same public rate limit). A disabled plugin’s routes return 404. Commerce’s storefront routes are in Commerce.
OpenAPI and reference UI
Section titled “OpenAPI and reference UI”GET /api/v1/openapi.json and GET /api/v1/docs (Scalar) describe every route that is registered with the OpenAPI layer, including admin and plugin routes’ request and response shapes but never data. They are enabled by default. Set API_DOCS_ENABLED = "false" in [vars] to make both return 404.
Health and status
Section titled “Health and status”GET /api/v1/health returns { status: "ok", version } after a D1 query. GET /api/v1/system/status reports emailConfigured and authSecretConfigured. Both are unauthenticated.
The full route list is in the API routes reference.