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"

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