PagibleAI JSON REST API

Use PagibleAI's read-only Laravel JSON:API to deliver CMS pages to single-page applications, mobile apps, static builds and other services. You can fetch page content, files and optional navigation relationships as standard JSON:API documents.

The API is read-only. It exposes pages and a content schema endpoint that describes the page content, meta and config structures.

Install JSON:API

The PagibleAI meta-package includes JSON:API. Follow Install PagibleAI CMS or run:

composer require aimeos/pagible
php artisan cms:install
php artisan migrate

cms:install runs every package installer, including JSON:API. To add only JSON:API to an existing PagibleAI installation, run:

composer require aimeos/pagible-jsonapi
php artisan cms:install:jsonapi

The installer publishes the configuration, registers the cms server and adds the exception renderer. Set APP_URL to the public application URL so generated links use the correct scheme, host and port. See Configure PagibleAI CMS for shared application settings.

Quick start

Use the collection endpoint to find pages and the resource endpoint when you already know a page UUID:

GET https://example.com/cms/pages
GET https://example.com/cms/pages/{uuid}

Without a filter, the collection endpoint returns the root pages of the current tenant. This request selects the English page tagged root:

curl --get 'https://example.com/cms/pages' \
  --header 'Accept: application/vnd.api+json' \
  --data-urlencode 'filter[tag]=root' \
  --data-urlencode 'filter[lang]=en'

Replace example.com with your application's domain. A successful request returns 200 OK with the media type application/vnd.api+json.

Understand the response

Every response follows the same JSON:API structure:

  • meta.baseurl is the base URL for relative public file and preview paths.
  • data contains one pages resource or a collection of page resources.
  • links contains URLs supplied by the server. Collection responses provide pagination links.
  • relationships references navigation resources requested through include.
  • included contains those related resources as a flat list.

A shortened collection response looks like this:

{
  "meta": {
    "baseurl": "https://cdn.example.com/",
    "page": {
      "currentPage": 1,
      "lastPage": 1,
      "perPage": 15,
      "total": 1
    }
  },
  "jsonapi": {"version": "1.0"},
  "links": {
    "first": "https://example.com/cms/pages?page%5Bnumber%5D=1&page%5Bsize%5D=15",
    "last": "https://example.com/cms/pages?page%5Bnumber%5D=1&page%5Bsize%5D=15"
  },
  "data": [
    {
      "type": "pages",
      "id": "0198a4b2-3c5e-7f1a-8d2b-e4f6a8c0d2e4",
      "attributes": {
        "lang": "en",
        "path": "",
        "name": "Home",
        "title": "My website",
        "has": 6
      }
    }
  ]
}

has is the number of descendants in the page tree, not a boolean and not the number of resources returned by the current request.

Access, limits and errors

The API applies visibility and frontend access rules to page collections, individual pages and included navigation.

Visibility

  • Guests receive published public pages.
  • Authenticated frontend users can receive authentication-only pages and pages granted through Laravel Gate.
  • CMS users with page:view can receive the latest version, including drafts.
  • Missing or inaccessible pages return 404 Not Found.

Authentication and CORS

Same-origin sessions work with credentials: 'same-origin'. For a cross-origin frontend, allow its origin in the host application's CORS configuration. The JSON:API package does not open origins automatically.

Limits

Each IP address can make 60 requests per minute. Requests above that limit return 429 Too Many Requests.

Include paths have a default maximum depth of one. Increase CMS_JSONAPI_MAXDEPTH only when you need nested paths such as children.children.

Errors

Read the JSON:API error document before throwing a client-side error:

const response = await fetch('/cms/pages/not-a-uuid', {
  headers: {Accept: 'application/vnd.api+json'},
  credentials: 'same-origin',
});

const document = await response.json();

if (!response.ok) {
  const message = document.errors?.[0]?.detail
    ?? document.errors?.[0]?.title
    ?? `Request failed with ${response.status}`;
  throw new Error(message);
}

Content schema

GET /cms/schema (route name cms.schema) returns the registered content, meta and config definitions as a JSON Schema Draft 2020-12 document. Use it to validate page data, generate types or build editors for headless frontends.

curl 'https://example.com/cms/schema' \
  --header 'Accept: application/schema+json'

The response uses the application/schema+json media type. Its top-level properties contain one definition each for content, meta and config. Element types added by Composer extensions and tenant themes are included automatically, and standard formats, defaults, annotations and constraints are preserved.

The endpoint is read-only and shares the cms-jsonapi rate limit with the page endpoints.

Request logging and benchmarks

Request logging

Set CMS_JSONAPI_WATCH=true together with CMS_LOG_CHANNEL to write one structured cms.jsonapi log entry per JSON:API request. Each entry contains the action, duration_ms, domain, requested includes and tenant_id. Entries are sampled by CMS_WATCH_SAMPLE. Logging is disabled by default and a logging failure never breaks the request.

CMS_LOG_CHANNEL=daily
CMS_JSONAPI_WATCH=true

Benchmarks

cms:benchmark:jsonapi measures the database queries behind the JSON:API endpoints, such as page lists, page details, children, ancestors and lookups by path, domain, tag and language. Seed the benchmark data first:

php artisan cms:benchmark --seed
php artisan cms:benchmark:jsonapi --tries=100

Use --tenant (default benchmark) and --domain to select the data set. The command refuses to run in production unless you pass --force.

Continue with the endpoint guides

  • JSON:API Pages documents filters, pagination, sparse fieldsets, attributes, content, and files.
  • JSON:API Navigation shows how to request breadcrumbs, children, menus, parents, and subtrees.