Skip to main content
Halo’s Extension API provides a unified REST interface for managing all extension resources. Core extensions are built-in resource types that represent the fundamental entities in Halo CMS.

Overview

Core extensions follow a Kubernetes-inspired design pattern with:
  • Group-Version-Kind (GVK) based routing
  • Standard CRUD operations (Create, Read, Update, Delete, List)
  • Metadata management including labels, annotations, and versioning
  • Optimistic locking through version numbers
  • Soft deletion with finalizers support

API Endpoints

All extension APIs follow a consistent URL pattern:
/api/{version}/{plural}              # List and Create
/api/{version}/{plural}/{name}       # Get, Update, Delete
/apis/{group}/{version}/{plural}     # List and Create (grouped extensions)
/apis/{group}/{version}/{plural}/{name} # Get, Update, Delete (grouped extensions)

Authentication

All Extension APIs require authentication using one of the following methods:
  • Basic Auth: Username and password credentials
  • Bearer Token: JWT token obtained from login
See the Authentication guide for details.

Core Extension Types

Content Extensions

Content extensions are in the content.halo.run group.

Post

GVK: content.halo.run/v1alpha1/Post Represents a blog post with full content management capabilities.
spec.title
string
required
Post title
spec.slug
string
required
URL-friendly identifier
spec.owner
string
Username of the post owner
spec.deleted
boolean
default:"false"
Whether the post is in recycle bin
spec.publish
boolean
default:"false"
Whether to publish the post
spec.publishTime
string
ISO 8601 timestamp for scheduled publishing
spec.pinned
boolean
default:"false"
Pin post to top of list
spec.allowComment
boolean
default:"true"
Allow comments on this post
spec.visible
string
default:"PUBLIC"
Visibility level: PUBLIC, INTERNAL, or PRIVATE
spec.categories
array
Array of category names
spec.tags
array
Array of tag names
status.phase
string
Current phase: DRAFT, PENDING_APPROVAL, PUBLISHED, or FAILED
Public URL of the published post
status.excerpt
string
Auto-generated or custom excerpt
Example: List Posts
curl -X GET 'http://localhost:8091/apis/content.halo.run/v1alpha1/posts?page=0&size=20' \
  -H 'Authorization: Bearer <token>'
Example: Create Post
curl -X POST 'http://localhost:8091/apis/content.halo.run/v1alpha1/posts' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "apiVersion": "content.halo.run/v1alpha1",
    "kind": "Post",
    "metadata": {
      "name": "my-first-post"
    },
    "spec": {
      "title": "My First Post",
      "slug": "my-first-post",
      "deleted": false,
      "publish": false,
      "pinned": false,
      "allowComment": true,
      "visible": "PUBLIC",
      "priority": 0,
      "excerpt": {
        "autoGenerate": true
      }
    }
  }'

SinglePage

GVK: content.halo.run/v1alpha1/SinglePage Represents a standalone page (not part of the blog stream).
spec.title
string
required
Page title
spec.slug
string
required
URL-friendly identifier
spec.deleted
boolean
default:"false"
Whether the page is in recycle bin
spec.publish
boolean
default:"false"
Whether to publish the page
spec.visible
string
default:"PUBLIC"
Visibility level: PUBLIC, INTERNAL, or PRIVATE
Example: Get Single Page
curl -X GET 'http://localhost:8091/apis/content.halo.run/v1alpha1/singlepages/about' \
  -H 'Authorization: Bearer <token>'

Category

GVK: content.halo.run/v1alpha1/Category Represents a post category with hierarchical support.
spec.displayName
string
required
Display name of the category
spec.slug
string
required
URL-friendly identifier
spec.description
string
Category description
spec.priority
integer
default:"0"
Sort priority (higher values first)
spec.children
array
Array of child category names for hierarchical structure
status.postCount
integer
Total number of posts including subcategories
status.visiblePostCount
integer
Number of published and public posts

Tag

GVK: content.halo.run/v1alpha1/Tag Represents a post tag.
spec.displayName
string
required
Display name of the tag
spec.slug
string
required
URL-friendly identifier
spec.color
string
Color code for the tag (e.g., #FF5733)

Comment

GVK: content.halo.run/v1alpha1/Comment Represents a comment on a post or page.
spec.raw
string
required
Raw comment content (Markdown)
spec.content
string
required
Rendered HTML content
spec.owner
object
required
Comment owner information with kind, name, and displayName
spec.approved
boolean
default:"false"
Whether the comment is approved
spec.hidden
boolean
default:"false"
Whether the comment is hidden
spec.subjectRef
object
required
Reference to the subject (Post/SinglePage) with group, version, kind, and name

Core Extensions (v1alpha1)

These extensions use the default API group (empty string).

User

GVK: v1alpha1/User Represents a user account.
spec.displayName
string
required
User’s display name
spec.email
string
required
User’s email address
spec.avatar
string
Avatar image URL
spec.bio
string
User biography
spec.disabled
boolean
Whether the account is disabled
Example: List Users
curl -X GET 'http://localhost:8091/api/v1alpha1/users' \
  -H 'Authorization: Bearer <token>'

Role

GVK: v1alpha1/Role Defines permissions and access control.
rules
array
required
Array of policy rules defining permissions

RoleBinding

GVK: v1alpha1/RoleBinding Binds roles to users or groups.
subjects
array
required
Array of subjects (users/groups) to bind
roleRef
object
required
Reference to the role being bound

Setting

GVK: v1alpha1/Setting Stores system or plugin configuration settings.
spec.forms
array
Form configuration for setting UI

ConfigMap

GVK: v1alpha1/ConfigMap Stores configuration data as key-value pairs.
data
object
Key-value pairs of configuration data
Example: Get ConfigMap
curl -X GET 'http://localhost:8091/api/v1alpha1/configmaps/system-config' \
  -H 'Authorization: Bearer <token>'

Secret

GVK: v1alpha1/Secret Stores sensitive data like passwords and tokens.
stringData
object
Key-value pairs of secret data (write-only)
data
object
Base64-encoded secret data (read-only)
GVK: v1alpha1/Menu Defines a navigation menu.
spec.displayName
string
required
Menu display name
GVK: v1alpha1/MenuItem Represents an item in a menu.
spec.displayName
string
required
Display text for the menu item
spec.href
string
Link URL
spec.children
array
Array of child menu item names

Plugin Extensions

Plugin

GVK: plugin.halo.run/v1alpha1/Plugin Represents an installed plugin.
spec.displayName
string
Plugin display name
spec.version
string
required
Plugin version (semantic versioning)
spec.enabled
boolean
default:"false"
Whether the plugin is enabled
spec.author
object
Plugin author information with name and website
spec.homepage
string
Plugin homepage URL
status.phase
string
Plugin phase: PENDING, STARTING, STARTED, STOPPED, FAILED, etc.
status.loadLocation
string
File system path where the plugin is loaded from
Example: Update Plugin
curl -X PUT 'http://localhost:8091/apis/plugin.halo.run/v1alpha1/plugins/my-plugin' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "apiVersion": "plugin.halo.run/v1alpha1",
    "kind": "Plugin",
    "metadata": {
      "name": "my-plugin",
      "version": 1
    },
    "spec": {
      "enabled": true,
      "version": "1.0.0"
    }
  }'

