Api headless
Collection of skills for the ColdBox Platform and Claude Plugin
npx -y skills add ColdBox/skills --skill api-headlessAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use this skill when implementing headless ContentBox APIs, including REST endpoint design, JWT authentication flows, content CRUD, custom API handlers, and integration patterns for decoupled frontends.
SKILL.md
9.4 KB, as published. Nobody here has run it
ContentBox API & Headless Development (CFML)
Build headless and REST API integrations with ContentBox CMS using CFML. ContentBox provides a full REST API (v1) for managing all content types, enabling headless CMS architectures.
API Architecture
The API module lives at modules/contentbox/modules/contentbox-api/ with a nested v1 module at modules/contentbox/modules/contentbox-api/modules/contentbox-api-v1/.
API v1 Handlers
| Handler | Resource | Description |
|---|---|---|
auth.cfc | Authentication | JWT token generation and validation |
authors.cfc | Authors | Author CRUD operations |
categories.cfc | Categories | Category CRUD operations |
comments.cfc | Comments | Comment management |
contentStore.cfc | ContentStore | Key-value content blocks |
contentTemplates.cfc | Templates | Content template management |
entries.cfc | Entries | Blog entry CRUD operations |
menus.cfc | Menus | Menu management |
pages.cfc | Pages | Page CRUD operations |
relocations.cfc | Relocations | URL redirect management |
settings.cfc | Settings | Global settings API |
siteSettings.cfc | Site Settings | Site-specific settings |
sites.cfc | Sites | Multi-site management |
versions.cfc | Versions | Content versioning |
echo.cfc | Health Check | API health check / echo |
Base Handler Pattern
API handlers extend BaseHandler (which extends cborm.models.resources.BaseHandler):
<!--- handlers/api/v1/MyResource.cfc --->
<cfcomponent extends="contentbox.modules.contentbox-api.modules.contentbox-api-v1.handlers.baseHandler" singleton>
<!--- Inject the virtual entity service --->
<cfproperty name="ormService" inject="MyEntityService@contentbox">
<!--- Entity name (singular) --->
<cfset variables.entity = "MyEntity">
<!--- Default sort order --->
<cfset variables.sortOrder = "createdDate DESC">
<!--- Use native getOrFail() or getByIdOrSlugOrFail() --->
<cfset variables.useGetOrFail = true>
</cfcomponent>
This automatically provides: index, create, show, update, delete methods.
Authentication
JWT Authentication
The API uses JWT tokens for authentication:
// POST /api/v1/auth
// Body: { "username": "admin", "password": "secret" }
// Response: { "token": "eyJhbGciOiJIUzI1NiIs...", "expires": 3600 }
Using Tokens
Include the token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
API Endpoints
Entries
GET /api/v1/entries → List entries (paginated)
GET /api/v1/entries/:id → Get single entry
POST /api/v1/entries → Create entry
PUT /api/v1/entries/:id → Update entry
DELETE /api/v1/entries/:id → Delete entry
Query Parameters
| Parameter | Description |
|---|---|
page | Page number (default: 1) |
maxRows | Results per page |
sortOrder | Sort field and direction |
isDeleted | Include soft-deleted entries |
includes | Related entities to include |
excludes | Fields to exclude from response |
Pages
GET /api/v1/pages → List pages
GET /api/v1/pages/:id → Get single page (by ID or slug)
POST /api/v1/pages → Create page
PUT /api/v1/pages/:id → Update page
DELETE /api/v1/pages/:id → Delete page
Categories
GET /api/v1/categories → List categories
GET /api/v1/categories/:id → Get single category
POST /api/v1/categories → Create category
PUT /api/v1/categories/:id → Update category
DELETE /api/v1/categories/:id → Delete category
Authors
GET /api/v1/authors → List authors
GET /api/v1/authors/:id → Get single author
POST /api/v1/authors → Create author
PUT /api/v1/authors/:id → Update author
DELETE /api/v1/authors/:id → Delete author
ContentStore
GET /api/v1/contentstore → List all content store items
GET /api/v1/contentstore/:key → Get item by key
POST /api/v1/contentstore → Create item
PUT /api/v1/contentstore/:key → Update item
DELETE /api/v1/contentstore/:key → Delete item
Menus
GET /api/v1/menus → List menus
GET /api/v1/menus/:slug → Get menu by slug
POST /api/v1/menus → Create menu
PUT /api/v1/menus/:slug → Update menu
DELETE /api/v1/menus/:slug → Delete menu
Sites
GET /api/v1/sites → List sites
GET /api/v1/sites/:id → Get single site
POST /api/v1/sites → Create site
PUT /api/v1/sites/:id → Update site
DELETE /api/v1/sites/:id → Delete site
Response Format
List Response
{
"data": [
{ "id": "...", "title": "...", "slug": "...", ... }
],
"total": 100,
"page": 1,
"maxRows": 25
}
Single Resource Response
{
"data": {
"id": "...",
"title": "...",
"slug": "...",
"content": "...",
"author": { ... },
"categories": [ ... ],
...
}
}
Error Response
{
"error": true,
"message": "Resource not found",
"details": "..."
}
Creating Custom API Endpoints
Custom API Handler
<!--- handlers/api/v1/CustomResource.cfc --->
<cfcomponent extends="contentbox.modules.contentbox-api.modules.contentbox-api-v1.handlers.baseHandler" singleton>
<cfproperty name="ormService" inject="CustomEntityService@contentbox">
<cfset variables.entity = "CustomEntity">
<cfset variables.sortOrder = "createdDate DESC">
<!--- Override index for custom filtering --->
<cffunction name="index" access="public" returntype="void">
<cfargument name="event" type="any">
<cfargument name="rc" type="struct">
<cfargument name="prc" type="struct">
<!--- Custom filtering logic --->
<cfset prc.criteria = ormService.newCriteria()>
<cfif structKeyExists( rc, "status" )>
<cfset prc.criteria.isEq( "status", rc.status )>
</cfif>
<!--- Delegate to parent --->
<cfset super.index( event, rc, prc, prc.criteria )>
</cffunction>
<!--- Add custom action --->
<cffunction name="publish" access="public" returntype="void">
<cfargument name="event" type="any">
<cfargument name="rc" type="struct">
<cfargument name="prc" type="struct">
<cfset var entity = ormService.get( rc.id )>
<cfset entity.setStatus( "published" )>
<cfset ormService.save( entity )>
<cfset renderData(
type = "json",
data = { success : true, entity : entity.getMemento() },
statusCode = 200
)>
</cffunction>
</cfcomponent>
Custom API Routes
Register routes in your module's ModuleConfig.cfc:
<cfset routes = [
// RESTful resources
{ pattern = "/api/v1/custom", handler = "api/v1/customResource" },
{ pattern = "/api/v1/custom/:id", handler = "api/v1/customResource" },
// Custom actions
{ pattern = "/api/v1/custom/:id/publish", handler = "api/v1/customResource", action = "publish" }
]>
Headless CMS Usage
Frontend Integration
Use the API to build headless frontends:
// Fetch entries
const response = await fetch('/api/v1/entries?page=1&maxRows=10', {
headers: { 'Authorization': `Bearer ${token}` }
});
const { data, total, page } = await response.json();
// Fetch single page by slug
const pageResponse = await fetch('/api/v1/pages/my-page-slug', {
headers: { 'Authorization': `Bearer ${token}` }
});
const { data: page } = await pageResponse.json();
Content Rendering
The API returns content with all fields, including:
title,slug,content(HTML)publishedDate,createdDate,modifiedDateauthor(nested object)categories(array)customFields(if configured)featuredImage(media reference)
API Security
Firewall Rules
API routes are protected by cbSecurity rules. Configure in settings:
settings.cbsecurity = {
firewall : {
invalidAuthenticationEvent : "cbapi/auth/unauthorized",
defaultAuthenticationAction : "redirect",
invalidAuthorizationEvent : "cbapi/auth/forbidden",
defaultAuthorizationAction : "redirect"
}
};
Rate Limiting
The core RateLimiter@contentbox interceptor protects against brute-force attacks.
Best Practices
- Extend
baseHandler— get CRUD operations for free - Inject
ormService— use the correct virtual entity service - Use
variables.entity— set the singular entity name - Set
variables.sortOrder— define default sorting - Use
paramfor defaults — set safe defaults for query parameters - Override methods as needed — customize
index,show, etc. - Use
renderData()— for consistent JSON responses - Announce interception points — for extensibility
- Include related entities — use
includesparameter for nested data - Handle errors gracefully — return proper error responses
Engine Compatibility
This skill targets CFML engines (Lucee 5+, Adobe ColdFusion 2018+). For BoxLang-specific syntax and features, see the BoxLang variant of this skill.