Whoobe Docs

API Reference#

Overview of the HTTP APIs exposed by this monorepo's backend services, grouped by service and resource. Every endpoint returns/accepts JSON unless noted otherwise. Endpoints under /public/* and /preview/* (and /health, /dam-asset/*) require no authentication; everything else requires a valid wcms_session cookie (see Auth) and, in most cases, a specific permission. gateway's own /api/v1/gateway/resolve//submit are a third case: a published site (not an admin session) authenticates with a resolved gatewayBindingId and, optionally, a per-site API key — see docs/release/communication/api-gateway-security.md.

For exact request/response shapes, see the route handlers in each service's src/server.ts (or, for gateway, src/router.ts + src/admin-routes.ts/src/resolve-handler.ts/src/submit-handler.ts). A machine-readable companion spec covering every route on this page lives at docs/release/api/openapi.yaml — see its own section below for what it does and doesn't model.

Services#

Service Default port Base path prefix
core-api 3003 none (routes are top-level, e.g. /data-objects)
gateway 3001 mixed — /api/v1/gateway/* (admin + published-site), /public/*//api/internal/*//dam/* (proxies)
asset-processor 3002 /api/v1/*

core-api (port 3003)#

The main backend API: authentication, the PIM/MDM data model (Classes, Components, Data Objects), the CMS (Documents, Snippets, Whoobe One pages/templates/kits/websites/themes), mail, AI generation, Figma import, and Pimcore migration orchestration.

Auth#

Method & path Description
POST /auth/login Log in with email/password. Sets the session cookie, or returns { mfaRequired: true, mfaToken } if 2FA is enabled.
POST /auth/mfa/challenge Step 2 of a 2FA login: verify a TOTP code (or a recovery code) against a pending mfaToken and complete the session.
GET /auth/mfa/status Whether the current user has 2FA enabled.
POST /auth/mfa/setup Start 2FA enrollment; returns a TOTP secret + QR code.
POST /auth/mfa/verify-setup Confirm a TOTP code to finish enrollment; returns one-time recovery codes.
POST /auth/mfa/disable Disable 2FA (requires re-entering the password).
POST /auth/logout Revoke the current session and clear the cookie.
GET /auth/me Current user's id, email, display name, and effective permissions.
POST /auth/forgot-password Request a password-reset email.
POST /auth/reset-password Complete a password reset with the emailed token.
GET /auth/users List admin users.
POST /auth/users Create an admin user.
GET /auth/users/:id Get one admin user.
PATCH /auth/users/:id Update an admin user.
DELETE /auth/users/:id Delete an admin user.
POST /auth/users/:id/reset-password Force-reset another user's password (admin action).
GET /auth/roles List roles.
POST /auth/roles Create a role (name + permission set).
GET /auth/roles/:id Get one role.
PATCH /auth/roles/:id Update a role.
DELETE /auth/roles/:id Delete a role.
GET /auth/permissions List every permission key the system recognizes.

Documents & Snippets (legacy Pimcore-migrated content)#

Method & path Description
GET /documents List documents migrated from Pimcore.
GET /documents/:id Get one document.
PATCH /documents/:id Update a document's content.
GET /snippets List reusable content snippets (Whoobe Studio format - distinct from Whoobe One snippets below).
POST /snippets Create a snippet.
DELETE /snippets/:id Delete a snippet.

Whoobe One: Snippets#

Method & path Description
GET /whoobe-one/snippets List reusable block snippets (whoobe-one-spike editor format).
POST /whoobe-one/snippets Create a snippet.
GET /whoobe-one/snippets/:id Get one snippet.
GET /whoobe-one/snippets/:id/versions List the snippet's instant version history (up to the 10 most recent prior states).
GET /whoobe-one/snippets/:id/versions/:versionId Get one historical version's full node content.
POST /whoobe-one/snippets/:id/render Render a snippet's node tree to standalone email HTML.
PATCH /whoobe-one/snippets/:id Update a snippet in place. Snapshots the pre-update node into version history if it changed.
DELETE /whoobe-one/snippets/:id Delete a snippet.
PUT /whoobe-one/snippets/:id/thumbnail Set (or clear with null) the snippet thumbnail: an image data URL under 400k characters.
PUT /whoobe-one/snippets/:id/lock Lock or unlock a snippet ({ locked }). A locked snippet is not saved automatically: the editor's autosave skips it and PATCH /whoobe-one/snippets/:id with autosave: true answers 423. Manual saves are unaffected.

Whoobe One: Templates & Kits#

Method & path Description
GET /whoobe-one/templates List whole-page templates.
GET /whoobe-one/templates/:id Get one template.
POST /whoobe-one/templates Create a template (unique path).
PATCH /whoobe-one/templates/:id Update a template.
DELETE /whoobe-one/templates/:id Delete a template.
GET /whoobe-one/kits List named template collections ("kits").
GET /whoobe-one/kits/:id Get one kit.
POST /whoobe-one/kits Create a kit.
POST /whoobe-one/kits/:id/templates Append a template to an existing kit.
DELETE /whoobe-one/kits/:id Delete a kit.

Whoobe One: Pages#

Method & path Description
GET /whoobe-one/pages List real site pages, optionally filtered by websiteId.
GET /whoobe-one/pages/staged List Pimcore-migration staged pages awaiting review/promotion.
GET /whoobe-one/pages/staged/:id Get one staged page.
POST /whoobe-one/pages/staged/promote Promote all staged pages into the real pages table.
POST /whoobe-one/pages/staged/:id/promote Promote one staged page.
DELETE /whoobe-one/pages/staged/:id Discard one staged page without promoting it.
PUT /whoobe-one/pages/:id/thumbnail Set (or clear with null) the page thumbnail: an image data URL (webp/png/jpeg) under 400k characters. Used by the editor preview's "Capture thumbnail" (desktop crop, or the Mobile/Tablet device screen).
GET /whoobe-one/pages/:id Get one page.
GET /whoobe-one/pages/:id/versions List the page's instant version history (up to the 10 most recent prior states of its content).
GET /whoobe-one/pages/:id/versions/:versionId Get one historical version's full content tree.
GET /whoobe-one/pages/:id/layout Resolved website-template body slot (className/style) for this page's editor canvas.
POST /whoobe-one/pages/:id/render Render a page's node tree to standalone email HTML.
GET /whoobe-one/pages/:id/translations All locale variants of the same logical page.
POST /whoobe-one/pages/:id/translate AI-translate a page into a new locale, creating a draft in the same translation group.
POST /whoobe-one/pages Create a page. Validates/binds any Gateway content bindings before saving.
PATCH /whoobe-one/pages/:id Update a page. Snapshots the pre-update content into version history if it changed.
DELETE /whoobe-one/pages/:id Delete a page.

Whoobe One: Websites, Settings, PWA#

Method & path Description
GET /whoobe-one/websites List websites (domain + locale config a page tree belongs to).
POST /whoobe-one/websites Create a website.
POST /whoobe-one/websites/:id/gateway-api-key/regenerate Generate (or replace) this website's Gateway site API key. Plaintext is returned once, only a salted hash is stored.
DELETE /whoobe-one/websites/:id/gateway-api-key Clear this website's Gateway site API key.
GET /whoobe-one/settings/default-placeholder-image Get the org-wide default placeholder image used when an image element has no source.
PUT /whoobe-one/settings/default-placeholder-image Set the default placeholder image.
GET /whoobe-one/settings/strip-html-comments Get whether HTML comments are stripped from rendered output.
PUT /whoobe-one/settings/strip-html-comments Set the strip-HTML-comments setting.
GET /whoobe-one/settings/logging Get editor logging verbosity settings.
PUT /whoobe-one/settings/logging Set editor logging verbosity.
GET /whoobe-one/settings/autosave Get the org-wide default autosave enabled/interval settings.
PUT /whoobe-one/settings/autosave Set the org-wide default autosave settings.
GET /whoobe-one/settings/alpine-presets Get the catalog of Alpine presets: named sets of Alpine.js directives applied from the editor's Advanced > AlpineJS panel ({ presets: [{ name, description, directives }] }).
PUT /whoobe-one/settings/alpine-presets Replace the whole Alpine presets catalog ({ presets }); 400 with the reason when a name, a directive (x-..., @event, :attr) or a size limit is invalid, nothing is stored then.
GET /whoobe-one/settings/cdn-mirror Get the default CDN-mirroring settings for DAM assets.
PUT /whoobe-one/settings/cdn-mirror Set the default CDN-mirroring settings.
GET /whoobe-one/websites/:id Get one website.
PATCH /whoobe-one/websites/:id Update a website.
DELETE /whoobe-one/websites/:id Delete a website.
GET /whoobe-one/websites/:id/upload-settings The file-upload limits of a website's forms (settings.uploads: enabled, allowed file types, size, count, daily bytes, target folder), normalized, with the ceilings and the file types that can be allowed.
PUT /whoobe-one/websites/:id/upload-settings Save them. Only file types whose content can be checked are accepted (never html, svg, scripts, programs); numbers are held within the ceilings; the target folder is private unless a public one is explicitly allowed.
GET /whoobe-one/websites/:id/themes List themes available to this website (its settings.themes catalog).
POST /whoobe-one/websites/:id/themes Add a theme to this website's catalog.
PUT /whoobe-one/websites/:id/themes/:themeId Update one of this website's catalog themes.
DELETE /whoobe-one/websites/:id/themes/:themeId Remove a theme from this website's catalog.
GET /whoobe-one/themes/all List every website's themes in one call, for snippet/global editors with no single website context.
GET /whoobe-one/websites/:id/theme Get this website's currently active default theme.
PUT /whoobe-one/websites/:id/theme Set this website's active default theme.
POST /whoobe-one/websites/:id/generate-pwa Generate/update this website's installable PWA manifest + service worker config.

Themes (global catalog)#

Method & path Description
GET /whoobe-one/themes List all globally-defined themes (name, colors, fonts, custom styles/Tailwind classes).
POST /whoobe-one/themes Create a theme.
GET /whoobe-one/themes/:id Get one theme.
PUT /whoobe-one/themes/:id Update a theme.
DELETE /whoobe-one/themes/:id Delete a theme.

Website Templates (header/aside/main/footer/404 composition)#

Method & path Description
GET /whoobe-one/websites/:websiteId/templates List a website's layout templates.
POST /whoobe-one/websites/:websiteId/templates Create a layout template.
GET /whoobe-one/websites/:websiteId/templates/:id Get one layout template.
PATCH /whoobe-one/websites/:websiteId/templates/:id Update a layout template.
DELETE /whoobe-one/websites/:websiteId/templates/:id Delete a layout template.

Website Paths (menu/navigation tree)#

Method & path Description
GET /whoobe-one/website-paths List a website's menu/navigation entries.
POST /whoobe-one/website-paths Create a menu entry.
GET /whoobe-one/website-paths/:id Get one menu entry.
PATCH /whoobe-one/website-paths/:id Update a menu entry.
DELETE /whoobe-one/website-paths/:id Delete a menu entry.

Public site endpoints (no auth)#

Method & path Description
GET /public/pages/:locale/* Fetch a published page by locale + full path (static slug or dynamic pattern match), for SSR/rendering.
GET /public/page/* SEO-friendly page lookup with no locale in the URL - detects the website's rootPath from the first path segment.
GET /public/404/:websiteId Fetch a website's configured 404 page content.
GET /public/sitemap.xml Generated sitemap of all published, sitemap-included pages.
GET /public/robots.txt Generated robots.txt pointing at the sitemap.
GET /public/websites List websites (id + name only).
GET /public/websites/:id Get one website's public config (domains, locales, PWA config; secrets redacted).
GET /public/pages List a website's published pages (id/slug/title only), for static-export route generation.
GET /public/snippets/:id Get one Whoobe One snippet's node tree (public, for embedding on a published site).
GET /public/assets/:uuid Resolve a DAM asset's public URL by its stable uuid reference.
GET /public/dam/assets/mirror-status Whether CDN-mirrored copies exist for a batch of asset paths.
GET /public/apps/:websiteId List a website's kind: app pages, for the Capacitor mobile-app generator.
GET /public/search Full-text search (tsvector + pg_trgm) across published pages/objects/classes/assets.

PWA push#

Method & path Description
POST /pwa/subscribe Register a browser's push subscription for a website.
POST /pwa/send Send a push notification to a website's subscribers.

Data Classes (PIM/MDM class definitions)#

Method & path Description
GET /data-classes List all classes.
GET /data-classes/:id Get one class.
POST /data-classes Create a class (name, label, fields, optional view config).
PATCH /data-classes/:id Update a class. Renaming/retyping a field is blocked once objects of that class exist.
DELETE /data-classes/:id Delete a class. Blocked while any object of that class still exists.
GET /data-classes/:id/object-count How many objects the class has (used before emptying it).
POST /data-classes/:id/empty Delete every object of the class, keeping the class. The body must carry confirm equal to the class name; the action is logged and returns the number deleted.
GET /data-classes/:id/workflow Get the class's publishing workflow definition, if any.
PUT /data-classes/:id/workflow Create/replace the class's workflow (places + transitions).
DELETE /data-classes/:id/workflow Remove the class's workflow.

Data Components (reusable field-collection sub-schemas)#

Method & path Description
GET /data-components List all component types.
GET /data-components/:id Get one component type.
GET /data-components/:id/usage Whether any existing object references this component.
POST /data-components Create a component type.
PATCH /data-components/:id Update a component type. Renaming/retyping a field is blocked while it's in use.
DELETE /data-components/:id Delete a component type. Blocked while it's in use.

Migration Sources & Pimcore import#

Method & path Description
GET /migration-sources List configured migration sources (passwords never included).
POST /migration-sources Save a new source (DB connection + var/classes path).
PATCH /migration-sources/:id Update a source.
DELETE /migration-sources/:id Delete a source.
POST /migration-sources/:id/import-classes Import Pimcore class definitions into data-classes.
POST /migration-sources/:id/preview-classes Read the class definition files of the source and return the proposed fields of each class, without creating anything (the dashboard lets the user choose and map fields before importing).
POST /migration-sources/:id/import-objects Import one class's real object instances from the source MySQL DB.
GET /migration-sources/import-jobs/:jobId State of a background object import started with background: true (progress, counts, failed records).
POST /migration-sources/:id/extract-components Extract embedded collection types of the imported classes into standalone data components (no access to the Pimcore DB needed).
POST /migration-sources/:id/import-documents Convert the source's Pimcore documents into pages. With staging: true they land in the staging table for review instead of the live pages.
POST /migration-sources/:id/promote-documents Copy the staged documents of this source into the live pages table.

Data Objects (PIM/MDM instances)#

Method & path Description
GET /data-objects List objects, optionally filtered by classId.
GET /data-objects/:id Get one object.
POST /data-objects Create an object.
POST /data-objects/bulk Create (or, with onConflict: update, update) up to 500 objects of one class in one call, as drafts; rows that break a rule (required, unique) are returned in rejected and do not stop the others.
PATCH /data-objects/:id Update an object.
DELETE /data-objects/:id Delete an object.
GET /data-objects/batch Fetch several objects by id (admin: drafts included).
POST /data-objects/batch Batch action on ids[]: publish, unpublish, delete or resolve-assets.
POST /data-objects/query Query objects by class name + filters (admin: no published filter).
GET /data-objects/:id/translations Every locale variant of the same logical object.
GET /data-objects/translations/:translationGroupId Locale variants by translation group id.
POST /data-objects/:id/preview-link Create a shareable preview link for an object (may be a draft); body { expiresInDays? }. Requires objects:publish.
GET /data-objects/:id/preview-links List the object's preview links (with view counts).
DELETE /data-objects/preview-links/:token Revoke a preview link; ?permanent=true removes a revoked or expired one for good. Requires objects:publish.
GET /data-objects/:id/transitions Workflow transitions available for the object in its class's workflow.
POST /data-objects/:id/transition Run a workflow transition; each transition declares the permissions it needs.

Public Data Objects & Forms (no auth, published only)#

Method & path Description
GET /public/data-objects List published objects of a class by name.
GET /public/data-objects/batch Fetch multiple published objects by id.
POST /public/data-objects/query Query published objects by class name + filters.
GET /public/data-objects/:id Get one published object (404 if it's a draft - never leaks draft existence).
POST /public/uploads/intent Public. Approve one file for a form Upload field: { fieldId, filename, size } is checked against the website's upload limits (type, size, daily quota) and the field's own; answers { uploadId, uploadUrl, expiresIn, maxBytes }. The bytes go to uploadUrl (asset service, PUT /public/upload-data/<ticket>), then the form submission refers to the upload as { uploadId }. 503 when UPLOAD_TOKEN_SECRET is not set.
POST /public/forms/:classId/submit Submit a public form, creating an unpublished Data Object of the given class. A notify block in the body only sends mail if it is the one an author saved in a form of a page for that class (F-053); recipients must be one plain address, 3 mails an hour per address.
GET /preview/objects/:token Resolve a preview-link token to its (possibly unpublished) object.

Object events: subscriptions and delivery log (permission object_events:manage)#

Method & path Description
GET /object-event-subscriptions List the subscriptions that send object events to a service.
POST /object-event-subscriptions Create one: { name, events[], endpointId, routeId, classId?, enabled?, ignoreActors?, signingSecretRef? }. The route must be POST, PUT or PATCH with a fixed path; signingSecretRef is an environment variable name starting OBJECT_EVENTS_SECRET_.
GET /object-event-subscriptions/:id Get one subscription.
PATCH /object-event-subscriptions/:id Change some of its fields.
DELETE /object-event-subscriptions/:id Delete it and its delivery log.
POST /object-event-subscriptions/:id/test Queue a synthetic object.updated marked "test": true for this subscription only (202).
GET /object-event-subscriptions/:id/deliveries The delivery log, newest first (?status=pending, delivered, retrying, dead or stopped, ?type=object.updated and so on, and limit up to 200): status, attempts, next try, last problem. Never the event content or the service's answer.
DELETE /object-event-subscriptions/:id/deliveries Clear finished deliveries from the log: body { ids: [...] } (up to 500) or `{ status: 'delivered'
POST /object-event-deliveries/:id/retry Retry a delivery that gave up (dead); 409 for any other status.

Documentation sites (Markdown)#

Method & path Description
GET /docs-sites/:websiteId/tree A documentation website (settings kind: docs, source DAM folder): its documents with titles, addresses and visibility, the index (automatic from the tree of files, or _nav.yml), the other files and the warnings (broken links, entries pointing nowhere).
GET /docs-sites/:websiteId/preview/* A rendered page of a documentation website by its address (empty = home), private documents included: { site, nav, page } with the HTML, the headings, breadcrumbs, previous/next and the warnings.
POST /docs-sites/:websiteId/render Live preview: renders Markdown that is not saved yet ({ path, markdown }) as it would be at that path, with the folder's real links and files; returns { title, html, headings, warnings }.
POST /docs-sites/:websiteId/nav/check Checks the text of the index file ({ text }) without saving it: { ok, errors, warnings, nav }.
GET /docs-sites/:websiteId/search-index The search index of a documentation website (a serialised MiniSearch, searched in the browser), private documents included. ETag-cached.
GET /public/docs/:websiteId/search-index The search index of the PUBLIC documents of a documentation website. ETag-cached; the same file the static site ships.
GET /public/docs-site/:segment Which documentation website answers at a root path segment ({ websiteId, rootPath, title }, 404 if none).
GET /public/docs/:websiteId/nav Index of the PUBLIC documents of a documentation website.
GET /public/docs/:websiteId/page/* A rendered public document by its address (empty = home): { site, page }. A document that is private in the DAM answers 404.

Mail: settings, log, templates#

Method & path Description
GET /mail-settings Get a mail configuration: the default, or with ?websiteId= that website's own, plus what a message of that scope is sent with. Passwords and API keys are never returned (only whether they are set).
GET /mail-providers List the installed HTTP mail providers (OneSignal ...): their id, label and config fields. Providers are JSON files (packages/core/mail-providers, MAIL_PROVIDERS_PATH), read again when one changes.
PUT /mail-settings Save a mail configuration for the default (no websiteId) or for one website: provider is smtp (with smtp: {host, port, secure, user, password}) or a provider id (with providerConfig). Secrets are encrypted at rest; a blank secret keeps the stored one. Needs MAIL_SETTINGS_ENCRYPTION_KEY on the server.
DELETE /mail-settings Remove a website's own mail configuration (?websiteId=), so its mail goes out with the default again. The default cannot be removed.
POST /mail-settings/test Send a test email with the configuration of the default or, with websiteId, of that website.
GET /mail-log List sent-mail log entries.
POST /mail-log/delete Bulk-delete mail log entries.
GET /mail-log/:id Get one mail log entry (including the rendered body).
POST /mail-log/:id/resend Re-send a previously logged email.
GET /mail-templates List HTML/text mail templates.
POST /mail-templates Create a mail template.
GET /mail-templates/:id Get one mail template.
PATCH /mail-templates/:id Update a mail template.
DELETE /mail-templates/:id Delete a mail template.
POST /mail-templates/:id/render Render a mail template to HTML, substituting sample/live data.

AI: text, images, translation, whole-website generation#

Method & path Description
GET /ai/settings Get the configured AI text-generation provider/model/key.
PUT /ai/settings Update AI text-generation settings.
POST /ai/generate Generate text for an editor field (heading, paragraph, etc.) from a prompt.
GET /ai/generated List past AI-generation results.
POST /ai/generate-website-structure Generate a full website's page/section structure from a text brief.
POST /whoobe-one/websites/from-ai Create a real website + pages from a previously generated AI structure.
GET /whoobe-one/websites/:id/export Export a website as a version 2 bundle (JSON manifest): pages, templates, menus, themes and everything they refer to - snippets, module pages, data classes/components/objects, asset records. ?dataObjects=referenced leaves out the objects a data binding would list. The asset files are fetched by the client (admin dashboard zips them).
POST /whoobe-one/websites/import Import a version 1 or 2 bundle as a new website. ?dryRun=1 writes nothing and returns the report with the asset plan; assetMap in the body maps old asset ids to the records the client stored. Classes and objects that exist are reused, ids are rewritten, a failure removes what was created.
GET /ai/image-settings Get the configured AI image-generation provider/model/key.
PUT /ai/image-settings Update AI image-generation settings.
GET /ai/translate-settings Get the configured AI translation provider/model/key.
PUT /ai/translate-settings Update AI translation settings.
POST /ai/generate-image Generate an image from a text prompt, uploading the result to the DAM.

Figma import#

Method & path Description
GET /figma/settings Get the configured Figma personal access token (masked).
PUT /figma/settings Update the Figma access token.
POST /figma/import Import a Figma file/frame, converting it into a page's node tree.

Search (admin)#

Method & path Description
GET /whoobe-one/search Admin search over the same index as /public/search, but session-gated and including drafts and non-indexable pages.
POST /whoobe-one/search/reindex Rebuild the whole search index from the source tables (heals drift; indexing hooks are best-effort).

System#

Method & path Description
GET /api/v1/system/logs Tail recent application log lines.
GET /api/v1/system/logs/download Download the full current log file.
GET /health Liveness/uptime check.
GET /site-root Asked by the reverse proxy for requests it cannot route by name: 204 if the first path segment is a website's root path (the proxy then sends the request to the editor, which renders the page), 403 otherwise (dashboard). Answers from a 5 s cache; reads the URI from X-Original-URI.

gateway (port 3001)#

Federated API Gateway: lets a published site or the admin editor reach third-party REST APIs (HubSpot, Brevo, Stripe, or any custom endpoint) through server-side-only credentials, plus a couple of authenticated/public proxy passthroughs to core-api/asset-processor for callers that only have the Gateway's own origin configured. See docs/release/communication/api-gateway-security.md for the authorization model behind /resolve//submit (a mandatory server-resolved gatewayBindingId, plus an optional per-site API key) — a published site never gets to pick an arbitrary endpoint/route itself.

Gateway admin: endpoints, routes, schemas (auth: wcms_session + GATEWAY_MANAGE)#

Method & path Description
GET /api/v1/gateway/endpoints List configured upstream API endpoints (base URL, auth type, rate limits).
POST /api/v1/gateway/endpoints Register a new upstream endpoint.
GET /api/v1/gateway/endpoints/:id Get one endpoint (credentials redacted).
PATCH /api/v1/gateway/endpoints/:id Update an endpoint.
DELETE /api/v1/gateway/endpoints/:id Delete an endpoint and its routes.
GET /api/v1/gateway/endpoints/:id/routes List an endpoint's configured routes.
POST /api/v1/gateway/endpoints/:id/routes Add a route (path + method) to an endpoint.
PATCH /api/v1/gateway/routes/:id Update a route.
DELETE /api/v1/gateway/routes/:id Delete a route.
POST /api/v1/gateway/routes/:id/test Fire a real test request through a route and return the raw upstream response.
POST /api/v1/gateway/routes/:id/execute Execute a route's proxied request with real parameters (used by the editor's live preview).
GET /api/v1/gateway/routes/:id/schema Get a route's auto-inferred response schema + sample payload.
POST /api/v1/gateway/routes/:id/refresh-schema Re-infer a route's response schema from a fresh live call.
POST /api/v1/gateway/endpoints/:id/import-openapi Bulk-create routes for an endpoint from an OpenAPI/Swagger spec.
POST /api/v1/gateway/preview-resolve Admin-authenticated live resolve, for the editor's own binding-picker preview (distinct from the public /resolve below).
GET /api/v1/gateway/plugins List loaded custom Gateway plugins.
GET /api/v1/gateway/presets List available connector presets (HubSpot, Brevo, Stripe, etc.).

Gateway admin: API clients (auth: wcms_session + GATEWAY_MANAGE)#

Method & path Description
GET /api/v1/gateway/clients List the API clients (applications that call the gateway with a key) with their keys' prefixes; never a key or a hash.
POST /api/v1/gateway/clients Create a client (name, scopes, limits, allowed addresses, expiry; authMode key or jwt; a jwt client carries the identity provider registration in jwt). A key client gets its first key, in the reply, once; a token client has none.
GET /api/v1/gateway/clients/:id Get one client with its keys.
PATCH /api/v1/gateway/clients/:id Change a client: name, status (active / suspended), scopes, limits, addresses, expiry. Scopes are checked against the resulting kind.
DELETE /api/v1/gateway/clients/:id Delete a client and its keys.
POST /api/v1/gateway/clients/:id/keys Add a key to a key client (rotation). The key is in the reply, once.
DELETE /api/v1/gateway/clients/:id/keys/:keyId Revoke a key.

Gateway client surface (auth: an API key wbk_... from a server, or an identity provider token from a browser or an app, as Authorization: Bearer; the key also as X-Whoobe-Key; no session - see docs/release/communication/integrations.md)#

Method & path Description
GET /client/v1/me What the calling key is: name, auth mode, scopes, limits, state of the rate-limit store. No secret.
GET /client/v1/data/:class Published objects of a Data Class named in a data:read:<Class> scope: filter=field:op:value (up to 5), orderBy, dir, limit (1-100), offset, locale. Only the class's own attributes are returned. Outside the scopes or an unknown class: 404 Not found.
GET /client/v1/data/:class/:id One published object of that class; a draft, another class's id or a malformed id answer 404 Not found.
POST /client/v1/automations/:endpoint/* Start the flow behind a POST route of an engine endpoint (Activepieces, n8n) named in an automation:run:<endpoint>:<route> scope, wait for its answer and return { ok, outcome?, response }; outcome is the validated key (1-32 letters, digits, _, -) the flow answered. JSON body up to 1 MB. Outside the scopes: 404 Not found; an engine error: 502.
ALL /client/v1/gateway/:endpoint/* Call a configured route of an endpoint the client's scopes allow: the path is matched to a route (templates such as customers/{id} included), query string and JSON body are passed on, the gateway adds the credentials. Anything outside the scopes answers 404 Not found; 429 with Retry-After over the client's limits. A key sent with an Origin header (a browser) is refused with 403; a valid token whose claims give no access gets 403.

Gateway published-site endpoints (site API key or bound content only - see docs/release/communication/api-gateway-security.md)#

Method & path Description
POST /api/v1/gateway/resolve Resolve a gateway-bound content field for a published page - the only way a published site reads third-party data. Requires a resolved gatewayBindingId (server-assigned at page-save time), not a free endpoint/route choice.
POST /api/v1/gateway/submit Submit a gateway-bound form for a published page. Requires a resolved gatewayBindingId, same as /resolve. The reply is { success, response }, plus outcome when the service answered a plain key of 1-32 letters, digits, _ or - (the page reacts to it, see guides/marketing-automation.md).

Gateway internal proxies (auth: wcms_session, admin-dashboard use only)#

Method & path Description
ALL /api/internal/* Authenticated passthrough proxy to core-api, for admin-dashboard requests that need to cross from the Gateway's own origin.
ALL /dam/* Authenticated passthrough proxy to asset-processor.

Gateway public proxy (no auth)#

Method & path Description
ALL /public/* Unauthenticated passthrough proxy to core-api's own /public/* routes, for published sites that only have the Gateway's origin configured.

Gateway plugin routes#

Method & path Description
ALL /api/remote/* Dynamically registered by loaded Gateway plugins (see /api/v1/gateway/plugins) - not enumerable statically.

Health#

Method & path Description
GET /health Liveness/uptime check.

asset-processor (port 3002)#

DAM (Digital Asset Management) microservice: image processing/transform, metadata extraction, and S3-backed asset & folder storage, plus optional CDN mirroring. Isolated from core-api so heavy image work never blocks the main API.

Stateless image processing#

Method & path Description
POST /api/v1/process Resize/convert an uploaded (or base64) image; ?mode=variants returns multiple sizes in one call.
POST /api/v1/metadata Extract EXIF/IPTC/GPS/camera metadata from an uploaded file.

DAM assets (S3-backed, Postgres-tracked)#

Method & path Description
GET /api/v1/dam/info Non-secret storage config (bucket, endpoint, public base URL) for the admin UI.
POST /api/v1/dam/upload Upload a file to S3 and record it (path, visibility, metadata).
POST /api/v1/dam/transform Re-process an already-uploaded image (resize/format/watermark/etc.) and save it as a new version or _edited copy.
DELETE /api/v1/dam/asset Delete an asset (and its thumbnails) from storage and the DB.
POST /api/v1/dam/assets/move Move/rename an asset to a new folder path.
GET /api/v1/dam/folders List DAM folders.
POST /api/v1/dam/folders Create a folder.
DELETE /api/v1/dam/folders Delete a folder and everything under it (descendant folders, asset records, and S3 objects).
GET /api/v1/dam/assets List assets in a folder, with resolved URLs + thumbnails.
POST /api/v1/dam/assets List assets in a folder (POST variant, avoids URL-length limits for large folder-rule payloads).
GET /api/v1/dam/assets/:id Get a single asset by record id, with resolved URLs.
PATCH /api/v1/dam/assets/metadata Update an asset's stored metadata.
POST /api/v1/dam/assets/:id/mirror-cdn Push a copy of this asset to the configured CDN mirror target.
GET /api/v1/dam/asset-urls Resolve an asset's (public or freshly presigned) URL + thumbnail URLs by path.
POST /api/v1/dam/asset-urls Resolve URLs for a batch of asset paths in one call.
GET /api/v1/dam/exists Check whether an asset exists at a given path.
POST /api/v1/dam/exists Check existence for a batch of paths in one call.
POST /api/v1/dam/regenerate-thumbnails Regenerate thumbnail variants for one or more assets.
POST /api/v1/dam/ensure-bucket Ensure the target bucket exists with the correct public-read policy for current folder rules.
GET /dam-asset/* Streams a stored object through this server (signed S3 GetObject), so the browser never talks to S3 directly.

Health#

Method & path Description
GET /health Liveness/uptime check.

Non-HTTP: migration-tool CLI#

packages/migration-tool also ships a standalone CLI (used directly, or wrapped by core-api's /migration-sources/*/import-* endpoints above):

