Skip to content
mxHeadless
REST API gateway for headless frontends on MODX 3. Resources, objects, OpenAPI, API keys, and OAuth
  1. Extras
  2. mxHeadless
  3. API

API overview

Base URL: {prefix}/v1, default /api/v1.

Live catalog on an installed site: GET /meta/endpoints and Swagger UI at /docs. Below are core routes from RoutesRegistrar and CoreEndpointBootstrap (package version 1.0.42). Extras may add their own via registerEndpoint.

Success envelope

json
{
  "data": {},
  "meta": {
    "total": 100,
    "count": 20,
    "limit": 20,
    "offset": 0,
    "has_more": true
  },
  "links": {
    "self": "/api/v1/resources?limit=20&offset=0",
    "next": "/api/v1/resources?limit=20&offset=20"
  }
}

On error the response follows RFC 9457 with no data/meta wrapper.

Meta and auth

MethodPathPublicScopePurpose
GET/yes-Discovery: version, capabilities
GET/healthyes-Health (DB). Available with kill switch
GET/schemayes-Schema of registered objects
GET/docsyes-Swagger UI (mxheadless_swagger_enabled)
GET/meta/endpointsyes-Live endpoint catalog
GET/meta/openapiyes-OpenAPI in envelope
GET/meta/openapi.jsonyes-Raw OpenAPI 3.0 JSON
POST/auth/tokenyes*-OAuth token. Works only when mxheadless_oauth_enabled

*The route is public, but the endpoint is disabled by setting until OAuth is turned on.

Resources and pages

MethodPathPublicScope
GET/resourcesyesresources.read
GET/resources/{id}yesresources.read
POST/resourcesnoresources.create
PUT, PATCH/resources/{id}noresources.update
DELETE/resources/{id}noresources.delete
GET/pages/{uri}yesresources.read

Public GET works for anonymous callers. API key or OAuth on a public GET still needs the listed scope.

Contexts

MethodPathPublicScope
GET/contextsnocontexts.read
GET/contexts/{key}nocontexts.read
GET/contexts/{key}/settingsnocontexts.read

{key} is the context key (web, mgr, …). Settings follow an allowlist.

Elements (read-only)

MethodPathPublicScope
GET/chunksnochunks.read
GET/chunks/{id}nochunks.read
GET/templatesnotemplates.read
GET/templates/{id}notemplates.read
GET/snippetsnosnippets.read
GET/snippets/{id}nosnippets.read
GET/tvsnotvs.read
GET/tvs/{id}notvs.read
GET/categoriesnocategories.read
GET/categories/{id}nocategories.read
GET/content_typesnocontent_types.read
GET/content_types/{id}nocontent_types.read

Generic objects

Only for names in ObjectRegistry (core + extras). Unregistered {name}404.

MethodPathPublicScope
GET/objects/{name}no{name}.read
GET/objects/{name}/{id}no{name}.read
POST/objects/{name}no{name}.create
PUT, PATCH/objects/{name}/{id}no{name}.update
DELETE/objects/{name}/{id}no{name}.delete

Example: object products → scopes products.read, products.create, …

Full scope list: Authorization.

Kill switch

When mxheadless_enabled=false, only GET / and GET /health work. Everything else → 503 service_disabled.

Headers

HeaderRole
Authorization / X-API-KeyCredentials
X-ContextMODX context
X-CSRF-TokenSession mutations
Idempotency-KeyIdempotent POST
X-Request-IDCorrelation (if client sets it)

Rate limit response headers: X-RateLimit-Limit, Remaining, Reset.

Further by group