Skip to content

Powered by Grav + Helios

Blueprints

Blueprints

Endpoints for retrieving blueprint schemas used for page templates, user accounts, groups, plugins, themes, configuration and permission definitions, plus GET /blueprint-files, which lists files for blueprint folder picker fields. Uploading and deleting files for blueprint file fields is covered...

Endpoints for retrieving blueprint schemas used for page templates, user accounts, groups, plugins, themes, configuration and permission definitions, plus GET /blueprint-files, which lists files for blueprint folder picker fields. Uploading and deleting files for blueprint file fields is covered under Media: POST /blueprint-upload and DELETE /blueprint-upload.

List Page Types

GET /blueprints/pages
List the page templates (blueprints) available for new pages, after the `onAdminPageTypes` / `onAdminModularPageTypes` hooks and the configured hidden types are applied. Requires `api.pages.read`.

Parameters

Name Type Description
modular optional boolean Query parameter: `true` (or `1` / `yes`) lists modular templates instead of regular page templates
JSON
{"data": [{"type": "default", "label": "Default"}, {"type": "blog", "label": "Blog"}, {"type": "post", "label": "Post"}]}

Response Codes

200 Success
401 Unauthorized
403 Missing `api.pages.read` permission

Get Page Blueprint

GET /blueprints/pages/{template}
Get the fully resolved blueprint schema for a page template, including inherited fields and imports. Requires `api.pages.read`. Fires `onApiBlueprintResolved` with `context: page` so plugins can adjust the serialized fields.

Parameters

Name Type Description
template required string The page template name (e.g. default, blog, post, or modular/hero for a modular template)
JSON
{"data": {"name": "default", "title": "Default", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "header.title", "type": "text", "label": "Title"}]}}

Response Codes

200 Success
401 Unauthorized
403 Missing `api.pages.read` permission
404 Template blueprint not found

Get User Blueprint

GET /blueprints/users
Get the user account blueprint schema for rendering the user edit form. Needs only `api.access`, since every signed-in user renders their own profile form with it. Fires `onApiBlueprintResolved` with `context: account`.
JSON
{"data": {"name": "account", "title": "Account", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "username", "type": "text", "label": "Username"}]}}

Response Codes

200 Success
401 Unauthorized
404 User blueprint not found

Get Permissions

GET /blueprints/users/permissions
Get all registered permission actions in the system, organized hierarchically with translated labels. Requires `api.users.read`. A `children` key appears only on actions that have child actions.
JSON
{"data": [{"name": "admin", "label": "Admin", "children": [{"name": "admin.login", "label": "Login"}]}]}

Response Codes

200 Success
401 Unauthorized
403 Missing `api.users.read` permission

Get Plugin Page Blueprint

GET /blueprints/plugins/{plugin}/pages/{pageId}
Get a custom page blueprint for a plugin. Requires `api.config.read`. Loads the YAML file from admin/blueprints/{pageId}.yaml within the plugin directory and returns it as a serialized blueprint with resolved fields. When that file is missing and `pageId` equals the plugin slug, the plugin's main `blueprints.yaml` is used instead. Fires `onApiBlueprintResolved` with `context: plugin-page`.

Parameters

Name Type Description
plugin required string The plugin slug
pageId required string The page blueprint identifier (matches the filename without extension)
JSON
{"data": {"name": "licenses", "title": "Licenses", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "licenses", "type": "array", "label": "Licenses"}]}}

Response Codes

200 Success
401 Unauthorized
403 Missing `api.config.read` permission
404 Plugin or page blueprint not found

Get Plugin Blueprint

GET /blueprints/plugins/{plugin}
Return a plugin's `blueprints.yaml` with fields resolved (labels translated, data options expanded). Requires `api.config.read`. Fires the `onApiBlueprintResolved` event with `context: plugin` so plugins can mutate the serialized fields (e.g., inject dynamic options).

Parameters

Name Type Description
plugin required string Plugin slug.
JSON
{"data": {"name": "simplesearch", "title": "SimpleSearch", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "enabled", "type": "toggle", "label": "Plugin status"}]}}

Response Codes

200 Blueprint returned.
401 Unauthorized.
403 Missing `api.config.read` permission.
404 Plugin or its `blueprints.yaml` not found.

Get Theme Blueprint

GET /blueprints/themes/{theme}
Return a theme's `blueprints.yaml` with resolved fields. Requires `api.config.read`. Fires `onApiBlueprintResolved` with `context: theme`.

Parameters

Name Type Description
theme required string Theme slug.
JSON
{"data": {"name": "quark", "title": "Quark", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "dropdown.enabled", "type": "toggle", "label": "Dropdown in navbar"}]}}

Response Codes

200 Blueprint returned.
401 Unauthorized.
403 Missing `api.config.read` permission.
404 Theme or its `blueprints.yaml` not found.

Get Config Blueprint

GET /blueprints/config/{scope}
Return the blueprint that describes a system/site config scope. Admin2 pairs this with `GET /config/{scope}` to render configuration forms. Looks up the blueprint via the `blueprints://` stream so plugin overrides (e.g. the admin plugin's `media.yaml`) are honored, then falls back to `system://blueprints/config/{scope}.yaml`.

Parameters

Name Type Description
scope required string One of the core scopes `system`, `site`, `media`, `security`, `scheduler`, `backups`, or a custom top-level config scope the site defines (for example `user/blueprints/config/<scope>.yaml`). Other system blueprints such as `streams` are refused.
JSON
{"data": {"name": "system", "title": "System Configuration", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "cache.enabled", "type": "toggle", "label": "Caching"}]}}

