API Overview
UnfoldCMS ships with a public REST API for headless content access. The API is versioned under /api/v1/, returns JSON, and is split into three audiences with separate authentication models.
Quick Start
curl https://your-site.com/api/v1/health
Response:
{
"success": true,
"message": "API is healthy",
"data": {
"status": "ok",
"api_version": "v1",
"cms_version": "1.1.0",
"time": "2026-05-26T15:00:00+00:00"
}
}
That's it. No API key. No setup. The /api/v1/health endpoint is the canary — if it returns 200, everything else is wired up.
Three Audiences, Three Auth Models
The API splits by URL prefix. The prefix tells you both what's available and what authentication is required.
| Prefix | Audience | Auth | Rate limit |
|---|---|---|---|
/api/v1/* |
Public readers (frontends, AI crawlers, RSS) | None | 60 req/min per IP |
/api/v1/me/* |
Authenticated users (mobile apps, SPAs) | Bearer token (Sanctum) | 120 req/min per user |
/api/v1/admin/* |
Admin/integration clients | Bearer token with admin ability |
30 req/min per user |
This split keeps contracts obvious. A public endpoint never needs auth. An admin endpoint always does. No header sniffing, no role-detection magic.
Response Envelope
Every JSON response uses the same envelope. Success:
{
"success": true,
"message": "Posts retrieved successfully",
"data": { /* the resource(s) */ },
"pagination": { /* only on list endpoints */
"current_page": 1,
"per_page": 12,
"total": 47,
"last_page": 4,
"from": 1,
"to": 12
}
}
Error:
{
"success": false,
"message": "Post not found",
"errors": {
"code": "NOT_FOUND"
}
}
The top-level errors.code value is a stable machine-readable identifier. Use it to branch in client code instead of parsing the human message.
Error Codes
| Code | HTTP | Meaning |
|---|---|---|
NOT_FOUND |
404 | Resource missing |
UNAUTHENTICATED |
401 | No valid bearer token |
INVALID_CREDENTIALS |
401 | Login failed |
ACCOUNT_BANNED |
403 | User is banned |
VALIDATION_ERROR |
422 | Request body failed validation |
REGISTRATION_DISABLED |
403 | Admin disabled signups |
MAINTENANCE_MODE |
503 | Site is in maintenance mode |
DELIVERY_FAILED |
502 | Webhook test ping failed |
Pagination
List endpoints accept ?page=N and ?per_page=M. Default per-page is 12, max is 100. The response includes a pagination object with current page, total, and total pages.
curl "https://your-site.com/api/v1/posts?page=2&per_page=20"
Filtering & Search
Public list endpoints accept query filters:
# Posts in a category
curl "https://your-site.com/api/v1/posts?category=cms"
# Posts matching a search term (min 2 chars)
curl "https://your-site.com/api/v1/posts?q=headless"
# Global search across posts + pages
curl "https://your-site.com/api/v1/search?q=nextjs"
Versioning
The API is versioned in the URL path. Today is v1. When v2 ships, it lives at /api/v2/* and v1 keeps working for at least 6 months with a Deprecation header.
This means: the API contract you build against today won't silently change underneath you.
What's NOT in v1
We could pretend we shipped everything. Here's the honest list of what's deliberately not yet available:
| Feature | Status |
|---|---|
| GraphQL endpoint | Roadmap |
| Real-time subscriptions (WebSocket/SSE) | Roadmap |
Official npm SDK packages (@unfoldcms/next, etc.) |
Roadmap |
| Multi-language content endpoints | Roadmap |
| Bulk import/export (CSV) | Roadmap |
| Admin UI for webhook management | Next minor |
| Admin UI for API key issuance | Next minor |
| Draft preview tokens | Roadmap |
If you need any of these for your use case, the JSON API today supports building them as middleware on your side. Tell us what you need.
Next Steps
- Authentication — how Sanctum tokens work
- Posts endpoint — fetch and manage blog content
- Webhooks — receive signed events when content changes
- Next.js guide — wire UnfoldCMS into a Next.js app