Package Manager
Endpoints for managing Grav packages (plugins and themes) via the GPM, including installation, removal, updates, and repository search.
Endpoints for managing Grav packages (plugins and themes) via the GPM, including installation, removal, updates, and repository search.
List Plugins
GET
/gpm/plugins
List all installed plugins with enablement flags, update status, and whether each plugin is installed via a symlink (important for upgrade gating — symlinked packages should not be overwritten).
JSON
{"data": [{"slug": "admin2", "name": "Admin2", "version": "3.0.0-beta.1", "enabled": true, "is_symlink": false, "updatable": false}]}
Response Codes
200
Plugins returned.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
Get Plugin
GET
/gpm/plugins/{slug}
Get details for a single installed plugin, including `enabled`, `updatable`, `installed_version`, `available_version`, and the `is_symlink` flag.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | The plugin slug. |
JSON
{"data": {"slug": "simplesearch", "name": "SimpleSearch", "enabled": true, "is_symlink": false, "installed_version": "2.3.0", "available_version": "2.4.0", "updatable": true}}
Response Codes
200
Plugin returned.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
404
Plugin not found.
Install Package
POST
/gpm/install
Install a plugin or theme from the GPM repository.
Parameters
| Name | Type | Description |
|---|---|---|
| package required | string | Package slug to install |
| type required | string | Package type: plugin or theme |
| license optional | string | License key for premium packages |
JSON
{"package": "sitemap", "type": "plugin"}
Response Codes
201
Package installed
401
Unauthorized
422
Validation error (package not found or install failed)
Remove Package
POST
/gpm/remove
Remove an installed package.
Parameters
| Name | Type | Description |
|---|---|---|
| package required | string | Package slug to remove |
JSON
{"package": "sitemap"}
Response Codes
204
Package removed
401
Unauthorized
404
Package not found
Check Updates
GET
/gpm/updates
Check for available updates across plugins, themes, and the Grav core. `total` counts Grav itself as well as plugin/theme updates. The `grav` object includes `is_symlink` so admin UIs can disable the core-upgrade action when Grav is symlinked.
Parameters
| Name | Type | Description |
|---|---|---|
| flush optional | boolean | Bypass cache and fetch fresh update data. |
JSON
{"data": {"total": 4, "grav": {"installed_version": "2.0.0-beta.1", "available_version": "2.0.0-beta.2", "updatable": true, "is_symlink": false}, "plugins": [{"slug": "seo-magic", "installed_version": "1.9.0", "available_version": "1.10.0"}], "themes": []}}
Response Codes
200
Update summary returned.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
Search Repository
GET
/gpm/search
Search the GPM repository for plugins and themes.
Parameters
| Name | Type | Description |
|---|---|---|
| q required | string | Search query string |
| page optional | integer | Page number for pagination (default: 1) |
| per_page optional | integer | Number of results per page (default: 20, max: 100) |
Response Codes
200
Success
401
Unauthorized
List Themes
GET
/gpm/themes
List all installed themes with thumbnail URLs, update status, and the `is_symlink` flag.
JSON
{"data": [{"slug": "quark", "name": "Quark", "version": "2.0.0", "updatable": false, "is_symlink": false, "thumbnail": "/api/v1/thumbnails/quark-thumb.jpg"}]}
Response Codes
200
Themes returned.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
Get Theme
GET
/gpm/themes/{slug}
Get details for a specific installed theme, including screenshot URL, `updatable` status, and the `is_symlink` flag.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | The theme slug. |
JSON
{"data": {"slug": "quark", "name": "Quark", "version": "2.0.0", "updatable": false, "is_symlink": false, "screenshot": "/api/v1/thumbnails/quark-screen.jpg"}}
Response Codes
200
Theme returned.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
404
Theme not installed.
Update Package
POST
/gpm/update
Update a specific installed plugin or theme to the latest version.
Parameters
| Name | Type | Description |
|---|---|---|
| package required | string | Package slug to update |
JSON
{"package": "admin"}
JSON
{"data": {"message": "Package 'admin' updated successfully.", "package": "admin"}}
Response Codes
200
Package updated
401
Unauthorized
422
Package not updatable or not installed
500
Update failed
Update All Packages
POST
/gpm/update-all
Update every updatable plugin and theme in one request. Each package is attempted independently — one failure does not abort the batch. Returns two arrays: `updated` (slugs that succeeded) and `failed` (objects with `package` and `error`). Fires `onApiBeforePackageUpdate` / `onApiPackageUpdated` for each package.
JSON
{"data": {"updated": ["simplesearch", "seo-magic"], "failed": [{"package": "broken-plugin", "error": "Dependency unmet"}]}}
Response Codes
200
Batch completed; per-package outcome in `updated[]` / `failed[]`.
401
Unauthorized.
403
Missing `api.gpm.write` permission.
Browse Repository Themes
GET
/gpm/repository/themes
List all themes available in the GPM repository with `installed` flag on each. Supports pagination and `q` text search. 502 if the repository is unreachable.
Parameters
| Name | Type | Description |
|---|---|---|
| q optional | string | Search query to filter themes (matches name / slug / description). |
| page optional | integer | Page number (default 1). |
| per_page optional | integer | Items per page (default from config; max 2000 so the install modal can fetch the full list). |
JSON
{"data": [{"slug": "quark", "name": "Quark", "description": "Modern theme", "installed": true}], "meta": {"total": 120, "page": 1, "per_page": 20}}
Response Codes
200
Repository themes returned.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
502
GPM repository unreachable.
Get README
GET
/gpm/plugins/{slug}/readme
Get the README.md content for an installed plugin or theme. Also available at /gpm/themes/{slug}/readme.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | The package slug |
JSON
{"data": {"content": "# My Plugin\n\nThis plugin does..."}}
Response Codes
200
Success
401
Unauthorized
404
Package or README not found
Get Changelog
GET
/gpm/plugins/{slug}/changelog
Get the CHANGELOG.md content for an installed plugin or theme. Also available at /gpm/themes/{slug}/changelog.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | The package slug |
JSON
{"data": {"content": "# v1.2.0\n## 01/15/2025\n\n* Added feature X..."}}
Response Codes
200
Success
401
Unauthorized
404
Package or changelog not found
Get Plugin Page
GET
/gpm/plugins/{slug}/page
Get the admin page definition for a plugin. Returns the page type, blueprint reference, data/save endpoints, and action buttons. Resolution order: 1) onApiPluginPageInfo event, 2) admin-next/pages/{slug}.yaml, 3) admin-next/pages/{slug}.js (inferred component mode).
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | The plugin slug |
JSON
{"data": {"id": "license-manager", "plugin": "license-manager", "title": "License Manager", "icon": "fa-key", "page_type": "blueprint", "blueprint": "licenses", "data_endpoint": "/licenses/form-data", "save_endpoint": "/licenses", "actions": [{"id": "save", "label": "Save", "icon": "fa-check", "primary": true}], "has_custom_component": false}}
Response Codes
200
Success
401
Unauthorized
404
No admin page found for plugin
Get Plugin Page Script
GET
/gpm/plugins/{slug}/page-script
Serve the page-level web component JavaScript file for a plugin. The file is loaded from admin-next/pages/{slug}.js within the plugin directory. Returned with Content-Type application/javascript and immutable cache headers.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | The plugin slug |
Response Codes
200
Success (JavaScript content)
401
Unauthorized
404
Page component not found for plugin
Upgrade Grav Core
POST
/gpm/upgrade
Self-upgrade the Grav core. Refuses to run when Grav is installed via symlink (typical dev/monorepo setups). Fires `onApiBeforeGravUpgrade` and `onApiGravUpgraded` around the upgrade.
JSON
{"data": {"message": "Grav upgraded successfully.", "previous_version": "2.0.0-beta.1", "new_version": "2.0.0-beta.2"}}
Response Codes
200
Core upgraded.
400
Grav is already at the latest version, or installed via symlink.
401
Unauthorized.
403
Missing `api.gpm.write` permission.
500
Upgrade failed mid-flight.
Direct Install
POST
/gpm/direct-install
Install a plugin or theme from a URL or uploaded zip — bypasses the GPM repository lookup. Accepts either a JSON body with `url`, or a multipart upload with a `file` field. Useful for private/unpublished packages, pre-release builds, or local development.
Parameters
| Name | Type | Description |
|---|---|---|
| url optional | string | URL of the package zip (mutually exclusive with `file`). |
| file optional | file | Uploaded zip file (multipart; mutually exclusive with `url`). |
JSON
{"url": "https://example.com/builds/my-plugin-1.0.0.zip"}
JSON
{"data": {"message": "Package installed successfully via direct install."}}
Response Codes
201
Package installed.
400
Neither `url` nor a valid `file` was provided.
401
Unauthorized.
403
Missing `api.gpm.write` permission.
500
Installation failed.
List Repository Plugins
GET
/gpm/repository/plugins
List all plugins available in the GPM repository, with `installed` flag on each. Supports pagination (`page`, `per_page` — capped at 2000 so the install modal can fetch the full list) and `q` text search. 502 if the repository is unreachable.
Parameters
| Name | Type | Description |
|---|---|---|
| page optional | integer | Page number (default 1). |
| per_page optional | integer | Items per page (default from config; max 2000). |
| q optional | string | Search filter matched against name / slug / description. |
JSON
{"data": [{"slug": "simplesearch", "name": "SimpleSearch", "version": "2.4.0", "installed": true, "installed_version": "2.3.0"}], "meta": {"total": 250, "page": 1, "per_page": 50}}
Response Codes
200
Repository plugins returned.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
502
GPM repository unreachable.
Get Repository Package
GET
/gpm/repository/{slug}
Get full repository details for a plugin or theme (whichever matches the slug), plus an `installed` flag.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | Package slug. |
JSON
{"data": {"slug": "simplesearch", "name": "SimpleSearch", "version": "2.4.0", "description": "...", "author": {"name": "Trilby Media"}, "installed": false}}
Response Codes
200
Package found.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
404
Package not found in the GPM repository.
Get Custom Field Script
GET
/gpm/plugins/{slug}/field/{type}
Serve the JavaScript web component for a plugin's custom blueprint field type. Also available under `/gpm/themes/{slug}/field/{type}` for theme-provided fields. Admin2 loads these on demand when rendering a blueprint that uses an unknown field type. Convention: the file lives at `admin-next/fields/{type}.js` inside the package. Response is served with `Content-Type: application/javascript`.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | Plugin (or theme) slug. |
| type required | string | Field type identifier (matches the `type:` value in the blueprint). |
Response Codes
200
JavaScript file served.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
404
Field component not found.
Get Report Script
GET
/gpm/plugins/{slug}/report-script/{reportId}
Serve the web component for a custom report shown on the Admin2 Reports page. Plugins ship the file at `admin-next/reports/{reportId}.js` and register the report via the `onApiGenerateReports` event. Admin2 loads the script only when the matching report is rendered.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | Plugin slug. |
| reportId required | string | Report identifier (matches the `id` from `onApiGenerateReports`). |
Response Codes
200
JavaScript file served.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
404
Report component not found.
Get Floating Widget Script
GET
/gpm/plugins/{slug}/widget-script
Serve the web component for a plugin-provided floating widget. Convention: the file lives at `admin-next/widgets/{slug}.js`. Registered via the `onApiFloatingWidgets` event and listed by `GET /floating-widgets`.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | Plugin slug. |
Response Codes
200
JavaScript file served.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
404
Widget component not found.
Get Context Panel Script
GET
/gpm/plugins/{slug}/panel-script
Serve the web component for a plugin-provided context panel (right-rail panel shown while editing pages or other content). Convention: the file lives at `admin-next/panels/{slug}.js`. Registered via the `onApiContextPanels` event and listed by `GET /context-panels`.
Parameters
| Name | Type | Description |
|---|---|---|
| slug required | string | Plugin slug. |
Response Codes
200
JavaScript file served.
401
Unauthorized.
403
Missing `api.gpm.read` permission.
404
Panel component not found.