Response Codes

200 Blueprint returned.
401 Unauthorized.
403 Missing `api.config.read` permission.
404 Unknown scope, or blueprint file not found.

Resolve Data Options

GET /data/resolve
Resolve `data-options@: \Some\Class::method` directives used in blueprint field definitions (e.g., the list of page templates, the list of themes). Admin2 calls this when rendering a blueprint whose select/checkboxes field references a callable. Only `Class::method` callables on the approved data provider allowlist (`Blueprint::isSafeDynamicCall()`) are accepted — an exact-match allow-list prevents arbitrary code execution. Core's providers are pre-approved; plugins and themes register their own via `Blueprint::addAllowedDynamicCallable()` at startup. Results are normalized to `[{value, label}]` for select-compatible consumption.

Parameters

Name Type Description
callable required string Fully-qualified `\Class\Name::method` to invoke. Must be an approved data provider (on the core allowlist, or registered via `Blueprint::addAllowedDynamicCallable()`).
type optional string Extra arg passed when `callable` is `Grav\Common\Page\Pages::pageTypes` (`standard` / `modular`). Defaults to `standard`.
JSON
{"data": [{"value": "default", "label": "Default"}, {"value": "blog", "label": "Blog"}]}

Response Codes

200 Options returned (empty array if the method does not return an array).
401 Unauthorized.
403 Missing `api.pages.read` permission.
404 Class or method does not exist.
422 Missing/invalid `callable`, or callable is not an approved data provider, or not in `Class::method` format.

Get Group Blueprint

GET /blueprints/groups
Get the user group edit blueprint (`user/group.yaml`, resolved through the `blueprints://` stream so site overrides apply). Requires `api.users.read`. Fires `onApiBlueprintResolved` with `context: group`.
JSON
{"data": {"name": "group", "title": "Group", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "readableName", "type": "text", "label": "Display Name"}]}}

Response Codes

200 Success
401 Unauthorized
403 Missing `api.users.read` permission
404 Group blueprint not found

Get New Group Blueprint

GET /blueprints/groups/new
Get the user group creation blueprint (`user/group_new.yaml`, resolved through the `blueprints://` stream so site overrides apply). Requires `api.users.read`. Fires `onApiBlueprintResolved` with `context: group_new`.
JSON
{"data": {"name": "group_new", "title": "Add Group", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "groupname", "type": "text", "label": "Group Name"}]}}

Response Codes

200 Success
401 Unauthorized
403 Missing `api.users.read` permission
404 Group creation blueprint not found

Get Accounts Config Blueprint

GET /blueprints/config/accounts
Get the Flex accounts configuration blueprint, the form behind the Configuration tab of the Users page. Requires `api.config.read`. Built with the same Flex directory blueprint classic admin uses, so it includes the shared Caching tab alongside the user-accounts settings. Pair it with `GET /config/accounts`. Fires `onApiBlueprintResolved` with `context: config` and `template: accounts`.
JSON
{"data": {"name": "accounts", "title": "Accounts Configuration", "type": null, "child_type": null, "validation": "loose", "fields": [{"name": "object.cache.index.enabled", "type": "toggle", "label": "Enable Index Caching"}]}}

Response Codes

200 Success
401 Unauthorized
403 Missing `api.config.read` permission
404 Flex Objects is not available, or the `user-accounts` Flex directory is not registered

List Blueprint Folder Files

GET /blueprint-files
List the files in the folder a blueprint field points at with its `folder:` option (filepicker, mediapicker), like classic admin's `taskGetFilesInFolder`. Requires `api.media.read`.

Parameters

Name Type Description
folder required string Query parameter: folder to list. A Grav stream (`user://media`, `theme://images`, `account://`), a `self@:subpath` token resolved against `scope`, or a path relative to `user/`
scope optional string Query parameter: blueprint owner used to resolve `self@:`. One of `plugins/<slug>`, `themes/<slug>`, `pages/<route>`, `users/<username>`
accept optional string Query parameter: comma-separated filter of extensions (`.pdf`, `*.jpg`) or MIME patterns (`image/*`). `*` matches everything
JSON
{"data": [{"filename": "logo.png", "url": "/user/themes/quark/images/logo.png", "type": "image/png", "size": 18432, "dimensions": {"width": 400, "height": 120}, "thumbnail_url": "/api/v1/thumbnails/3f2a9c1e4b5d6a7f8e9d0c1b2a394857.png", "modified": "2026-09-01T10:15:00+00:00"}], "meta": {"pagination": {"page": 1, "per_page": 1, "total": 1, "total_pages": 1}, "folder": "themes/quark/images", "scope": null, "exists": true}, "links": {"self": "/api/v1/blueprint-files?page=1&per_page=1"}}

Response Codes

200 Success. A folder that does not exist yet returns an empty list with `meta.exists: false`
401 Unauthorized
403 Missing `api.media.read` permission, or a `users/<username>` scope for another account without `api.users.write`
422 Missing `folder`, traversal or an unresolvable stream or scope, or a `@self` / `self@` page-media folder

The result uses the paginated envelope but is never actually paginated: every matching file comes back on page 1.

The page-media literals @self and self@ (with no subpath) are not handled here, since the client already has a page's media from GET /pages/{route}/media. They return a standard 422 validation error whose errors entry for folder carries the message PAGE_MEDIA_ONLY:

JSON
{"status": 422, "title": "Unprocessable Entity", "detail": "Use /pages/{route}/media for @self / self@ folders.", "errors": [{"field": "folder", "message": "PAGE_MEDIA_ONLY"}]}