API reference

Domains

Add, verify and remove the sites a workspace covers, and read their install instructions.

  1. GET/v1/domains
  2. POST/v1/domains
  3. GET/v1/domains/availability
  4. GET/v1/domains/transfers
  5. GET/v1/domains/transfers/{id}
  6. POST/v1/domains/transfers/{id}/accept
  7. POST/v1/domains/transfers/{id}/cancel
  8. POST/v1/domains/transfers/{id}/decline
  9. POST/v1/domains/{domainId}/transfer
  10. GET/v1/domains/{domainId}/transfer/preflight
  11. DELETE/v1/domains/{id}
  12. GET/v1/domains/{id}
  13. PATCH/v1/domains/{id}
  14. GET/v1/domains/{id}/instructions
  15. POST/v1/domains/{id}/verify
  16. GET/v1/install/instructions
GET/v1/domains

Domains in this workspace, filterable, with a count per status

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
statusquery"pending" | "verified" | "failed"Verification status.
groupIdquerystring (uuid)Only domains in this group.
qquerystringCase-insensitive hostname search.
sortquery"createdAt" | "hostname" | "status"Sort field (default createdAt).
orderquery"asc" | "desc"Sort direction (default desc).
Responses
StatusBodyWhen
200DomainListDto
200 body · DomainListDto
FieldTypeWhat it is
items requiredDomainDto[]
items[].id requiredstring
items[].hostname requiredstring
items[].rootDomain requiredstringThe registrable domain this hostname belongs to — the unit the plan bills.
items[].billedAs required"root" | "included" | "extra"How this hostname is billed. A billed domain is the root domain, www and up to two further subdomains: root is the billed unit, included is covered by its root at no extra cost, and extra is a third or later subdomain that counts as another domain.
items[].status required"pending" | "verified" | "failed"
items[].verifyMethod required"script" | "dns_txt" | "meta_tag" | "file"
items[].verifyToken requiredstring
items[].verifiedAt requiredstring | nullISO timestamp, or null if not yet verified.
items[].verifyReason requiredstring | nullWhy the last check failed, in words meant for the customer. Null when the domain is verified or has never been checked.
items[].lastCheckedAt requiredstring | nullISO timestamp of the last verification attempt, or null if never attempted.
items[].sslOk requiredboolean
items[].groupId requiredstring | nullGroup this domain belongs to, or null if ungrouped.
items[].region required"EU" | "US-CA" | "UK" | "GLOBAL" | nullCompliance jurisdiction the owner declared for this domain, or null if unset.
items[].installMethod required"script" | "wordpress" | "gtm" | "shopify" | "wix"How the tag is installed on this site. Decides which instructions the panel shows; the tag itself is the same on every route.
items[].createdAt requiredstring
items[].score requirednumberLive compliance score (0–100) for this domain's banner: the same score the Compliance screen shows. It uses the published banner, else the draft, else the default banner.
items[].overAllowance requiredbooleanTrue when the workspace's plan does not cover this domain. Its banner is held unpublished, and publishing is refused until the plan allows more domains or another domain is removed. This happens only after a downgrade: adding a domain over the limit is refused.
items[].lastScanAt requiredstring | nullWhen this domain was last scanned, whether the scan completed, was blocked or failed. Null when it has never been scanned.
items[].activeScan requiredobject
facets requiredDomainFacetsDto
facets.all requirednumber
facets.pending requirednumber
facets.verified requirednumber
facets.failed requirednumber
total requirednumberRows matching ALL active filters, i.e. the size of items before any paging.
allowance requiredDomainAllowanceDtoComputed over every domain in the workspace, whatever the filters.
allowance.limit requirednumber | null
allowance.used requirednumber
POST/v1/domains

