Management API

Everything the dashboard does, for your own automation, partner platforms and AI assistants: accounts and sub-accounts, sites and all their settings, cookie lists, scans, consent proof, statistics and webhooks.

Basics

  • Base address: https://cmp-app.trackable.digital/api/v1
  • The full description, for tools and code generators: openapi.json (OpenAPI 3.1, no key needed).
  • Keys are made in the dashboard (API and AI assistants). The secret is shown once; we keep only a hash of it.
curl https://cmp-app.trackable.digital/api/v1/sites -H "Authorization: Bearer tcmp_…"

Scopes

ScopeAllows
readEverything readable: sites, settings, cookie lists, scans, consent proof, statistics, compliance, experiments
writePlus creating, changing and deleting sites, replacing cookie lists, running scans, fixes, imports and experiments
adminPlus organisations, members, API keys, webhooks and what the consent log keeps

A key acts on its own account and every sub-account below it, so an agency's key reaches all its clients. Limit: 120 requests a minute per key.

Errors

Errors look like { "error": { "code": "…", "message": "…", "details": … } }.

StatusWhen
400Invalid JSON, an unknown field or a wrong type (details lists each problem)
401Missing, unknown or revoked key
403The key lacks the scope
404Not found, or outside the key's accounts (the same answer on purpose)
409A domain another site has, or deleting an account that still has sites
422Valid JSON that is not allowed, such as an unreadable colour
429Over the rate limit

Endpoints

Account

  • GET/meread

    The calling key, its scopes and organisation

Organisations

