The public REST API of PageHub, called with a ph_ API key (Authorization: Bearer ph_...), plus the one webhook the platform calls on a white-label tenant's server (fetchPage).
A site is HTML + Liquid files: its pages are files (pages/*.liquid), written through the files API; the page routes manage each page's record (name, slug, SEO, access). Writes land in the site's draft; PUT /api/v1/sites/{id} with published: true makes the draft live.
The headless content API (/api/v1/content/...) is described by its own document (GET /api/v1/content/openapi.json); GET /api/openapi.json serves this document with it merged in.
The routes also accept the dashboard's session cookie from the dashboard itself; only the API key is the public contract.
Every operation carries two extension fields. x-auth says who may call it: api-key (a ph_ key), session-or-key (the dashboard's own session, or a key), optional-key (public, a key widens what you see), admin-key (a platform admin's key), session (the dashboard session only; an API key is refused) or public. x-rate-limit names the rate-limit rule (see the rate-limiting guide) when the route has one; most routes limit per user, public routes per IP.
Sites
Create, read, update, publish and delete sites.
List sites
GET /api/v1/sites
The sites the key's user is a member of, or the sites of the key's tenant, newest update first.
Who can call it: API key.
Create a site
POST /api/v1/sites
Creates a site from a template's stored files, or the blank starter when no template is given.
Who can call it: API key.
JSON body fields: name, title, description, template, sourceTemplate.
Read a site
GET /api/v1/sites/{id}
The site's own fields. Its pages are files: read them through the files API. mountKey is returned only to a tenant key or a user with the owner or agency role.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Update or publish a site
PUT /api/v1/sites/{id}
Sets the site's own fields. published: true builds a release from the draft and makes it live (the first publish is subject to the plan's site limit); published: false unpublishes. Pages are not sent here: use the files and pages routes.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: name, title, description, ogImage, portal, crawlPolicy, timezone, language, mountOrigin, rotateMountKey, published, expectedUpdatedAt.
Delete a site
DELETE /api/v1/sites/{id}
Permanently deletes the site and everything under it. Site owners only.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Duplicate a site
POST /api/v1/sites/{id}/duplicate
Copies the site's files and page rows into a new site owned by the caller. Needs edit access.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: name, title, description.
Audit a draft page
GET /api/v1/sites/{id}/audit
Renders the draft page as the preview does, then runs the SEO or accessibility checks on it.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind | query | seo \ | accessibility |
path | query | string | The page's URL path. |
Screenshot the draft
POST /api/v1/sites/{id}/screenshot
Renders the draft preview in a real browser and returns the image as base64. Nothing is stored.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: path, width, height, fullPage, selector.
Change theme, favicon, language or integrations
PUT /api/v1/sites/{id}/source-settings
Settings that live in the site's files: theme sets custom properties in theme.css, favicon sets or clears site.json favicon, language is site.json lang, integrations merges provider blocks. Send at least one.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: theme, favicon, language, integrations.
List AI edits waiting for review
GET /api/v1/sites/{id}/ai-review
In review mode PageHub AI stages its file edits instead of writing them. count=1 answers only the number.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
count | query |
Keep or discard staged AI edits
POST /api/v1/sites/{id}/ai-review
Keep writes a staged file to the draft (as an AI write, against bases); discard drops it. keep and discard take file paths or "all". A file that changed meanwhile answers 409 version_conflict and nothing is written.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: keep, discard, bases.
Read the social image design
GET /api/v1/sites/{id}/og-card
The site-wide Social Image designer scene. Claimed sites need an editor session; an unclaimed site passes.
Who can call it: Dashboard session only (an API key is refused).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Save the social image design
PUT /api/v1/sites/{id}/og-card
Who can call it: Dashboard session only (an API key is refused).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: scene.
Read the favicon design
GET /api/v1/sites/{id}/favicon-design
Who can call it: Dashboard session only (an API key is refused).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Save the favicon design
PUT /api/v1/sites/{id}/favicon-design
Who can call it: Dashboard session only (an API key is refused).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: scene, renderedMediaId.
Read a site's privacy settings
GET /api/v1/sites/{id}/privacy
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Update a site's privacy settings
PUT /api/v1/sites/{id}/privacy
Send only the fields to change.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: consentMode, privacyUrl, builtInAnalytics, submissionRetentionDays.
Files
A site's draft files (pages, partials, theme.css, site.json, ...).
List draft files, read several, or search them
GET /api/v1/sites/{id}/files
Without q or read: every file path of the draft with its version (a content hash); glob keeps only the matching paths. With read: the text and version of up to 40 files in one call (400,000 characters at most; the rest comes back as skipped). With q: the hits of the text (plain, case-insensitive) or, with regex, of a JavaScript regular expression run under a time limit; each hit has its line and column and the text around the match. Up to 100 hits.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
X-PageHub-Stage | header | With an API key: read the draft under the staged AI layer and write into that layer instead of the draft. | |
q | query | string | Text to search for. |
path | query | string | With q: only files whose path starts with this, e.g. pages/. |
read | query | string | Comma-separated paths to read in one call (1-40), e.g. pages/index.liquid,partials/header.liquid. |
regex | query | 1 \ | true |
glob | query | string | Only paths matching, for the listing and for q: * within a folder, ** across folders, ?, {a,b}. A glob with no / matches the file name at any depth (*.liquid). |
context | query | integer | With q: lines of context before and after each hit. |
Save a batch of files atomically
POST /api/v1/sites/{id}/files
Writes and deletes up to 500 files in one atomic save. baseVersions says which version of each file you edited; a file someone else changed since answers 409 version_conflict and nothing is written. Files are linted and sanitized; invalid HTML nesting is repaired and reported in repaired, so compare the stored text before the next edit. pages also creates a page record for each new page file in the same write, so a new page and the link to it land together; a page that can't be created (taken URL, plan cap) answers 400 or 403 and writes nothing. Not available in review mode.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
X-PageHub-Stage | header | With an API key: read the draft under the staged AI layer and write into that layer instead of the draft. |
JSON body fields: changes, baseVersions, pages.
Read one draft file
GET /api/v1/sites/{id}/files/{path}
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
X-PageHub-Stage | header | With an API key: read the draft under the staged AI layer and write into that layer instead of the draft. | |
path (required) | path | string | The file's path in the site, one URL segment per folder, e.g. pages/shop/[handle].liquid. |
Write one draft file
PUT /api/v1/sites/{id}/files/{path}
Same rules as the batch save, for a single file. page on a new pages/<slug>.liquid file also creates its page record.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
X-PageHub-Stage | header | With an API key: read the draft under the staged AI layer and write into that layer instead of the draft. | |
path (required) | path | string | The file's path in the site, one URL segment per folder, e.g. pages/shop/[handle].liquid. |
JSON body fields: text, baseVersion, page.
Outline a page
GET /api/v1/sites/{id}/outline
The structure of one page of the draft: sections and landmarks with their line ranges, headings, and every {% render %} / {% section %} of a partial, expanded in place with its own sections and headings (anchored to the partial's file and lines) unless expand=0. Rendered partials that are components carry their use counts.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
X-PageHub-Stage | header | With an API key: read the draft under the staged AI layer and write into that layer instead of the draft. | |
page (required) | query | string | A page id, its URL (/about) or a file path (pages/about.liquid, partials/header.liquid). |
expand | query | 0 \ | 1 |
classes | query | 1 \ | true |
Pages
The page records of a site: name, slug, URL pattern, SEO, access policy.
List pages
GET /api/v1/sites/{id}/source-pages
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Create a page
POST /api/v1/sites/{id}/source-pages
Creates the page's file (it must not exist yet) and its record. The first page of a site becomes the home page. Send text, or blank: true to start from the site's own header and footer around a heading.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: name, slug, pathPattern, text, blank, seo, file.
Read a page's record and settings
GET /api/v1/sites/{id}/source-pages/{pageId}
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
pageId (required) | path | string | The page's pageId from the pages list. |
Change a page's record
PATCH /api/v1/sites/{id}/source-pages/{pageId}
seo and policy merge into the current values; a null value removes a key. file edits the page's own file. Clients (content-only role) cannot change page settings.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
pageId (required) | path | string | The page's pageId from the pages list. |
JSON body fields: name, slug, pathPattern, isHomePage, is404Page, isHidden, seo, policy, file.
Delete a page
DELETE /api/v1/sites/{id}/source-pages/{pageId}
Deletes the page's file, then its record. The home page cannot be deleted.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
pageId (required) | path | string | The page's pageId from the pages list. |
Components
Reusable components (partials) of a site.
List components
GET /api/v1/sites/{id}/components
The reusable components (partials) of the site's draft and where each is used.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Rename a component
PATCH /api/v1/sites/{id}/components/{name}
Renames the component and every {% render %} tag of it, as one write.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
name (required) | path | string | The component's id. |
JSON body fields: name.
Delete a component
DELETE /api/v1/sites/{id}/components/{name}
Refused with 409 in_use while anything still renders it.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
name (required) | path | string | The component's id. |
Collections
A site's collections and their rows. Reading them publicly is the content API.
List collections
GET /api/v1/sites/{id}/collections
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Create a collection
POST /api/v1/sites/{id}/collections
Needs the owner or agency role on the site and a plan that includes collections (and the chosen source type).
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: slug, name, description, schema, source, isPublic.
Read a collection
GET /api/v1/sites/{id}/collections/{colId}
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
Update a collection
PATCH /api/v1/sites/{id}/collections/{colId}
name and description are open to any editor; changing the slug, schema, source, visibility or member gates needs the owner or agency role.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
JSON body fields: name, description, slug, schema, source, isPublic, requiresCustomerLogin, requiredPlans, memberFields.
Delete a collection and its rows
DELETE /api/v1/sites/{id}/collections/{colId}
Owner or agency role.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
List rows
GET /api/v1/sites/{id}/collections/{colId}/rows
Cursor-paginated, in order. Fields the reader's role cannot read are redacted.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
limit | query | integer | |
cursor | query | string | The nextCursor of the previous page. |
Create rows
POST /api/v1/sites/{id}/collections/{colId}/rows
Send one row ({ data } or the bare field object), an array of rows, or { rows: [...] }; up to 500 per call. Each row is validated against the collection's schema.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
Update a row
PATCH /api/v1/sites/{id}/collections/{colId}/rows/{rowId}
data merges into the row's current data and is validated against the schema.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
rowId (required) | path | string |
JSON body fields: data, order, externalId.
Delete a row
DELETE /api/v1/sites/{id}/collections/{colId}/rows/{rowId}
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
rowId (required) | path | string |
Fetch a Google Sheet as CSV
POST /api/v1/sites/{id}/collections/sheet-csv
Only for Google Sheets links shared as "Anyone with the link". The server fetches the export (the browser can't) through the SSRF guard, up to 8 MB.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: link.
Read a collection's fields and bindings
GET /api/v1/sites/{id}/collections/{colId}/fields
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
Export a collection's rows as CSV
GET /api/v1/sites/{id}/collections/{colId}/export.csv
One column per schema field, in row order. Served as a file download.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
Import rows from CSV
POST /api/v1/sites/{id}/collections/{colId}/import
Send CSV text as a text/csv body or { csv }, or { mediaId } for an uploaded CSV, TSV or XLSX the site's members uploaded. Columns map to schema fields by name. mode: append (default), replace (deletes the rows first), or upsert (matches on externalId or id).
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
mode | query | append \ | replace \ |
JSON body fields: csv, mediaId.
Sync a collection from its source
POST /api/v1/sites/{id}/collections/{colId}/sync
Runs the collection's source sync (the source type must be allowed on the plan). The answer is the sync result.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
List a collection's recent syncs
GET /api/v1/sites/{id}/collections/{colId}/sync-logs
The last 50 runs, newest first.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
Whether a collection has source credentials
GET /api/v1/sites/{id}/collections/{colId}/credentials
Answers only a boolean; the secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
sourceType | query | string | Defaults to the collection's source type. |
Save a collection's source credentials
POST /api/v1/sites/{id}/collections/{colId}/credentials
Owner or agency role.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
sourceType | query | string | Defaults to the collection's source type. |
JSON body fields: secrets, sourceType.
Delete a collection's source credentials
DELETE /api/v1/sites/{id}/collections/{colId}/credentials
Owner or agency role.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
sourceType | query | string | Defaults to the collection's source type. |
List a row's revisions
GET /api/v1/sites/{id}/collections/{colId}/rows/{rowId}/history
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
rowId (required) | path | string | The row's id. |
Restore a row revision
POST /api/v1/sites/{id}/collections/{colId}/rows/{rowId}/history
A normal update seeded from the snapshot, so it validates against the current schema and records a new revision.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
rowId (required) | path | string | The row's id. |
JSON body fields: revisionId.
Connect RSS or Atom feed
POST /api/v1/sites/{id}/apps/rss
Fills a collection with the latest posts from a feed. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: url, name.
Connect Notion database
POST /api/v1/sites/{id}/apps/notion
Fills a collection from a Notion database. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, databaseId, name.
Connect Cal.com open times
POST /api/v1/sites/{id}/apps/calcom
Shows the next open times of one Cal.com event. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: apiKey, eventLink, name.
Connect Eventbrite events
POST /api/v1/sites/{id}/apps/eventbrite
Fills a collection with upcoming Eventbrite events. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, organizationId, name.
Connect Ticket Tailor events
POST /api/v1/sites/{id}/apps/tickettailor
Fills a collection with upcoming Ticket Tailor events. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: apiKey, name.
Connect Supabase table
POST /api/v1/sites/{id}/apps/supabase
Fills a collection from a table in a Supabase project's public schema. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: projectUrl, table, apiKey, name.
Connect Baserow table
POST /api/v1/sites/{id}/apps/baserow
Fills a collection from a Baserow table. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, tableId, baseUrl, name.
Connect NocoDB table
POST /api/v1/sites/{id}/apps/nocodb
Fills a collection from a NocoDB table. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, baseUrl, tableId, name.
Connect Shopify products
POST /api/v1/sites/{id}/apps/shopify
Fills a collection with a Shopify store's products. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: shop, token, name.
Connect WooCommerce products
POST /api/v1/sites/{id}/apps/woocommerce
Fills a collection with a WooCommerce store's products. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: storeUrl, consumerKey, consumerSecret, name.
Connect Square items
POST /api/v1/sites/{id}/apps/square
Fills a collection with a Square account's items. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, storeUrl, name.
Connect Gumroad products
POST /api/v1/sites/{id}/apps/gumroad
Fills a collection with a Gumroad account's products. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, name.
Connect Lemon Squeezy products
POST /api/v1/sites/{id}/apps/lemonsqueezy
Fills a collection with a Lemon Squeezy store's products. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, and an app the site's plan includes (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: apiKey, storeId, name.
Connect an Airtable table
POST /api/v1/sites/{id}/apps/airtable
Fills a collection from an Airtable table. Reads the table's first records, which checks the token. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, on a plan that includes Airtable (Business and up; 403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, base, table, name.
Connect Hospitable
POST /api/v1/sites/{id}/apps/hospitable
Fills the properties collection with the homes in a Hospitable account. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, on Pro and up (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: token, bookingUrl.
Connect Hostaway
POST /api/v1/sites/{id}/apps/hostaway
Fills the properties collection with the homes in a Hostaway account. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, on Pro and up (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: accountId, apiKey, bookingUrl.
Connect Guesty
POST /api/v1/sites/{id}/apps/guesty
Fills the properties collection with the homes in a Guesty account. Checks what was sent with the app (a bad key is a 400 with a message to show as is), makes or reuses the collection it fills, stores secrets encrypted, and runs the first sync. Needs an owner or agency role on the site, on Pro and up (403 with upgrade: true otherwise). Secrets are never returned.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: clientId, clientSecret, bookingUrl.
List the calendar links a site reads
GET /api/v1/sites/{id}/apps/calendar-feed
The links themselves are secret and never returned; each entry carries only its host.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind (required) | query | availability \ | events |
Connect a calendar link
POST /api/v1/sites/{id}/apps/calendar-feed
Reads the link once, adds it (as a home or a calendar), makes the properties or events collection if the site has none, and runs the first sync. Needs an owner or agency role and Pro or up.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: app, name, url, bookingUrl.
Stop reading a calendar link
DELETE /api/v1/sites/{id}/apps/calendar-feed
Its rows go with it. Answers with the same shape as connecting, listing the links that remain.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind (required) | query | availability \ | events |
feedId (required) | query | string | The link's id, from the list. |
List dates closed in a rental tool
GET /api/v1/sites/{id}/collections/{colId}/booking-pushes
The collection's homes' dates that were closed (or failed to close) in their rental tool, newest first, up to 20.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
Run a failed date push again
POST /api/v1/sites/{id}/collections/{colId}/booking-pushes
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
JSON body fields: pushId.
List the calendar links a collection's homes share
GET /api/v1/sites/{id}/collections/{colId}/claim-feeds
Up to 200 homes. path is null until a link is made for the home.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
Make a home's calendar link
POST /api/v1/sites/{id}/collections/{colId}/claim-feeds
Returns the path of the link other platforms read. With rotate, the link is replaced and the old one stops working.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
JSON body fields: rowId, rotate.
List the dates taken or closed on a row
GET /api/v1/sites/{id}/collections/{colId}/rows/{rowId}/claims
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
rowId (required) | path | string | The row's id. |
Close dates on a row
POST /api/v1/sites/{id}/collections/{colId}/rows/{rowId}/claims
Closes open dates by hand. Answers 409 when any of them is already taken.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
rowId (required) | path | string | The row's id. |
JSON body fields: field, keys, note.
Reopen dates closed on a row
DELETE /api/v1/sites/{id}/collections/{colId}/rows/{rowId}/claims
A claim tied to an order is refused with 409: unbook the order instead.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
colId (required) | path | string | The collection's id or slug. |
rowId (required) | path | string | The row's id. |
JSON body fields: claimId.
Releases
Releases built by publishing.
Read a release
GET /api/v1/sites/{id}/releases/{releaseId}
A publish too big to build inside the request answers release.queued; poll the release until status is ready or failed.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
releaseId (required) | path | string |
Make a release live again
POST /api/v1/sites/{id}/releases/{releaseId}
Rollback: the undo for a bad publish. Needs permission to publish the site.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
releaseId (required) | path | string |
JSON body fields: action.
Media
A site's media library and direct uploads.
Read the media library
GET /api/v1/sites/{id}/media
The site's media items and folders. ?summary=1 returns the library's tab counts and ?usage=1 where each file is used, instead.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind | query | Only images. | |
summary | query | ||
usage | query |
Upload media: sign, confirm, import a URL, or register items
POST /api/v1/sites/{id}/media
Large files go straight to the CDN in two steps, so the bytes never pass through the API:
{ step: "sign", size, contentType, filename? }returns anuploadURL. Send the file there: images as a multipartPOSTwith fieldformField(file); everything else as a rawPUTwhoseContent-TypematchescontentTypeexactly.{ step: "confirm", ticket, filename?, width?, height? }finalizes the upload and registers it in the library. Confirm is not optional.
private: true (digital downloads) works only through sign then confirm. Without step: { fileUrl } (or imageUrl) imports a public URL, { dataBase64, mimeType, filename } uploads small bytes inline (a few MB at most), and { items } registers already-uploaded files in the library.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Reorder or move library items
PATCH /api/v1/sites/{id}/media
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: order, move.
List media folders
GET /api/v1/sites/{id}/media/folders
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Replace the media folders
PUT /api/v1/sites/{id}/media/folders
Replaces all folders. Items in a removed folder move to the top level.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: folders.
List the user's unattached files
GET /api/v1/sites/{id}/media/unattached
The signed-in user's stored files that no library lists. An API key gets an empty list. canManage is true for the site's owner, who may add them to the library or delete them.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Update a library file
PATCH /api/v1/sites/{id}/media/{mediaId}
metadata merges key by key; a null value removes a key.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
mediaId (required) | path | string | The file's media id. |
JSON body fields: name, order, type, cdnId, metadata.
Remove a file from the library
DELETE /api/v1/sites/{id}/media/{mediaId}
Drops the entry and, for a signed-in caller, deletes the stored file when that is safe. An API key only drops the entry (deleted: false). A file in no library is deleted only by the site's owner, and only when nothing uses it (409 in-use).
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
mediaId (required) | path | string | The file's media id. |
Format
The HTML + Liquid authoring reference.
The HTML + Liquid authoring reference
GET /api/v1/format/liquid
Public; no key needed. The tags, filters, objects and lint rules are generated from the renderer's catalogues; the conventions (files, runtime data-* attributes with examples, site JavaScript, forms and form webhooks, dates and timezone, maps) are written by hand and checked against the runtime. The same Markdown is the MCP get_style_reference topic liquid and the /docs/schema page.
Who can call it: Public.
Content
The public headless content API.
List collection items
GET /api/v1/content/{site}/{collection}
| Parameter | In | Type | What it is |
|---|---|---|---|
site (required) | path | string | Page id. |
collection (required) | path | string | Collection slug. |
q | query | string | Full-text search. |
category | query | string | |
sort | query | string | e.g. price-asc, newest. |
page | query | integer | |
limit | query | integer | |
minPrice | query | integer | |
maxPrice | query | integer | |
filter | query | string | JSON object of equality constraints, e.g. {"brand":"acme"}. |
facet.<key> | query | string | Comma-separated facet values, e.g. ?facet.color=red,blue. |
Describe a collection's fields + response shape
GET /api/v1/content/{site}/{collection}/schema
| Parameter | In | Type | What it is |
|---|---|---|---|
site (required) | path | string | |
collection (required) | path | string |
Stock
Public stock image and video search.
Search stock images
GET /api/v1/stock-images
Public. Searches the verified stock library; returned images get their uses count bumped.
Who can call it: Public.
| Parameter | In | Type | What it is |
|---|---|---|---|
q | query | string | Full-text search. |
category | query | string | |
orientation | query | string | |
source | query | unsplash \ | pexels \ |
sort | query | popular \ | newest |
page | query | integer | |
limit | query | integer |
Upsert stock images (admin)
POST /api/v1/stock-images
Platform admins only. Each item needs photoId and url; an item without them comes back as a result with an error instead of failing the call.
Who can call it: Platform admin API key.
Search a stock image provider
POST /api/v1/stock-images/search-external
Public. Searches an external provider (Pexels by default) and caches the results in the stock library. A provider that is unavailable or fails answers 200 with an empty list and a note.
Who can call it: Public.
JSON body fields: q, count, orientation, provider.
Search a stock video provider
POST /api/v1/stock-videos/search-external
Public. Like the image search; nothing is cached.
Who can call it: Public.
JSON body fields: q, count, orientation, minDuration, maxDuration, provider.
Blocks
The block library and placing a block into a page.
Browse the block library
GET /api/v1/liquid-blocks
The public library plus the caller's own saved blocks, without their source. Ask the block's route for the ones you use.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
q | query | string | |
category | query | string | |
style | query | string | |
limit | query | integer |
Read one block as Liquid
GET /api/v1/liquid-blocks/{slug}
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
slug (required) | path | string | The block's slug. |
Place a library block into a page
POST /api/v1/sites/{id}/blocks
Adds the block's Liquid (with fresh ids) to a page file of the draft as one write. pageId or path picks the page, the home page by default. position is end (default, before the footer) or start; before or after is text that occurs once in the page.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: slug, pageId, path, position, before, after.
Templates
The template catalog.
List templates
GET /api/v1/templates
Public templates; with a key, also the tenant's own (an admin key sees every template). slugs=a,b,c fetches those templates in full and ignores the other filters.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
category | query | string | |
tag | query | string | |
q | query | string | Full-text search. |
slugs | query | string | Comma-separated slugs (up to 100). |
previewLimit | query | string | Trims how many preview items each template carries. |
Create a template
POST /api/v1/templates
A template is its files: send files (and pages), or fromSite to snapshot a site. The thumbnail is captured automatically after the response. Only platform admins publish into the public catalog (isPublic); a tenant's templates stay its own.
Who can call it: API key.
JSON body fields: slug, title, tagline, description, category, tags, hidden, isPublic, sortOrder, files, pages, fromSite.
Read a template
GET /api/v1/templates/{slug}
A private template is visible only to its tenant or an admin. fields=theme answers just the palette and style guide; format=liquid answers the files and page records a site made from the template starts with.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
slug (required) | path | string | The template's slug. |
fields | query | ||
format | query |
Update a template
PUT /api/v1/templates/{slug}
The tenant's own template, or any for an admin. Send files / pages / fromSite to replace its content (the thumbnail is recaptured). expectedVersion guards against a concurrent edit.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
slug (required) | path | string | The template's slug. |
JSON body fields: title, tagline, description, category, tags, hidden, sortOrder, expectedVersion, files, pages, fromSite.
Delete a template
DELETE /api/v1/templates/{slug}
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
slug (required) | path | string | The template's slug. |
Audit a template page
GET /api/v1/templates/{slug}/audit
Renders the template's stored page as its preview does, then runs the SEO or accessibility checks on it. A private template is visible only to its tenant or an admin.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
slug (required) | path | string | The template's slug. |
kind | query | seo \ | accessibility |
path | query | string | The page's URL path. |
Presets
Curated theme bundles.
List presets
GET /api/v1/presets
Public presets; with a key, also the tenant's own.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
mood | query | string | Case-insensitive match on a mood. |
limit | query | integer |
Create a preset (admin)
POST /api/v1/presets
Platform admins only: presets are global and public.
Who can call it: Platform admin API key.
JSON body fields: presetId, name, description, mood, palette, styleGuide, fonts, style.
Read a preset
GET /api/v1/presets/{id}
A private preset is visible only to its owner.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The preset's presetId. |
Update a preset
PUT /api/v1/presets/{id}
Only the preset's owner.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The preset's presetId. |
JSON body fields: name, description, mood, palette, styleGuide, fonts, style.
Delete a preset
DELETE /api/v1/presets/{id}
Only the preset's owner.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The preset's presetId. |
Components library
The shared component library (blocks stored as Liquid).
Search the component library
GET /api/v1/components
Public blocks; with a key, also the caller's own. The Liquid source is left out: read one block for it.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
q | query | string | Full-text search. |
tag | query | string | |
featured | query | ||
sort | query | popular \ | newest \ |
page | query | integer | |
limit | query | integer | |
category | query | string | Comma-separated for several. |
categories | query | string | |
subcategory | query | string | |
preset | query | string | |
source | query | string | |
group | query | string | |
style | query | string | Comma-separated for several. |
styles | query | string | |
blockType | query | string |
Add a block to the library
POST /api/v1/components
A block is its Liquid source (sanitized and linted like a site file). Only platform admins can publish one (isPublic) or mark it a category preview.
Who can call it: API key.
JSON body fields: name, slug, description, visual, category, subcategory, tags, preset, group, style, styles, isPublic, isCategoryPreview, source.
List library categories
GET /api/v1/components/categories
Categories with counts, subcategories and styles, for a category-first block picker.
Who can call it: Public; an API key shows more.
Read a block with its Liquid
GET /api/v1/components/{id}
By _id or slug. Bumps the block's uses count.
Who can call it: Public; an API key shows more.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The block's _id or slug. |
Update a block
PUT /api/v1/components/{id}
Only the block's owner (or an admin). source is sanitized and linted. expectedVersion guards against a concurrent edit. Only an admin can change isPublic, isFeatured or isCategoryPreview.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The block's _id or slug. |
JSON body fields: name, slug, description, visual, category, subcategory, tags, preset, group, style, isPublic, isFeatured, isCategoryPreview, expectedVersion, source.
Delete a block
DELETE /api/v1/components/{id}
Only the block's owner (or an admin).
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The block's _id or slug. |
Like a public block
POST /api/v1/components/{id}/like
Idempotent per caller: the first like counts, repeats answer alreadyLiked.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The block's _id or slug. |
Team
Site members and invites.
List members and pending invites
GET /api/v1/sites/{id}/invites
Needs a user key (not a tenant key) with the owner role on the site.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Invite someone to the site
POST /api/v1/sites/{id}/invites
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: email, role.
Revoke a pending invite
DELETE /api/v1/sites/{id}/invites
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
inviteId (required) | query | string | The invite's id. |
Domain
A site's custom domain.
Read a site's domain, or preflight one
GET /api/v1/sites/{id}/domain
The attached domain with the DNS records still to create for each variant. check=<domain> preflights a candidate instead; a candidate held by another site answers only available: false.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
check | query | string | A domain to preflight. |
Attach a domain or change its redirect mode
PATCH /api/v1/sites/{id}/domain
Needs the owner or agency role. Attaching registers both variants of the pair with the host, and the answer carries the DNS records to create; attaching does not publish the site. Repeating the same call is a no-op that reports the DNS state.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: domain, domainRedirectMode.
Detach the domain
DELETE /api/v1/sites/{id}/domain
Needs the owner or agency role. detachFailures lists any variant still left on the host project.
Who can call it: API key.
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Chat
The site's chat bot.
Read the site chat bot's settings
GET /api/v1/sites/{id}/chat
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Update the site chat bot's settings
PUT /api/v1/sites/{id}/chat
A partial update; an unknown setting is refused.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: enabled, assistantName, greeting, instructions, leadFields, leadCollectionSlug, notifyEmail, dailyCreditCap.
Emails
The emails a site sends, and the address they come from.
List the site's emails
GET /api/v1/sites/{id}/emails
Every email kind, whether the owner customized it, and whether it is sent today.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Read the look of the site's emails
GET /api/v1/sites/{id}/emails/brand
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Change the look of the site's emails
PUT /api/v1/sites/{id}/emails/brand
Logo on or off and the button colour, on every plan.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: brand.
Read one email
GET /api/v1/sites/{id}/emails/{kind}
The stored design (null = default) with file versions, the defaults, the kind's variables and slots, sample data, and feature.customDesigns (whether the owner's plan saves custom designs).
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind (required) | path | Which email. |
Save one email
PUT /api/v1/sites/{id}/emails/{kind}
source (the design) needs a plan with custom designs and an HTML-first site; subject and preheader save on every plan. The design is checked before saving; problems come back as errors. base carries the file versions the edit started from.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind (required) | path | Which email. |
JSON body fields: subject, preheader, source, base.
Reset one email to the default
DELETE /api/v1/sites/{id}/emails/{kind}
Both of the email's files are removed.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind (required) | path | Which email. |
Preview an unsaved email
POST /api/v1/sites/{id}/emails/{kind}/preview
Renders the draft with sample data. A field the body leaves out uses what is saved. A design with errors renders the default (usedDefault).
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind (required) | path | Which email. |
JSON body fields: subject, preheader, source.
Send a test of an unsaved email
POST /api/v1/sites/{id}/emails/{kind}/test
Sends the draft, with sample data, to the signed-in user only. Dashboard session only: an API key is refused. Refused while the design has errors.
Who can call it: Dashboard session only (an API key is refused).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
kind (required) | path | Which email. |
JSON body fields: subject, preheader, source.
Read the address the site's emails come from
GET /api/v1/sites/{id}/email-sender
How mail goes out now, the saved SMTP settings (password masked), the last error, and what PageHub sending looks like for this site.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Save the site's own mail server
PUT /api/v1/sites/{id}/email-sender
Owner or agency role, on a plan with own sender. Saved unverified: nothing changes until the test succeeds. Without password, the stored one is kept only if host, port and username are unchanged.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: fromName, fromEmail, replyTo, host, port, user, password.
Remove the site's own mail server
DELETE /api/v1/sites/{id}/email-sender
Back to PageHub sending. Open on every plan.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Test the site's mail server
POST /api/v1/sites/{id}/email-sender/test
Connects, logs in, and sends one email to the signed-in user from the owner's address. Success turns the sender on. Dashboard session only; owner or agency role.
Who can call it: Dashboard session only (an API key is refused).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Storefront
Stripe catalog, checkout, orders and file downloads.
Search the Stripe catalog
GET /api/v1/sites/{id}/stripe
Full-catalog tooling (not the visitor storefront). action picks the read: search, categories or product.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
action (required) | query | search \ | categories \ |
q | query | string | With search. |
category | query | string | With search. |
limit | query | integer | With search. |
sort | query | string | With search. |
id | query | string | With product: the product id. |
slug | query | string | With product. |
Refresh the products collection from Stripe
POST /api/v1/sites/{id}/stripe
action=refresh syncs the live catalog into the site's products collection.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
action (required) | query | Required. |
Read storefront settings
GET /api/v1/sites/{id}/storefront-settings
The switches for the buyer receipt, gift cards, shipping and Stripe Tax, which are all off until turned on.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Update storefront settings
PATCH /api/v1/sites/{id}/storefront-settings
Merges any subset of the keys. Needs the owner or agency role.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: allowPromoCodes, orderEmail, giftCard, shipping, tax, collectEmailConsent.
List checkout configs
GET /api/v1/sites/{id}/checkout
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Point checkout at a collection
POST /api/v1/sites/{id}/checkout
Maps a collection's price field so its rows can be sold. Map a priceId field, or give the collection a numeric price field to sell via price data.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: collectionSlug, provider, fieldMap.
Remove a collection's checkout config
DELETE /api/v1/sites/{id}/checkout
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
collectionSlug (required) | query | string | The collection's slug. |
List storefront orders
GET /api/v1/sites/{id}/orders
Newest first, read from the site's Stripe account. stripeConnected: false when none is connected. Needs the owner or agency role.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
cursor | query | string | The nextCursor of the previous page (a Checkout Session id). |
email | query | string | Only this buyer. |
Mark an order shipped
POST /api/v1/sites/{id}/orders/{orderId}/fulfilment
Also re-saves tracking. The buyer's shipped email goes out after the response, only from the request that applied the change, and only with notifyBuyer.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
orderId (required) | path | string | The order's Stripe Checkout Session id. |
JSON body fields: carrier, tracking, notifyBuyer.
Mark an order not shipped
DELETE /api/v1/sites/{id}/orders/{orderId}/fulfilment
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
orderId (required) | path | string | The order's Stripe Checkout Session id. |
Refund an order
POST /api/v1/sites/{id}/orders/{orderId}/refund
Refunds through the site's own Stripe account. This moves money. amount is in the smallest currency unit; omit it to refund everything not yet refunded.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
orderId (required) | path | string | The order's Stripe Checkout Session id. |
JSON body fields: amount.
List hosted file downloads
GET /api/v1/sites/{id}/downloads
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Publish a download or add a version
POST /api/v1/sites/{id}/downloads
Needs the owner or agency role and a plan that hosts files. Send { mediaId, filename, name?, downloadId?, label?, notes? } to publish or add a version, { downloadId, currentVersionId } to roll back or forward, or { downloadId, name } to rename. Any of these may carry access: { members, plans }; access: null makes it public. The file is a non-image upload by a site member, from private storage or a public one that is moved private here.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: mediaId, filename, name, downloadId, label, notes, currentVersionId, access.
Remove a download or one of its versions
DELETE /api/v1/sites/{id}/downloads
Files no other version uses are deleted too. The current version cannot be removed alone.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
downloadId (required) | query | string | |
versionId | query | string | Remove only this non-current version. |
Approve or decline a held order
POST /api/v1/sites/{id}/orders/{orderId}/approval
For an order whose collection's checkout holds the payment. Approving charges the held amount through the site's Stripe account (this moves money) and settles the order like a paid one: stock, customer and receipt. Declining releases the hold and emails the guest. A site without Stripe connected answers 404.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
orderId (required) | path | string | The order's Stripe Checkout Session id. |
JSON body fields: approve.
Reopen the dates an order holds
DELETE /api/v1/sites/{id}/orders/{orderId}/booking
Never refunds: refunding is its own call. A site without Stripe connected answers 404.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
orderId (required) | path | string | The order's Stripe Checkout Session id. |
List promo codes
GET /api/v1/sites/{id}/promo-codes
The promo codes on the site's own Stripe account, newest first, on and off. Needs the owner or agency role.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Create a promo code
POST /api/v1/sites/{id}/promo-codes
Creates a coupon and a promotion code on the site's own Stripe account. Give percentOff (1 to 99) or amountOff in the smallest currency unit with currency (default usd). On a booking with lodging tax, Stripe takes the same share off every line, so tax is worked out on the price after the code.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: code, percentOff, amountOff, currency, maxRedemptions, expiresAt.
Turn a promo code off or on
PATCH /api/v1/sites/{id}/promo-codes
Redemptions already made stand.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: id, active.
History
A site's revision timeline, what changed in each version, and restoring one to the draft.
List a site's revisions
GET /api/v1/sites/{id}/history
The timeline, newest first: one row per editing session, publish or restore. restorable is false for a version saved before the HTML editor (it can be listed, not diffed or restored). retention is the site owner's plan cap. Needs write access to the site (owner, editor, agency).
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
page | query | integer | Page number. |
pageSize | query | integer | Rows per page. |
Read one revision, optionally with what changed
GET /api/v1/sites/{id}/history/{revId}
With diff=prev (or another revision's id) the answer groups the changes by page: added, removed, changed and moved elements, with class changes as token sets. Capped at 500 changes (truncated, totalChanges). 409 LEGACY_REVISION for a version saved before the HTML editor.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
revId (required) | path | string | A revision's id from the history list. |
diff | query | string | prev, or the id of the revision to compare against. |
Restore a revision into the draft
POST /api/v1/sites/{id}/history/{revId}/restore
Writes the revision's files forward into the DRAFT and records a restore revision, so a restore is itself undoable; the live release is never touched, publish to make it live. A full pre-restore backup is taken first: if it fails the answer is 500 PRE_RESTORE_BACKUP_FAILED and nothing changes. scope: "page" restores one page (needs pageNodeId). Owner, editor and agency; a client or viewer cannot.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
revId (required) | path | string | A revision's id from the history list. |
JSON body fields: scope, pageNodeId.
Review
Client review comments pinned to a site's preview.
List a site's review comments
GET /api/v1/sites/{id}/review-threads
The client-review threads pinned to the site's preview, newest first, each with its messages (author emails included: you can moderate). The same list the dashboard's Review inbox shows. A signed-in team member's key (owner, editor, agency); a tenant key is refused.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
status | query | open \ | resolved \ |
pageSlug | query | string | A page's slug. Present and empty: the home page. Absent: every page. |
summary | query | 1 | Add summary (open, resolved, total, people, lastCommentAt). |
page | query | integer | Page number. |
pageSize | query | integer | Rows per page. |
Reply to a review comment
POST /api/v1/sites/{id}/review-threads/{threadId}
Posts as the key's user (max 5,000 characters, 100 replies per thread), emails the site's other owners and lands in History > Activity, like a reply from the dashboard. Replying does not reopen a resolved thread. A tenant key is refused.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
threadId (required) | path | string | A thread's id from the review-threads list. |
JSON body fields: body.
Open, resolve or close a review comment
PATCH /api/v1/sites/{id}/review-threads/{threadId}
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
threadId (required) | path | string | A thread's id from the review-threads list. |
JSON body fields: status.
Forms
A site's form submissions and the webhooks that deliver them.
List a site's form submissions
GET /api/v1/sites/{id}/submissions
The form inbox, newest first, filtered to one state (default open). Each row carries its webhook delivery status when the form has a webhook. formNames and summary ride on the first page. Reading never marks a row read. Visitor details: owner, editor and agency members.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
state | query | open \ | done \ |
formName | query | string | Only this form. |
q | query | string | Matches anywhere in the answers. |
cursor | query | string | nextCursor of the previous page. |
limit | query | integer | Rows per page. |
Read one form submission
GET /api/v1/sites/{id}/submissions/{submissionId}
The answers, how the visitor arrived (attribution), the notes and state changes (activity) and the webhook delivery. Does not mark the row read.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
submissionId (required) | path | string | A submission's _id from the list. |
Resend a submission's webhook
POST /api/v1/sites/{id}/submissions/{submissionId}/webhook
Resets the attempts and queues the delivery again from the start, to the form's current webhook URL. The submissionId in the payload never changes. Owners only: a delivery carries the lead's details to a third party. 409 when the submission has no webhook; 502 when it could not be queued.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
submissionId (required) | path | string | A submission's _id from the list. |
List the form webhook destinations and whether each has a signing secret
GET /api/v1/sites/{id}/form-webhooks
The destinations the forms on the LIVE release post to (URL without its query string), with the forms that use each. A secret is never returned. Owners only.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
Rotate or set a form webhook's signing secret
POST /api/v1/sites/{id}/form-webhooks
rotate mints a new secret and returns it ONCE; set stores the secret the receiver issued (16 to 256 characters, no spaces) and returns nothing. endpoint is the key the list returned: the URL never comes from the caller. Receivers verify X-PageHub-Signature: sha256=<hex HMAC-SHA256 of "<X-PageHub-Timestamp>.<raw body>">. Owners only.
Who can call it: API key (or the dashboard session).
| Parameter | In | Type | What it is |
|---|---|---|---|
id (required) | path | string | The site's id. |
JSON body fields: endpoint, action, secret.