Add a domain (starts pending verification)

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Request body · CreateDomainDto
FieldTypeWhat it is
hostname requiredstringA hostname or URL; normalized server-side (scheme/path/port stripped).
verifyMethod"script" | "dns_txt" | "meta_tag" | "file"Preferred ownership-verification method (defaults to dns_txt).
region"EU" | "US-CA" | "UK" | "GLOBAL"The compliance region the owner says this domain serves. Informational: it does not change what the banner does.
installMethod"script" | "wordpress" | "gtm" | "shopify" | "wix"How the owner will put the tag on the site. Picks which install instructions the panel shows; defaults to a plain script tag.
Responses
StatusBodyWhen
201DomainDto
201 body · DomainDto
FieldTypeWhat it is
id requiredstring
hostname requiredstring
rootDomain requiredstringThe registrable domain this hostname belongs to — the unit the plan bills.
billedAs required"root" | "included" | "extra"How this hostname is billed. A billed domain is the root domain, www and up to two further subdomains: root is the billed unit, included is covered by its root at no extra cost, and extra is a third or later subdomain that counts as another domain.
status required"pending" | "verified" | "failed"
verifyMethod required"script" | "dns_txt" | "meta_tag" | "file"
verifyToken requiredstring
verifiedAt requiredstring | nullISO timestamp, or null if not yet verified.
verifyReason requiredstring | nullWhy the last check failed, in words meant for the customer. Null when the domain is verified or has never been checked.
lastCheckedAt requiredstring | nullISO timestamp of the last verification attempt, or null if never attempted.
sslOk requiredboolean
groupId requiredstring | nullGroup this domain belongs to, or null if ungrouped.
region required"EU" | "US-CA" | "UK" | "GLOBAL" | nullCompliance jurisdiction the owner declared for this domain, or null if unset.
installMethod required"script" | "wordpress" | "gtm" | "shopify" | "wix"How the tag is installed on this site. Decides which instructions the panel shows; the tag itself is the same on every route.
createdAt requiredstring
score requirednumberLive compliance score (0–100) for this domain's banner: the same score the Compliance screen shows. It uses the published banner, else the draft, else the default banner.
overAllowance requiredbooleanTrue when the workspace's plan does not cover this domain. Its banner is held unpublished, and publishing is refused until the plan allows more domains or another domain is removed. This happens only after a downgrade: adding a domain over the limit is refused.
lastScanAt requiredstring | nullWhen this domain was last scanned, whether the scan completed, was blocked or failed. Null when it has never been scanned.
activeScan requiredobject
activeScan.status required"queued" | "running"
activeScan.pagesCrawled requirednumber
activeScan.pagesPlanned requirednumber | null
GET/v1/domains/availability

Check whether a hostname can be added to this workspace (advisory)

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
hostname requiredquerystringA hostname or full URL
Responses
StatusBodyWhen
200DomainAvailabilityDto
200 body · DomainAvailabilityDto
FieldTypeWhat it is
hostname requiredstringThe normalised form the check was actually run against; "" if nothing was left.
available requiredboolean
reason required"taken" | "invalid" | null
message requiredstring | nullA sentence to show the customer, or null when the domain is available.
existingDomainId requiredstring | nullThe id of the existing domain when reason is "taken" — otherwise null.
GET/v1/domains/transfers

Domain transfers in both directions

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Responses
StatusBodyWhen
200DomainTransfersDto
200 body · DomainTransfersDto
FieldTypeWhat it is
outgoing requiredDomainTransferDto[]Offers made by this workspace.
outgoing[].id requiredstring
outgoing[].domainId requiredstring
outgoing[].hostname requiredstringThe hostname as it was when offered.
outgoing[].status required"pending" | "accepted" | "declined" | "cancelled"
outgoing[].notestring | null
outgoing[].fromWorkspaceName requiredstring
outgoing[].fromWorkspaceSlug requiredstring
outgoing[].toWorkspaceName requiredstring
outgoing[].toWorkspaceSlug requiredstring
outgoing[].expiresAt requiredstringAfter this, the offer lapses and the link stops working.
outgoing[].respondedAtstring | null
outgoing[].createdAt requiredstring
incoming requiredDomainTransferDto[]Offers made to this workspace.
incoming[].id requiredstring
incoming[].domainId requiredstring
incoming[].hostname requiredstringThe hostname as it was when offered.
incoming[].status required"pending" | "accepted" | "declined" | "cancelled"
incoming[].notestring | null
incoming[].fromWorkspaceName requiredstring
incoming[].fromWorkspaceSlug requiredstring
incoming[].toWorkspaceName requiredstring
incoming[].toWorkspaceSlug requiredstring
incoming[].expiresAt requiredstringAfter this, the offer lapses and the link stops working.
incoming[].respondedAtstring | null
incoming[].createdAt requiredstring
GET/v1/domains/transfers/{id}