Accounts and sub-accounts (agency → client).

  • GET/organisationsread

    List the key's organisation and its sub-accounts

  • POST/organisationsadmin

    Create a sub-account (parentId defaults to the key's organisation)

  • GET/organisations/{id}read

    Get an organisation

  • PATCH/organisations/{id}admin

    Rename or change kind

  • DELETE/organisations/{id}admin

    Delete an empty organisation (no sites, sub-accounts or kept consent records)

Members

  • GET/organisations/{id}/membersread

    People with dashboard access, and pending invitations

  • POST/organisations/{id}/membersadmin

    Give a person access; without an account they are invited: the answer has signUpUrl, their invitation link (signing up needs it)

  • DELETE/organisations/{id}/members/{email}admin

    Remove a member or invitation

Sites

Domain groups: one banner configuration for one or more domains.

  • GET/sitesread

    List domain groups

    Query: organisationId (Only this organisation and its sub-accounts), domain (Only the site with this hostname), verified (true: only where that hostname is verified), limit (1–200, default 50), offset (Default 0)

  • POST/siteswrite

    Create a domain group; any settings not given use the defaults

  • GET/sites/{key}read

    Get a domain group with settings and install code

  • PATCH/sites/{key}write

    Change any settings (partial; nested objects merge; null clears gtm, cookieDomain, loaderUrl). Publishes a new config version when the banner config changes

  • DELETE/sites/{key}write

    Delete: the banner stops and the site is hidden; consent records are kept for their retention period

  • GET/sites/{key}/installread

    Install code: recommended (hybrid), same-origin, quick, the cookie declaration embed, and the step-by-step guide for the site's platform

    Query: platform (Show the guide for another platform: wordpress, shopify, webflow, wix, squarespace, framer, hubspot, ghost, bigcommerce, godaddy, hostinger-builder, duda, nextjs, nuxt, astro, gatsby, drupal, joomla, custom)

  • GET/sites/{key}/domainsread

    Each domain: verified or not (verifiedBy: install, dns or before-verification), the last check's reason, and for unverified ones the DNS TXT record that proves them. The banner works on every domain; verified ones belong to this account only, and the Shopify app and server-side tracking connect only to verified domains. Checked again automatically

  • POST/sites/{key}/domains/verifywrite

    Check the unverified domains now: this site's banner on the homepage (directly or through a GTM container), or the DNS TXT record. Returns every domain's state

  • GET/sites/{key}/platformread

    The site's platform, the last detection with its evidence, and every platform there is a guide for

  • POST/sites/{key}/platform/detectwrite

    Read the homepage: platform with evidence, CDN, other cookie banners, GTM containers, whether this banner is installed (on the page or through a GTM container it loads); a confident answer becomes the site's platform unless apply is false. Returns the install guide

  • GET/sites/{key}/versionsread

    Published versions, newest first (kept as evidence)

    Query: body (1 to include each version's settings)

Cookies

  • GET/sites/{key}/cookiesread

    The cookie list (kept current by automatic scans)

  • PUT/sites/{key}/cookieswrite

    Replace the cookie list. Entries sent count as decided by a person (scans keep them); entries left out are removed

Scans

  • GET/sites/{key}/scansread

    Recent scans

  • POST/sites/{key}/scanswrite

    Scan now (about a minute) and update the cookie list; with region, check the banner as a visitor from there instead (evidence only)

  • GET/sites/{key}/scans/{id}read

    A scan's full report, including Google Consent Mode as Google received it per stage (decoded gcd); format=markdown for the report as Markdown

    Query: format (markdown)

Compliance

The compliance score and its one-click fixes.

  • GET/sites/{key}/complianceread

    The compliance score (0–100) and risk per region, every check with its fix, and what to fix first

    Query: region (uk | eu | us; all three when left out)

  • POST/sites/{key}/fixeswrite

    Apply a one-click fix from the compliance score

Migration

Switching from Cookiebot.

  • POST/sites/{key}/cookiebot/bannerwrite

    Import the site's Cookiebot banner (wording in every language it has, layout) and publish it

  • POST/sites/{key}/cookiebot/cookieswrite

    Add the cookies in the site's Cookiebot declaration (found by a scan) that the cookie list lacks

Server-side tracking

Optional connection to Trackable SST (server-side GTM). The banner works without it and SST works with any consent tool; connected, both sides can be checked together.

  • GET/sites/{key}/sstread

    The connected Trackable SST site and its status: tagging server health, GTM container refreshed in the last 5 minutes, client hostnames. 404 when not connected

  • POST/sites/{key}/sstwrite

    Connect an existing Trackable SST site (created through the SST API). The SST site must be for one of this site's domains, and that domain not another account's site (403 otherwise; Trackable can connect it). Optional: SST works with any consent tool, and this banner works without SST. With applyToBanner, the banner loads the SST site's GTM container through SST (a new version; visitors are not asked again)

  • DELETE/sites/{key}/sstwrite

    Disconnect. The SST site keeps running and the banner keeps its settings

  • POST/sites/{key}/sst/verifywrite

    Check the banner and server-side tracking together: same site, the banner loads the GTM container SST expects (through SST), tracking works end to end, and every hit SST received carries the banner's consent signal. Each check is pass, warn or fail; ok means nothing failed. Sends one debug GA4 hit

Experiments

A/B tests of the banner, with sequential analysis per region.

  • GET/sites/{key}/experimentsread

    Banner experiments, running first; sticky = a returning visitor keeps their arm

  • POST/sites/{key}/experimentswrite

    Create a draft: the full experiment, or { template } (with optional name, hypothesis, regions, mainRegion, mdePoints, confidence)

  • GET/sites/{key}/experiments/templatesread

    Ready-made first experiments from published evidence, each with the draft it creates for this banner (null: does not apply)

  • PUT/sites/{key}/experiments/settingswrite

    Experiment settings for the site

  • GET/sites/{key}/experiments/{id}read

    One experiment with its results per region (live while running, frozen once ended); a draft gets its problems and a duration forecast

  • DELETE/sites/{key}/experiments/{id}write

    Delete a draft

  • POST/sites/{key}/experiments/{id}/startwrite

    Start a draft (one running experiment per site)

  • POST/sites/{key}/experiments/{id}/stopwrite

    Stop a running experiment and freeze its result; apply publishes the winning arm as the banner

Insights

Anonymised industry benchmarks for sites that share their own results.

  • GET/benchmarksread

    Industry benchmarks without a site (for businesses not on the CMP yet): the narrowest anonymised cells for a sector, subsector and business model in one jurisdiction; empty until enough sites share

    Query: sector (Sector id from the taxonomy), subsector (Subsector id (default other)), model (Business model, e.g. ecommerce), region (Jurisdiction, default trackable_uk_opt_in)

  • GET/sites/{key}/insightsread

    Own rates, and (profile confirmed, sharing on) industry benchmarks, best-banner traits, pooled learnings and the next experiment to run

    Query: region (Jurisdiction compared, e.g. trackable_uk_opt_in; default: the one with most visitors)

  • GET/sites/{key}/insights/profileread

    The business profile benchmarks are matched on

  • PUT/sites/{key}/insights/profilewrite

    Confirm the business profile

  • PUT/sites/{key}/insights/opt-inwrite

    Share anonymised results (and see the industry's); turning on needs agree: true

Tracking

GTM container audit and the sGTM template.

  • POST/gtm-auditread

    Audit a GTM container export (web or server) for consent problems and get a fixed copy to import. Nothing is stored. Up to 10 MB

  • GET/sgtm-templateread

    The sGTM variable template that verifies the signed consent cookie, with the steps to use it

Audits

Prospect audits: scans of any address.

  • GET/auditsread

    Prospect audits (scans of any address, not tied to a site) of your organisation

  • POST/auditswrite

    Audit any public address now (about a minute)

  • GET/audits/{id}read

    One prospect audit's full report; format=markdown for Markdown

    Query: format (markdown)

Webhooks

  • GET/webhooksadmin

    List webhooks

  • POST/webhooksadmin

    Add a webhook (public https only). The signing secret is returned once

  • DELETE/webhooks/{id}admin

    Delete a webhook

  • POST/webhooks/{id}/testadmin

    Send a test delivery (event webhook.test)

API keys

  • GET/api-keysadmin

    List keys (never their secrets)

  • POST/api-keysadmin

    Create a key for this organisation or a sub-account, with at most the caller's scopes. The secret is returned once

  • DELETE/api-keys/{id}admin

    Revoke a key

Billing

  • GET/sites/{key}/billingread

    The site's plan and product, who pays (self, parent, shopify), and any notice (choosePlan: the plan a Shopify store is asked to choose)

  • PUT/sites/{key}/billingadmin

    Platform keys only: a Shopify store's plan from its Shopify subscription ({"plan": "starter", "payer": "shopify"}). The account is then billed by Shopify, never by our Stripe

Partners

  • GET/partnersread

    The partner directory: Certified and Premier agencies that install Trackable CMP, Premier first, then the best fit for a platform and region

    Query: platform (Platform id, e.g. shopify), region (uk | eu | us | ca | au | other)

  • GET/partnerread

    A partner's tier, active paid sites, what the next tier needs, benefits, referral code and link, credits owed and paid, referred accounts and deals

    Query: organisationId (The partner (default: the key's organisation))

  • POST/partner/dealswrite

    Register a prospect's domain as a deal: for 90 days a direct sign-up with it is the partner's referral. Refused when the domain is already a customer or another partner registered it first

  • PUT/organisations/{id}/agencyadmin

    Move a client account under another agency. Platform keys move it at once; the client account's own key asks, and an admin of that agency accepts in the dashboard (Clients): the answer is then {id, requested: true, agencyId}. Sites and consent records stay with the client; the old agency loses access once it moves

Next: AI assistants