Theme Extensions

Theme

GVK: theme.halo.run/v1alpha1/Theme Represents an installed theme.
spec.displayName
string
required
Theme display name
spec.version
string
Theme version
spec.author
object
required
Theme author with name and optional website
spec.customTemplates
object
Custom template definitions for posts, pages, and categories
status.phase
string
Theme phase: READY, FAILED, or UNKNOWN

Common Operations

List Extensions

List all resources of a given type with pagination, filtering, and sorting.
page
integer
default:"0"
Page number (0-based)
size
integer
default:"0"
Page size (0 means no pagination)
labelSelector
array
Filter by labels (e.g., hidden!=true)
fieldSelector
array
Filter by fields (e.g., metadata.name==my-post)
sort
array
Sort criteria (e.g., metadata.creationTimestamp,desc)
Example: List with Filters
curl -X GET 'http://localhost:8091/apis/content.halo.run/v1alpha1/posts?labelSelector=content.halo.run/published=true&sort=metadata.creationTimestamp,desc&page=0&size=10' \
  -H 'Authorization: Bearer <token>'

Get Extension

Retrieve a single resource by name.
GET /api/v1alpha1/{plural}/{name}
GET /apis/{group}/{version}/{plural}/{name}

Create Extension

Create a new resource.
POST /api/v1alpha1/{plural}
POST /apis/{group}/{version}/{plural}
Content-Type: application/json
The request body must include apiVersion, kind, metadata, and spec.

Update Extension

Update an existing resource (full replacement).
PUT /api/v1alpha1/{plural}/{name}
PUT /apis/{group}/{version}/{plural}/{name}
Content-Type: application/json
The metadata.version field is required and must match the current version to prevent concurrent update conflicts.

Patch Extension

Partially update a resource using JSON Patch (RFC 6902).
PATCH /api/v1alpha1/{plural}/{name}
PATCH /apis/{group}/{version}/{plural}/{name}
Content-Type: application/json-patch+json
Example: Patch Post
curl -X PATCH 'http://localhost:8091/apis/content.halo.run/v1alpha1/posts/my-post' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json-patch+json' \
  -d '[
    {
      "op": "replace",
      "path": "/spec/title",
      "value": "Updated Title"
    }
  ]'

Delete Extension

Delete a resource.
DELETE /api/v1alpha1/{plural}/{name}
DELETE /apis/{group}/{version}/{plural}/{name}
Resources with finalizers are soft-deleted (marked with deletionTimestamp) until all finalizers are removed.

Response Format

All responses follow a consistent structure:

Single Resource Response

{
  "apiVersion": "content.halo.run/v1alpha1",
  "kind": "Post",
  "metadata": {
    "name": "my-post",
    "version": 5,
    "creationTimestamp": "2024-01-15T10:30:00Z",
    "labels": {
      "content.halo.run/published": "true"
    }
  },
  "spec": {
    "title": "My Post",
    "slug": "my-post",
    "publish": true
  },
  "status": {
    "phase": "PUBLISHED",
    "permalink": "https://example.com/posts/my-post"
  }
}

List Response

{
  "page": 1,
  "size": 20,
  "total": 42,
  "totalPages": 3,
  "first": true,
  "last": false,
  "hasNext": true,
  "hasPrevious": false,
  "items": [
    { /* extension object */ },
    { /* extension object */ }
  ]
}

Error Handling

API errors return appropriate HTTP status codes with error details:
  • 400 Bad Request: Invalid request body or parameters
  • 401 Unauthorized: Missing or invalid authentication
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Resource not found
  • 409 Conflict: Version conflict (optimistic locking failure)
  • 422 Unprocessable Entity: Validation error
  • 500 Internal Server Error: Server error
Error Response:
{
  "status": 409,
  "error": "Conflict",
  "message": "The resource version has been modified",
  "path": "/apis/content.halo.run/v1alpha1/posts/my-post"
}

Next Steps

Build docs developers (and LLMs) love