Review an offer from its emailed link

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
token requiredquerystring
Responses
StatusBodyWhen
200DomainTransferDto
403—The token does not match this transfer.
200 body · DomainTransferDto
FieldTypeWhat it is
id requiredstring
domainId requiredstring
hostname requiredstringThe hostname as it was when offered.
status required"pending" | "accepted" | "declined" | "cancelled"
notestring | null
fromWorkspaceName requiredstring
fromWorkspaceSlug requiredstring
toWorkspaceName requiredstring
toWorkspaceSlug requiredstring
expiresAt requiredstringAfter this, the offer lapses and the link stops working.
respondedAtstring | null
createdAt requiredstring
POST/v1/domains/transfers/{id}/accept

Accept a domain into this workspace

Moves the domain, its banner configuration and its entire consent log. The domain keeps its id, so the tag on the site is unaffected and the banner does not go down.

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
Request body · RespondToDomainTransferDto
FieldTypeWhat it is
token requiredstringThe secret half of the link, after the dot.
Responses
StatusBodyWhen
201DomainTransferDto
409—Already answered, expired, the domain has moved on, this workspace already has that hostname, or its plan has no room for another domain.
201 body · DomainTransferDto
FieldTypeWhat it is
id requiredstring
domainId requiredstring
hostname requiredstringThe hostname as it was when offered.
status required"pending" | "accepted" | "declined" | "cancelled"
notestring | null
fromWorkspaceName requiredstring
fromWorkspaceSlug requiredstring
toWorkspaceName requiredstring
toWorkspaceSlug requiredstring
expiresAt requiredstringAfter this, the offer lapses and the link stops working.
respondedAtstring | null
createdAt requiredstring
POST/v1/domains/transfers/{id}/cancel

Withdraw an offer this workspace made

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
Responses
StatusBodyWhen
201DomainTransferDto
201 body · DomainTransferDto
FieldTypeWhat it is
id requiredstring
domainId requiredstring
hostname requiredstringThe hostname as it was when offered.
status required"pending" | "accepted" | "declined" | "cancelled"
notestring | null
fromWorkspaceName requiredstring
fromWorkspaceSlug requiredstring
toWorkspaceName requiredstring
toWorkspaceSlug requiredstring
expiresAt requiredstringAfter this, the offer lapses and the link stops working.
respondedAtstring | null
createdAt requiredstring
POST/v1/domains/transfers/{id}/decline

Refuse an offered domain

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
Request body · RespondToDomainTransferDto
FieldTypeWhat it is
token requiredstringThe secret half of the link, after the dot.
Responses
StatusBodyWhen
201DomainTransferDto
201 body · DomainTransferDto
FieldTypeWhat it is
id requiredstring
domainId requiredstring
hostname requiredstringThe hostname as it was when offered.
status required"pending" | "accepted" | "declined" | "cancelled"
notestring | null
fromWorkspaceName requiredstring
fromWorkspaceSlug requiredstring
toWorkspaceName requiredstring
toWorkspaceSlug requiredstring
expiresAt requiredstringAfter this, the offer lapses and the link stops working.
respondedAtstring | null
createdAt requiredstring
POST/v1/domains/{domainId}/transfer

Offer a domain to another workspace

Owner-level: from this workspace's point of view the outcome is the same as deleting the domain. Nothing moves until the destination accepts from the one-time link emailed to its owners and admins — which is not returned here.

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
domainId requiredpathstring
Request body · RequestDomainTransferDto
FieldTypeWhat it is
toWorkspaceSlug requiredstringThe destination workspace's address — the subdomain it answers on. Named by slug rather than by email so the offer can only reach people who could act on it, and so "which of their workspaces?" has one answer. Example: "acme"
notestringShown to the recipient on the acceptance screen and in the email.
Responses
StatusBodyWhen
201DomainTransferDto
409—Already offered, or the destination cannot take it.
201 body · DomainTransferDto
FieldTypeWhat it is
id requiredstring
domainId requiredstring
hostname requiredstringThe hostname as it was when offered.
status required"pending" | "accepted" | "declined" | "cancelled"
notestring | null
fromWorkspaceName requiredstring
fromWorkspaceSlug requiredstring
toWorkspaceName requiredstring
toWorkspaceSlug requiredstring
expiresAt requiredstringAfter this, the offer lapses and the link stops working.
respondedAtstring | null
createdAt requiredstring
GET/v1/domains/{domainId}/transfer/preflight

