API Reference
All routes below are injected by @caretcms/core when you add caret() to your Astro config. The base path defaults to /api/cms and is configurable via apiBasePath.
Conventions
Section titled “Conventions”HTTP status codes
Section titled “HTTP status codes”| Status | Meaning |
|---|---|
200 | Success |
400 | Validation error (bad payload, prototype-pollution attempt, malformed field) |
401 | No session cookie or session expired |
403 | Missing CSRF header or insufficient permissions |
404 | Entry / collection not found |
409 | Optimistic-locking conflict (expectedRevision mismatch) |
500 | Server error |
| Route | Method | Purpose |
|---|---|---|
/api/cms/auth/login | POST | Log in with CARET_EDIT_PASSWORD |
/api/cms/auth/session | GET | Check whether the current editor session is authenticated |
/api/cms/auth/logout | POST | Clear the editor session |
POST /api/cms/auth/loginContent-Type: application/json
{ "password": "your-password" }Sets caret_session cookie on success (HttpOnly; SameSite=Lax; Secure on HTTPS).
GET /api/cms/auth/session
→ { "authenticated": true }Used by the inline editor bootstrap to decide whether to load editor JS.
POST /api/cms/auth/logoutx-caret-request: 1Clears the cookie. Returns { ok: true }.
Content
Section titled “Content”| Route | Method | Purpose |
|---|---|---|
/api/cms/entries | GET | List entries by collection |
/api/cms/schema | GET | Collection schema (registered, dynamic, or inferred) |
/api/cms/collections-metadata | GET | List metadata for all dynamic collections |
/api/cms/mutate | POST | Execute a mutation command |
/api/cms/history | GET / POST | Read or restore from revision history |
/api/cms/upload | POST | Upload a file (multipart/form-data) |
GET /api/cms/entries
Section titled “GET /api/cms/entries”GET /api/cms/entries?collection=pages
→ { "collection": "pages", "entries": [ { "id": "home", "data": { "headline": "..." }, "revision": 7 }, { "id": "about", "data": { "title": "..." }, "revision": 2 } ]}GET /api/cms/schema
Section titled “GET /api/cms/schema”GET /api/cms/schema?collection=pages
→ { "collection": "pages", "source": "registered", // or "dynamic" or "inferred" "schema": { /* JSON Schema */ }, "template": { /* default value */ }, "metadata": { // present when source is "dynamic" "label": "Pages", "icon": "📄", "creatable": true, "orderable": false }}See Schemas for the resolution order and supported features.
GET /api/cms/collections-metadata
Section titled “GET /api/cms/collections-metadata”GET /api/cms/collections-metadata
→ { "collections": [ { "id": "products", "label": "Products", "icon": "📦", "creatable": true, "orderable": true, "schema": { /* JSON Schema */ }, "created_at": 1714225200000, "updated_at": 1714225200000 } ]}POST /api/cms/mutate
Section titled “POST /api/cms/mutate”All writes go through here.
POST /api/cms/mutateContent-Type: application/jsonx-caret-request: 1Cookie: caret_session=...
{ "type": "save_field", "collection": "pages", "id": "home", "field": "headline", "value": "New" }
→ { "ok": true, "revision": 8 }Mutation command types
Section titled “Mutation command types”type | Purpose |
|---|---|
save_field | Update one field on one entry |
put_entry | Create or replace an entry’s full data |
delete_entry | Delete an entry |
reorder_entries | Reorder entries within a collection |
update_page_layout | Update section composer state |
create_collection | Create a dynamic collection (schema + metadata) |
delete_collection | Delete a dynamic collection (and all its entries + history) |
Common fields
Section titled “Common fields”| Field | Required by | Notes |
|---|---|---|
type | all | One of the values above |
collection | most | Lowercase, alphanumeric, - / _ |
id | most | Entry ID |
field | save_field | Dot-path (hero.title); rejects __proto__ etc. |
value | save_field, put_entry | New value |
expectedRevision | optional on writes | Pass for optimistic locking; returns 409 on mismatch |
Conflict response
Section titled “Conflict response”{ "error": "Revision conflict", "currentRevision": 9 }with HTTP 409. Re-read the entry, re-apply the user’s intent, and retry with the new currentRevision.
GET /api/cms/history
Section titled “GET /api/cms/history”GET /api/cms/history?collection=pages&id=home
→ { "history": [ { "ts": 1714225200000, "data": {...}, "action": "save_field" } ]}Capped at the last 50 revisions per entry.
POST /api/cms/history
Section titled “POST /api/cms/history”Restore an entry to a previous revision:
POST /api/cms/historyx-caret-request: 1Cookie: caret_session=...
{ "collection": "pages", "id": "home", "ts": 1714225200000 }The corresponding history entry is re-applied as a put_entry mutation.
POST /api/cms/upload
Section titled “POST /api/cms/upload”Multipart form with a single file field:
curl -X POST http://localhost:4321/api/cms/upload \ -H 'x-caret-request: 1' \ -H 'Cookie: caret_session=...' \ -F file=@./hero.jpg→ { "ok": true, "url": "/uploads/abc123.jpg", "size": 184320, "type": "image/jpeg" }Admin pages
Section titled “Admin pages”| Route | Purpose |
|---|---|
/admin | Login / redirect |
/admin/cms | Content Studio dashboard |
/admin/cms/[collection] | Collection list view |
/admin/cms/[collection]/[id] | Entry editor |
These mount at ${mountPath} (default /admin). Disable with enableAdmin: false.
Editor assets
Section titled “Editor assets”| Route | Purpose |
|---|---|
/__caret/editor.js | Inline editor runtime |
/__caret/editor.css | Editor styles |
Loaded automatically when an editor session cookie is present. Disable with enableInlineEditor: false.
Hosted cloud API Coming soon
Section titled “Hosted cloud API ”The hosted version of CaretCMS exposes a separate API surface for cloud mode clients. These routes are served by the hosted control plane, not by your Astro site.
| Route | Method | Purpose |
|---|---|---|
/content | GET | Fetch entries for a project |
/content/mutate | POST | Write mutations |
/content/schema | GET | Project schema |
/content/history | GET | Entry history |
/content/upload | POST | File upload |
/content/auth/login | POST | Editor login (Better Auth) |
/content/auth/logout | POST | Editor logout |
Cloud routes use bearer token authentication (Authorization: Bearer ...) instead of cookies. Project membership is verified on every request. These docs will be expanded once the hosted service launches.