pnpm --filter @whoobe-cms/migration-tool cli -- help
Command Description
migrate-documents Import Pimcore Documents (pages/snippets) and their Areablocks into whoobe_pages. Flags: --dry-run, --source=, --limit=, --staging.
promote-staging Copy whoobe_pages_staging rows into whoobe_pages (completes the staged workflow). Flags: --dry-run, --clear.
migrate-classes Translate Pimcore class definitions (var/classes/*.php) into data_classes.
migrate-objects --class=<Name> Import one class's real object instances into data_objects.
migrate-assets Upload Pimcore assets referenced by migrated documents into this system's S3 bucket + assets table (documents-migration plan Phase 1). Flags: --dry-run, --source=, --limit=, --public. Requires PIMCORE_VAR_ASSETS_PATH pointing at the source install's asset directory.

OpenAPI spec#

docs/release/api/openapi.yaml is a generated, machine-readable OpenAPI 3.0 companion to this page — importable into Swagger UI, Postman, Insomnia, or any OpenAPI-driven client generator. It's generated from the exact same route table as this page (see docs/release/api/gen-api-docs.py), so the two can't silently drift apart — when a route changes, edit that script's table and re-run it (python3 docs/release/api/gen-api-docs.py from docs/api/), not the YAML or this page's tables directly.

Scope, by design: every one of the ~226 routes documented above gets a real path, method, tag, auth requirement, and path parameters — that part is exhaustive. Request/response bodies are intentionally generic (type: object, no field-by-field modeling) for most routes, since hand-modeling every payload shape across three services would be a much larger, separate effort and would need to be re-verified against the handlers constantly to stay honest. A handful of flagship endpoints (POST /auth/login, GET /auth/me, POST /api/v1/gateway/resolve, POST /api/v1/gateway/submit, and the Whoobe One Pages CRUD) get real, hand-written schemas instead, as a quality anchor and a template for extending the rest incrementally.

Last updated