What moving this domain would take with it

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
domainId requiredpathstring
Responses
StatusBodyWhen
200DomainTransferPreflightDto
200 body · DomainTransferPreflightDto
FieldTypeWhat it is
hostname requiredstring
consentRecords requirednumberConsent receipts that move — the evidence.
impressions requirednumberImpressions recorded against this domain.
scans requirednumber
cookies requirednumber
published requiredbooleanWhether a banner is currently live on the site.
exportComplete requiredbooleanFalse when there are more consent records than one export can carry, so the copy the sender keeps would be incomplete.
pendingTransferIdstring | nullAn offer already open for this domain, if there is one.
DELETE/v1/domains/{id}

Remove a domain

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
Responses
StatusBodyWhen
204—
GET/v1/domains/{id}

Get a single domain

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
Responses
StatusBodyWhen
200DomainDto
200 body · DomainDto
FieldTypeWhat it is
id requiredstring
hostname requiredstring
rootDomain requiredstringThe registrable domain this hostname belongs to — the unit the plan bills.
billedAs required"root" | "included" | "extra"How this hostname is billed. A billed domain is the root domain, www and up to two further subdomains: root is the billed unit, included is covered by its root at no extra cost, and extra is a third or later subdomain that counts as another domain.
status required"pending" | "verified" | "failed"
verifyMethod required"script" | "dns_txt" | "meta_tag" | "file"
verifyToken requiredstring
verifiedAt requiredstring | nullISO timestamp, or null if not yet verified.
verifyReason requiredstring | nullWhy the last check failed, in words meant for the customer. Null when the domain is verified or has never been checked.
lastCheckedAt requiredstring | nullISO timestamp of the last verification attempt, or null if never attempted.
sslOk requiredboolean
groupId requiredstring | nullGroup this domain belongs to, or null if ungrouped.
region required"EU" | "US-CA" | "UK" | "GLOBAL" | nullCompliance jurisdiction the owner declared for this domain, or null if unset.
installMethod required"script" | "wordpress" | "gtm" | "shopify" | "wix"How the tag is installed on this site. Decides which instructions the panel shows; the tag itself is the same on every route.
createdAt requiredstring
score requirednumberLive compliance score (0–100) for this domain's banner: the same score the Compliance screen shows. It uses the published banner, else the draft, else the default banner.
overAllowance requiredbooleanTrue when the workspace's plan does not cover this domain. Its banner is held unpublished, and publishing is refused until the plan allows more domains or another domain is removed. This happens only after a downgrade: adding a domain over the limit is refused.
lastScanAt requiredstring | nullWhen this domain was last scanned, whether the scan completed, was blocked or failed. Null when it has never been scanned.
activeScan requiredobject
activeScan.status required"queued" | "running"
activeScan.pagesCrawled requirednumber
activeScan.pagesPlanned requirednumber | null
PATCH/v1/domains/{id}

Update a domain (assign/clear its group, change its region)

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
Request body · UpdateDomainDto
FieldTypeWhat it is
groupIdstring (uuid) | nullAssign the domain to a group (uuid), or null to ungroup.
region"EU" | "US-CA" | "UK" | "GLOBAL"Compliance jurisdiction the owner says this domain serves.
installMethod"script" | "wordpress" | "gtm" | "shopify" | "wix"Change how the tag is installed — the panel's instructions follow it.
deepScanbooleanNominate this domain for the monthly deep scan. Agency and above. The plan caps how many may be nominated at once — an agency with fifty client sites gets five, because the deep scan is the answer to "which one matters this month" and a deep scan of everything is just a very expensive routine scan.
Responses
StatusBodyWhen
200DomainDto
200 body · DomainDto
FieldTypeWhat it is
id requiredstring
hostname requiredstring
rootDomain requiredstringThe registrable domain this hostname belongs to — the unit the plan bills.
billedAs required"root" | "included" | "extra"How this hostname is billed. A billed domain is the root domain, www and up to two further subdomains: root is the billed unit, included is covered by its root at no extra cost, and extra is a third or later subdomain that counts as another domain.
status required"pending" | "verified" | "failed"
verifyMethod required"script" | "dns_txt" | "meta_tag" | "file"
verifyToken requiredstring
verifiedAt requiredstring | nullISO timestamp, or null if not yet verified.
verifyReason requiredstring | nullWhy the last check failed, in words meant for the customer. Null when the domain is verified or has never been checked.
lastCheckedAt requiredstring | nullISO timestamp of the last verification attempt, or null if never attempted.
sslOk requiredboolean
groupId requiredstring | nullGroup this domain belongs to, or null if ungrouped.
region required"EU" | "US-CA" | "UK" | "GLOBAL" | nullCompliance jurisdiction the owner declared for this domain, or null if unset.
installMethod required"script" | "wordpress" | "gtm" | "shopify" | "wix"How the tag is installed on this site. Decides which instructions the panel shows; the tag itself is the same on every route.
createdAt requiredstring
score requirednumberLive compliance score (0–100) for this domain's banner: the same score the Compliance screen shows. It uses the published banner, else the draft, else the default banner.
overAllowance requiredbooleanTrue when the workspace's plan does not cover this domain. Its banner is held unpublished, and publishing is refused until the plan allows more domains or another domain is removed. This happens only after a downgrade: adding a domain over the limit is refused.
lastScanAt requiredstring | nullWhen this domain was last scanned, whether the scan completed, was blocked or failed. Null when it has never been scanned.
activeScan requiredobject
activeScan.status required"queued" | "running"
activeScan.pagesCrawled requirednumber
activeScan.pagesPlanned requirednumber | null
GET/v1/domains/{id}/instructions

