In brief
From this page’s summary fields, verified 2026-10-29. Sources in each section.- Authentication (details in section Authentication)
- API key, Session login, OAuth 2.0 (PKCE), Personal token
- Rate limit (details in section Limits & quirks)
- Studio API 500 req/min per IP, MCP 3,000/min (defaults, configurable); Datahub: none documented
- Webhooks (details in section Events & webhooks)
- Datahub Webhooks (Enterprise): UI-configured, custom headers, no signature, one attempt
- Pagination (details in section At a glance)
- GraphQL first/after offset; Studio page/pageSize; Simple REST page_cursor (search_after)
- API spec (details in section At a glance)
- OpenAPI 3.1 for Studio API on GitHub (POCL, not archived); GraphQL schema per endpoint
Scope: the APIs that expose Pimcore assets, Platform Version 2026.3. Pimcore is self-hosted or runs on Pimcore PaaS. Every installation is its own server with no shared multi-tenant host, so {host} below is the customer's Pimcore domain. Several surfaces exist side by side, each with its own authentication. No authenticated call was made for this page.
| Surface | Style | Edition | Intended for |
|---|---|---|---|
| Datahub GraphQL | GraphQL, one endpoint per configuration | Core (all editions) | Integrations and front ends S2 S62 |
| Datahub Simple REST | REST, read-only, served from the search index | Enterprise | Fast catalogue and asset delivery S2 S69 |
| Studio Backend API | REST/JSON, OpenAPI 3.1 | Core | The API behind the Pimcore Studio UI S59 |
| WebDAV | WebDAV | Core | Mounting the asset tree S31 |
| Datahub Webhooks | Outbound HTTP | Enterprise | Event push to other systems S73 |
| MCP endpoints | MCP (streamable HTTP) | Experimental; Simple REST MCP needs Enterprise | AI agents S72 S55 |
| PHP API | In-process PHP | Core | Custom bundles, importers, commands S32 |
At a glance
https://{host}/pimcore-graphql-webservices/{configName} (route can be overridden) S62. Simple REST: https://{host}/pimcore-datahub-webservices/simplerest/…, Swagger UI at /pimcore-datahub-webservices/simplerest/swagger S70. Studio API: https://{host}/pimcore-studio/api/… S60. WebDAV: https://{host}/asset/webdav S31. MCP: https://{host}/pimcore-mcp/… and https://{host}/pimcore-datahub-webservices/simplerest-mcp S56 S72. OAuth: https://{host}/pimcore-oauth/authorize, /pimcore-oauth/token S57/admin/* controllers removed in 2026.1 S9pmcp_ tokens or the Studio session S56. Embedded OAuth 2.1 server (experimental, off by default): authorization code + PKCE S256 only, no client-credentials grant S57. WebDAV: Pimcore user credentials S31mcp:read/mcp:write are "consent labels" only; the user's own permissions decide S56. Tokens are bound to one resource (audience) S57/pimcore-studio/api/docs/json (Swagger UI at /pimcore-studio/api/docs in dev) S59. A copy (info.version 2026.2, 683 paths, 815 operations) is committed to the public studio-ui-bundle repository S60. Simple REST: Swagger UI per instance S69. GraphQL: schema generated per endpoint, with introspection on by default S63. Not archived on DAM Wiki (POCL licence); see API spec downloadsfirst (limit) and after (offset), totalCount S64 S66. Studio API: page and pageSize query parameters S60. Simple REST: opaque page_cursor (also in the Link header). It switches to search_after beyond max_results_window (10,000 default), so deep paging works; MCP page size 1–200, default 25 S71 S72Authentication
Datahub GraphQL (API key) S62 S63 S67
- In Studio, create a Datahub configuration of type GraphQL. Under Security Settings, click Generate Key; each click adds a key, so several keys can be valid at once.
- Select the workspaces (asset folders) and the create/read/update/delete rights the endpoint may use. With no workspace, nothing is accessible.
- Send the key with each request as an
apikeyheader, anX-API-Keyheader or an?apikey=query parameter. - Optional: disable introspection, or set what happens to related elements outside the workspace (fail the query, or null them out — the default).
Datahub Simple REST (API key or OAuth) S70
- Delivery Settings tab: define or generate an API key, sent as a bearer token in a header with every request. The same key secures the MCP endpoint.
- OAuth Access: allow chosen Pimcore users and roles to call the endpoint with tokens from the embedded OAuth 2.1 server. REST and MCP are separate audiences, so a token for one is refused by the other.
Studio Backend API (session) S60 S59
- POST
/pimcore-studio/api/loginwith credentials. With 2FA, the code follows on POST/pimcore-studio/api/login/2fa. POST/pimcore-studio/api/login/tokenlogs in with a user token; POST/pimcore-studio/api/logoutends the session. - The OpenAPI file declares no security scheme S60. Calls rely on the session cookie set at login. Real-time updates go through a Mercure hub (POST
/pimcore-studio/api/mercure/auth) S59 S60. - The API exists mainly to serve the Studio UI. Pimcore's Datahub docs separate the Studio API used by configuration panels from the endpoints meant for external systems S62 S70.
Embedded OAuth 2.1 authorization server (Studio Backend, experimental since 2026.3, off by default) S57 S11
- Discovery:
/.well-known/oauth-authorization-server(RFC 8414) and/.well-known/oauth-protected-resource{/path}(RFC 9728). - Flow:
/pimcore-oauth/authorizesends the user to a consent screen in Studio, then/pimcore-oauth/tokenexchanges the code for tokens (authorization_code and refresh_token grants). PKCE S256 is required from every client;plainis refused. - Clients: pre-registered in config, optional Dynamic Client Registration (
/pimcore-oauth/register, RFC 7591), or Client ID Metadata Documents. There is no client-credentials grant: tokens always act for a logged-in user. Machine access uses API keys or PATs instead. - The issuer must be the root of an origin; installations under a path prefix are not supported. The token and authorize endpoints have no rate limit.
MCP endpoints S56
- Stateless
pimcore_mcpfirewall on/pimcore-mcp/. It tries, in order: the Studio session cookie,Bearer pmcp_…per-chat tokens (minted by the Pimcore AI agent server, SHA-256 hashed at rest, sliding expiry),Bearer <JWT>from the OAuth server, then static personal access tokens declared per username in YAML. - Unauthenticated calls get 401. When OAuth is on, the response carries a
WWW-Authenticateheader pointing at the protected-resource metadata.
WebDAV: any Pimcore user, with that user's asset permissions S31.
Core resources
Studio Backend API paths below are relative to https://{host}. They come from the OpenAPI file (version 2026.2): 683 paths, 815 operations (406 GET, 225 POST, 91 DELETE, 85 PUT, 8 PATCH) in 66 tags. 377 of these operations belong to Enterprise or optional bundles, so the routes available depend on what is installed S60.
| Resource | Endpoints | Notes |
|---|---|---|
| Assets (Studio API) | GET/pimcore-studio/api/assets/{id} · PUT/pimcore-studio/api/assets/{id} · PATCH/pimcore-studio/api/assets · PATCH/pimcore-studio/api/assets/folder/{id} · DELETE/pimcore-studio/api/assets/batch-delete · POST/pimcore-studio/api/assets/{id}/clone/{parentId} · GET/pimcore-studio/api/assets/tree | Read, update, batch patch (by IDs or by folder + filters), clone, tree listing with page/pageSize/pqlQuery S60 |
| Uploads (Studio API) | POST/pimcore-studio/api/assets/add/{parentId} (multipart file) · POST/pimcore-studio/api/assets/add-zip/{parentId} · POST/pimcore-studio/api/assets/{id}/replace · GET|POST /pimcore-studio/api/assets/exists/{parentId} | Single upload, ZIP import, binary replacement, duplicate check S60 |
| Renditions / downloads (Studio API) | GET/pimcore-studio/api/assets/{id}/download · …/image/download/thumbnail/{thumbnailName} · …/image/download/format/{format} · …/image/stream/dynamic · …/video/stream/{thumbnailName} · …/video/thumbnail/{thumbnailName}/status · …/document/stream/pdf-preview · POST/pimcore-studio/api/assets/export/zip/asset | Original, named/dynamic thumbnails, video transcodes and status, PDF previews, ZIP jobs S60 |
| Thumbnail configs (Studio API) | GET|POST /pimcore-studio/api/thumbnails/image/config… · …/thumbnails/video/config… | CRUD on image and video pipelines S60 |
| Metadata (Studio API) | GET/pimcore-studio/api/assets/{id}/custom-metadata · GET/pimcore-studio/api/metadata/asset · POST|PUT|DELETE /pimcore-studio/api/metadata/predefined… | Custom metadata, predefined metadata definitions S60 |
| Metadata schema (Enterprise) | …/pimcore-studio/api/bundle/amdcd/configs… (list, CRUD, import/export) | Asset Metadata Class Definitions S60 S42 |
| Search (Studio API) | GET/pimcore-studio/api/search · POST/pimcore-studio/api/search/assets · POST/pimcore-studio/api/assets/grid · …/search/saved/configuration… | Full-text and PQL search through the Generic Data Index, grid queries, saved searches S60 S43 |
| Folders & tree | POST/pimcore-studio/api/elements/{elementType}/folder/{parentId} · GET/pimcore-studio/api/elements/{elementType}/path · GET/pimcore-studio/api/assets/tree | Folders are the main organising structure S60 |
| Tags | GET|POST|PUT|DELETE /pimcore-studio/api/tags… · POST/pimcore-studio/api/tags/assign/{elementType}/{id}/{tagId} · POST/pimcore-studio/api/tags/batch/{operation}/{elementType}/{id} | Tag tree and assignment, batch on children S60 |
| Versions | GET/pimcore-studio/api/versions/{elementType}/{id} · GET/pimcore-studio/api/versions/{id}/asset/download · POST/pimcore-studio/api/versions/{id} (publish) | Version history and restore S60 |
| Properties, notes, schedules | …/properties… · …/notes/{elementType}/{id} · …/schedules/{elementType}/{id} | Inheritable properties, Notes & Events, scheduled actions S60 |
| Dependencies & usage | GET/pimcore-studio/api/dependencies/{elementType}/{id} · GET/pimcore-studio/api/elements/usage/{elementType}/{id} · POST/pimcore-studio/api/elements/usage/replace/{elementType}/{id} | Where an asset is used; replace all references S60 |
| Workflows | GET/pimcore-studio/api/workflows/details · POST/pimcore-studio/api/workflows/action | Workflow state and transitions S60 |
| Users / roles | 28 User Management and 12 Role Management operations, e.g. GET/pimcore-studio/api/roles, GET|PUT|DELETE /pimcore-studio/api/role/{id}, and the matching /pimcore-studio/api/user… paths | Users, roles, permissions S60 |
| Rights / permissions | GET/pimcore-studio/api/elements/{elementType}/context-permissions/ · edit-lock endpoints | No dedicated usage-rights resource S60 |
| Portals & collections (Enterprise) | …/pimcore-studio/api/bundle/portal-engine/collection… (create, list, share, tree items) · …/wizard/create-portal | Portal Engine admin operations S60 |
| Direct Edit (Enterprise) | POST…/bundle/direct-edit/assets/{id}/generate-link · …/confirm-upload · …/resolve-conflict · GET…/status | Local-editing sessions S60 |
| Assets (GraphQL) | Queries getAsset(id), getAssetFolder(id), getAssetListing(ids, first, after, sortBy, sortOrder, filter); mutations createAsset, updateAsset, deleteAsset(id|fullpath) | Fields depend on the endpoint schema. Binary data is sent base64-encoded in input.data S64 S65 |
| Renditions (GraphQL) | fullpath(thumbnail: "name", format:, deferred:) on asset fields | Image and video thumbnails by configuration name S64 |
| Assets (Simple REST, Enterprise) | tree-items, search, get-element, download-asset under /pimcore-datahub-webservices/simplerest/ | Read-only. The first three answer from OpenSearch/Elasticsearch without hitting the database; download-asset streams the original or a configured thumbnail S69 S70 |
| Webhooks config (Enterprise) | GET|PUT /pimcore-studio/api/bundle/data-hub-webhooks/config/{name} · POST…/config/test-subscribers | Configuration through the Studio API; there is no public subscription API S60 |
Exact per-config Simple REST paths and parameters are documented in each instance's Swagger UI, which was not reachable without an instance S69.
Data model
- Elements: Assets, Data Objects and Documents are the three element types. Each element has an integer ID, a full path in its tree (
/folder/file.jpg), a type and timestamps S95 S60. - Asset types: image, video, audio, document, text, archive, folder and unknown (the default list in webhook schemas) S74. GET
/pimcore-studio/api/assets/typesreturns the installed list S60. - Metadata: a list of entries (name, input type, language, data), localizable, with fallback to the unlocalized value (e.g.
addMetadata("title", "input", "…", "en")) S32. The full list of core metadata types is not stated on that page: Unknown. Enterprise class definitions add structured schemas and more data types S42. Embedded EXIF/IPTC/XMP is exposed read-only S26. - Files & renditions: one binary per asset in Flysystem storage. Renditions ("thumbnails") are generated from named configurations, on demand or deferred, and stored in their own storage S33 S27.
- Taxonomy: hierarchical tags (ID, name, parentId, idPath), inheritable properties and folder paths S35.
- Relations: data objects link to assets through relation fields. Dependencies are tracked both ways S60 S95.
- Versions: serialized snapshots with optional notes S34 S32.
Search & querying
- PQL (Studio API
pqlQuery, Copilot filters): comparisons,LIKEwith*/?wildcards (case-insensitive),NULL/EMPTY, AND/OR with brackets, relation filters such asmain_image:Asset.type = "image", rawQUERY('…')S43. - GraphQL:
filtertakes a JSON condition ($like,$and,$or, …) in Pimcore's webservice filter syntax;sortBy/sortOrder;totalCountS66 S64. - Simple REST:
fulltext_search(OpenSearchsimple_query_string),query_string_queryfor field filters, legacy JSONfilter,order_by(string or JSON withunmapped_type), and aggregations for facets configured per endpoint. Withoutorder_by, results come by relevance (full-text) or bysystem.idS71 S70. - Max page size: Studio API: Not public (no maximum stated in the spec). Simple REST MCP tools clamp to 1–200 S72. Deep paging through
page_cursor/search_afterS71. - Semantic search through embeddings (Enterprise, experimental), behind a dedicated permission S11 S41.
Uploads & binaries
- Studio API:
multipart/form-dataupload with afilefield (and optionalassetType) to/pimcore-studio/api/assets/add/{parentId}. ZIP import and binary replacement have their own endpoints S60. Chunked or resumable upload: Not public (no such endpoint in the spec). - GraphQL:
createAsset/updateAssettake the file as base64 ininput.data. The parent must be in a workspace with create rights S65. - WebDAV:
PUT/GETthrough any WebDAV client S31. - Downloads: public assets and thumbnails are plain URLs served by the web server (with optional CDN prefixes). Protected folders need a custom controller S30 S33. Studio API download and stream endpoints need a session S60. Simple REST
download-assetonly hands out variants allowed by the endpoint configuration S70. - Presigned URLs: Not public (none documented).
- Server upload limits follow PHP settings (≥ 100 MB recommended) S36.
Events & webhooks
- Datahub Webhooks (Enterprise) S73 S74 S75 S76 S77:
- Events:
pimcore.asset.postAdd(POST),postUpdate(PUT),postDelete(DELETE),postUpdateFailure,postDeleteFailure, and the same for data objects and documents;workflow.entered,workflow.completed(PUT). - Configured in the Studio UI per Datahub configuration: asset types, workspaces, optional binary data (original or a thumbnail, base64 in
data64), subscriber URLs, custom headers (e.g. an auth header). A test button checks reachability. - Payload:
general(eventName, timestamp, subjectType, versionOnly) andsubject(id, path, type, mimeType…), plusworkflowDatafor workflow events. - Delivery goes through a Symfony Messenger queue and is attempted once: a subscriber that was down does not get the event later. Failures appear in the configuration's Logs tab. No payload signature is documented. Auto-saves never trigger webhooks.
- Events:
- Server-side events: Pimcore and Symfony event listeners (e.g. asset pre/post save) for custom code S74 S59.
- Real-time UI updates: Mercure server-sent events S59.
- Workflow Automation (Enterprise) exports n8n blueprints built from GraphQL and webhook configurations S79.
Limits & quirks
- Rate limits apply to the Studio API and MCP only: 500/min and 3,000/min per IP by default. Behind a proxy, trusted proxies must be configured or all users share one bucket. Multi-server setups need a shared cache (e.g. Redis) for the limiter S58.
- Assets are public by URL by default: an API permission model does not protect a file's direct URL unless protected folders are set up S30.
- GraphQL API keys in the query string are supported, so keys can end up in access logs. Header-based keys (
apikey,X-API-Key) are also accepted S62 S67. - "Skip Permission Check" disables workspace checks entirely for a GraphQL endpoint S63.
- Simple REST is eventually consistent: it serves the search index, so new configuration changes need re-indexing.
binaryDatalinks can point to variants no longer published until re-indexing. For SVGs, a non-rasterizing thumbnail exposes the original S70. - GraphQL output cache (off by default, 30 s default lifetime when on) can serve stale data S62.
- Datahub config storage: YAML files are only re-read in debug mode, so production changes must be deployed S68.
- OAuth server is experimental: configuration keys may change between minor versions S57.
- Studio API is shaped around the UI (grids, perspectives, widgets), declares no security scheme in OpenAPI, and depends on Mercure and the Generic Data Index S60 S59.
- Enterprise source is private: Simple REST, Webhooks, Portal Engine, Direct Edit and Copilot repositories are not public on GitHub S90.
SDKs, tools & code samples
| Tool | Language | Status | Notes |
|---|---|---|---|
| Pimcore PHP API | PHP (in-process) | Official, current | Pimcore\Model\Asset, listings, metadata, tags S32 S35 |
| Studio UI SDK | TypeScript/React | Official | Plugin SDK with RTK Query clients generated from the OpenAPI file S60 |
| GraphQL Playground / Explorer | Web | Official | Opened from each Datahub configuration S62 |
| Swagger UI (Studio, Simple REST) | Web | Official | Per instance S59 S70 |
pimcore/skills | Markdown | Official, public repo | Agent skill for Pimcore developers documenting Studio Backend endpoints (OpenAPI translation keys, tags) S90 |
| Remote client SDKs (JS, Python, PHP HTTP client) | — | None official found | S90 |
| Direct Edit Client | Electron (Windows, macOS) | Official, Enterprise | Desktop helper S50 |
Changelog of the API
| Date | Change |
|---|---|
| 2026-09-29 | 2026.3: embedded OAuth 2.1 authorization server (experimental); Simple REST accepts OAuth tokens on REST and MCP; legacy /admin/bundle/* routes of ApplicationLogger, CustomReports and SEO removed; legacy portal frontend deprecated (removal 2027.1) S11 S13 |
| 2026-07-08 | 2026.2: optional published argument for Datahub data object mutations; CDN invalidation events; issues consolidated in platform-version S10 S13 |
| 2026-04-08 | 2026.1: Admin UI Classic and all classic admin controllers removed (Studio API only); Datahub adapters move to pipeline-based schemas (legacy read-only, removal 2027.1); unified 2026.1.x module versioning; PHP 8.4+, Symfony 7 S9 S12 |
| 2025-12-09 | 2025.4 (LTS): experimental MCP server support S8 S13 |
| 2025-04-30 | 2025.1 (Pimcore 12): POCL licence; product registration required; Datahub SQL condition field and merge operator removed; timezone on date fields S6 S13 |