Ownership-verification instructions for a domain

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
methodquery"dns_txt" | "meta_tag" | "file" | "script"
Responses
StatusBodyWhen
200VerificationInstructionsDto
200 body · VerificationInstructionsDto
FieldTypeWhat it is
method required"script" | "dns_txt" | "meta_tag" | "file"
recordName requiredstringDNS record name (dns_txt), e.g. "_cmpstack.example.com".
recordType requiredstring
recordValue requiredstringThe exact value to publish (TXT value / meta content / file contents).
humanInstructions requiredstring
POST/v1/domains/{id}/verify

Attempt to verify domain ownership now

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Parameters
NameWhereTypeWhat it is
id requiredpathstring
Request body · VerifyDomainDto
FieldTypeWhat it is
verifyMethod"script" | "dns_txt" | "meta_tag" | "file"Override the method to verify with; also persisted as the domain's method.
Responses
StatusBodyWhen
200VerifyResultDto
200 body · VerifyResultDto
FieldTypeWhat it is
verified requiredboolean
status required"pending" | "verified" | "failed"
reason requiredstring | nullSpecific, actionable failure reason. Null when verified is true.
target requiredstringThe URL or DNS record name we actually checked.
checkedAt requiredstringISO timestamp of this attempt.
GET/v1/install/instructions

Install instructions per route, including the denied-first Consent Mode snippet

Needs: A signed-in panel session, sent as Authorization: Bearer <access token>.

Responses
StatusBodyWhen
200InstallInstructionsDto
200 body · InstallInstructionsDto
FieldTypeWhat it is
deniedFirst requiredDeniedFirstDto
deniedFirst.snippet requiredstringThe whole block, <script> element included, ready to paste above the tag.
deniedFirst.js requiredstringThe two lines inside it, for routes that wrap them in their own element.
deniedFirst.explanation requiredstringOne line on what it does, shown beside it.
deniedFirst.limitation requiredstringGoogle tags only — stated wherever the snippet is.
routes requiredInstallRouteDto[]
routes[].download requiredInstallDownloadDto | nullA file to fetch first, or null.
routes[].tagForm required"attributes" | "url"How the tag carries its Site ID on this route: attributes (data-site, data-api) or url (?site=…&api=…), for places that drop attributes.
routes[].method required"script" | "wordpress" | "gtm" | "shopify" | "wix"
routes[].name requiredstringThe route as a person names it: "WordPress".
routes[].summary requiredstringOne line saying what installing this way involves.
routes[].steps requiredstring[]What to do, in order. Three marks and no others: **what to press**, *a value to choose* and ` something typed `.
routes[].snippetLabel requiredstring | nullWhat the box holding the snippet is called, or null where nothing is pasted.
routes[].deniedFirst required"paste" | "emitted" | "template"How this route gets the call onto the page: paste shows the snippet above the tag, emitted means the integration prints it, template means the GTM template sets the same default itself.
routes[].placement requiredstringWhere the call goes on this route.
routes[].cannotReach requiredstring | nullWhere it cannot reach on this route and what covers that instead, or null.

Next groupClients