{"openapi":"3.1.0","info":{"title":"Trackable CMP management API","version":"1.0.0","description":"Everything the dashboard does, for automation: accounts and sub-accounts, domain groups (sites) and all their settings, cookie lists, scans, consent proof, statistics, webhooks and API keys.\n\nAuthenticate with `Authorization: Bearer tcmp_…`. A key acts on its organisation and every sub-account below it; a platform key acts on all. Scopes: `read`, `write` (implies read), `admin` (implies both; accounts, members, keys, webhooks). At most 120 requests per minute per key.\n\nErrors: `{ \"error\": { \"code\", \"message\", \"details?\" } }`."},"servers":[{"url":"https://cmp-app.trackable.digital/api/v1"}],"security":[{"bearer":[]}],"tags":[{"name":"Account"},{"name":"Organisations","description":"Accounts and sub-accounts (agency → client)."},{"name":"Members"},{"name":"Sites","description":"Domain groups: one banner configuration for one or more domains."},{"name":"Cookies"},{"name":"Scans"},{"name":"Consent"},{"name":"Compliance","description":"The compliance score and its one-click fixes."},{"name":"Migration","description":"Switching from Cookiebot."},{"name":"Server-side tracking","description":"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."},{"name":"Experiments","description":"A/B tests of the banner, with sequential analysis per region."},{"name":"Insights","description":"Anonymised industry benchmarks for sites that share their own results."},{"name":"Tracking","description":"GTM container audit and the sGTM template."},{"name":"Audits","description":"Prospect audits: scans of any address."},{"name":"Webhooks"},{"name":"API keys"},{"name":"Billing"}],"paths":{"/me":{"get":{"tags":["Account"],"summary":"The calling key, its scopes and organisation","description":"The calling key, its scopes and organisation\n\nScope: `read`.","x-scope":"read","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/organisations":{"get":{"tags":["Organisations"],"summary":"List the key's organisation and its sub-accounts","description":"List the key's organisation and its sub-accounts\n\nScope: `read`.","x-scope":"read","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Organisation"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Organisations"],"summary":"Create a sub-account (parentId defaults to the key's organisation)","description":"Create a sub-account (parentId defaults to the key's organisation)\n\nScope: `admin`.","x-scope":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"parentId":{"type":["string","null"],"format":"uuid"},"kind":{"enum":["direct","agency","client"]}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organisation"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/organisations/{id}":{"get":{"tags":["Organisations"],"summary":"Get an organisation","description":"Get an organisation\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"id","in":"path","required":true,"description":"Organisation id","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organisation"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"patch":{"tags":["Organisations"],"summary":"Rename or change kind","description":"Rename or change kind\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Organisation id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"kind":{"enum":["direct","agency","client"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organisation"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Organisations"],"summary":"Delete an empty organisation (no sites, sub-accounts or kept consent records)","description":"Delete an empty organisation (no sites, sub-accounts or kept consent records)\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Organisation id","schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/organisations/{id}/members":{"get":{"tags":["Members"],"summary":"People with dashboard access, and pending invitations","description":"People with dashboard access, and pending invitations\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"id","in":"path","required":true,"description":"Organisation id","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Member"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Members"],"summary":"Give a person access; without an account they are invited: the answer has signUpUrl, their invitation link (signing up needs it)","description":"Give a person access; without an account they are invited: the answer has signUpUrl, their invitation link (signing up needs it)\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Organisation id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"role":{"enum":["owner","admin","editor","viewer"]}}}}}},"responses":{"201":{"description":"Added or invited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/organisations/{id}/members/{email}":{"delete":{"tags":["Members"],"summary":"Remove a member or invitation","description":"Remove a member or invitation\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Organisation id","schema":{"type":"string"}},{"name":"email","in":"path","required":true,"description":"Email address","schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites":{"get":{"tags":["Sites"],"summary":"List domain groups","description":"List domain groups\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"organisationId","in":"query","required":false,"description":"Only this organisation and its sub-accounts","schema":{"type":"string"}},{"name":"domain","in":"query","required":false,"description":"Only the site with this hostname","schema":{"type":"string"}},{"name":"verified","in":"query","required":false,"description":"true: only where that hostname is verified","schema":{"type":"boolean"}},{"name":"limit","in":"query","required":false,"description":"1–200, default 50","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Default 0","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Site"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Sites"],"summary":"Create a domain group; any settings not given use the defaults","description":"Create a domain group; any settings not given use the defaults\n\nScope: `write`.","x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Settings"},{"type":"object","required":["name","domains"],"properties":{"organisationId":{"type":"string","format":"uuid","description":"Required with a platform key; defaults to the key's organisation"}}}]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}":{"get":{"tags":["Sites"],"summary":"Get a domain group with settings and install code","description":"Get a domain group with settings and install code\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"patch":{"tags":["Sites"],"summary":"Change any settings (partial; nested objects merge; null clears gtm, cookieDomain, loaderUrl). Publishes a new config version when the banner config changes","description":"Change any settings (partial; nested objects merge; null clears gtm, cookieDomain, loaderUrl). Publishes a new config version when the banner config changes\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Sites"],"summary":"Delete: the banner stops and the site is hidden; consent records are kept for their retention period","description":"Delete: the banner stops and the site is hidden; consent records are kept for their retention period\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/install":{"get":{"tags":["Sites"],"summary":"Install code: recommended (hybrid), same-origin, quick, the cookie declaration embed, and the step-by-step guide for the site's platform","description":"Install code: recommended (hybrid), same-origin, quick, the cookie declaration embed, and the step-by-step guide for the site's platform\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"platform","in":"query","required":false,"description":"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","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/billing":{"get":{"tags":["Billing"],"summary":"The site's plan and product, who pays (self, parent, shopify), and any notice (choosePlan: the plan a Shopify store is asked to choose)","description":"The site's plan and product, who pays (self, parent, shopify), and any notice (choosePlan: the plan a Shopify store is asked to choose)\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"put":{"tags":["Billing"],"summary":"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","description":"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\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan","payer"],"properties":{"plan":{"enum":["free","small","starter","growth","scale"]},"payer":{"enum":["shopify"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/domains":{"get":{"tags":["Sites"],"summary":"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","description":"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\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/domains/verify":{"post":{"tags":["Sites"],"summary":"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","description":"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\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/consent-log":{"get":{"tags":["Consent"],"summary":"What the consent log keeps: retentionDays (records older are deleted nightly), ipMode (truncated | none; full on older sites) and storeUserAgent","description":"What the consent log keeps: retentionDays (records older are deleted nightly), ipMode (truncated | none; full on older sites) and storeUserAgent\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"put":{"tags":["Consent"],"summary":"Change what the consent log keeps. Admin keys only","description":"Change what the consent log keeps. Admin keys only\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["retentionDays","ipMode","storeUserAgent"],"properties":{"retentionDays":{"type":"integer","minimum":30,"maximum":2190},"ipMode":{"enum":["truncated","none"]},"storeUserAgent":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/sst":{"get":{"tags":["Server-side tracking"],"summary":"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","description":"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\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Server-side tracking"],"summary":"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)","description":"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)\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug"],"properties":{"slug":{"type":"string","description":"The site's slug on Trackable SST"},"applyToBanner":{"type":"boolean","description":"Default false"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Server-side tracking"],"summary":"Disconnect. The SST site keeps running and the banner keeps its settings","description":"Disconnect. The SST site keeps running and the banner keeps its settings\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"204":{"description":"Disconnected"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/sst/verify":{"post":{"tags":["Server-side tracking"],"summary":"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","description":"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\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"hours":{"type":"integer","description":"Hours of traffic for the consent check (default 24, max 744)"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/platform":{"get":{"tags":["Sites"],"summary":"The site's platform, the last detection with its evidence, and every platform there is a guide for","description":"The site's platform, the last detection with its evidence, and every platform there is a guide for\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/platform/detect":{"post":{"tags":["Sites"],"summary":"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","description":"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\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"apply":{"type":"boolean","description":"Default true"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/cookies":{"get":{"tags":["Cookies"],"summary":"The cookie list (kept current by automatic scans)","description":"The cookie list (kept current by automatic scans)\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CookieEntry"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"put":{"tags":["Cookies"],"summary":"Replace the cookie list. Entries sent count as decided by a person (scans keep them); entries left out are removed","description":"Replace the cookie list. Entries sent count as decided by a person (scans keep them); entries left out are removed\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CookieEntry"}}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CookieEntry"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/scans":{"get":{"tags":["Scans"],"summary":"Recent scans","description":"Recent scans\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Scans"],"summary":"Scan now (about a minute) and update the cookie list; with region, check the banner as a visitor from there instead (evidence only)","description":"Scan now (about a minute) and update the cookie list; with region, check the banner as a visitor from there instead (evidence only)\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"A page on one of the site's domains; default its main domain"},"region":{"enum":["GB","DE","US-CA"],"description":"Trackable CMP sites: the edge applies this region's rules"}}}}}},"responses":{"201":{"description":"Scanned","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/scans/{id}":{"get":{"tags":["Scans"],"summary":"A scan's full report, including Google Consent Mode as Google received it per stage (decoded gcd); format=markdown for the report as Markdown","description":"A scan's full report, including Google Consent Mode as Google received it per stage (decoded gcd); format=markdown for the report as Markdown\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"Scan id","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"markdown","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/compliance":{"get":{"tags":["Compliance"],"summary":"The compliance score (0–100) and risk per region, every check with its fix, and what to fix first","description":"The compliance score (0–100) and risk per region, every check with its fix, and what to fix first\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"region","in":"query","required":false,"description":"uk | eu | us; all three when left out","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/fixes":{"post":{"tags":["Compliance"],"summary":"Apply a one-click fix from the compliance score","description":"Apply a one-click fix from the compliance score\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fix"],"properties":{"fix":{"enum":["enable-blocking","enable-auto-scans","enable-reopen","eu-opt-in","enable-privacy-choices","check-us"],"description":"check-us scans the homepage as a California visitor now (GPC on, then \"Your Privacy Choices\" clicked; a minute or two) and adds US-CA to monitorRegions"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/versions":{"get":{"tags":["Sites"],"summary":"Published versions, newest first (kept as evidence)","description":"Published versions, newest first (kept as evidence)\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"body","in":"query","required":false,"description":"1 to include each version's settings","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/cookiebot/banner":{"post":{"tags":["Migration"],"summary":"Import the site's Cookiebot banner (wording in every language it has, layout) and publish it","description":"Import the site's Cookiebot banner (wording in every language it has, layout) and publish it\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["cbid"],"properties":{"cbid":{"type":"string","description":"Cookiebot Domain Group ID"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/cookiebot/cookies":{"post":{"tags":["Migration"],"summary":"Add the cookies in the site's Cookiebot declaration (found by a scan) that the cookie list lacks","description":"Add the cookies in the site's Cookiebot declaration (found by a scan) that the cookie list lacks\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scanId"],"properties":{"scanId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/experiments":{"get":{"tags":["Experiments"],"summary":"Banner experiments, running first; sticky = a returning visitor keeps their arm","description":"Banner experiments, running first; sticky = a returning visitor keeps their arm\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Experiments"],"summary":"Create a draft: the full experiment, or { template } (with optional name, hypothesis, regions, mainRegion, mdePoints, confidence)","description":"Create a draft: the full experiment, or { template } (with optional name, hypothesis, regions, mainRegion, mdePoints, confidence)\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Either an experiment (type, name, hypothesis, primaryMetric, confidence, mdePoints, regions, mainRegion, variants, factors, controlWeight, template) or { template: \"<id>\" }."}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/experiments/templates":{"get":{"tags":["Experiments"],"summary":"Ready-made first experiments from published evidence, each with the draft it creates for this banner (null: does not apply)","description":"Ready-made first experiments from published evidence, each with the draft it creates for this banner (null: does not apply)\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/experiments/settings":{"put":{"tags":["Experiments"],"summary":"Experiment settings for the site","description":"Experiment settings for the site\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sticky"],"properties":{"sticky":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/experiments/{id}":{"get":{"tags":["Experiments"],"summary":"One experiment with its results per region (live while running, frozen once ended); a draft gets its problems and a duration forecast","description":"One experiment with its results per region (live while running, frozen once ended); a draft gets its problems and a duration forecast\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"Experiment id","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Experiments"],"summary":"Delete a draft","description":"Delete a draft\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"Experiment id","schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/experiments/{id}/start":{"post":{"tags":["Experiments"],"summary":"Start a draft (one running experiment per site)","description":"Start a draft (one running experiment per site)\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"Experiment id","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/experiments/{id}/stop":{"post":{"tags":["Experiments"],"summary":"Stop a running experiment and freeze its result; apply publishes the winning arm as the banner","description":"Stop a running experiment and freeze its result; apply publishes the winning arm as the banner\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"id","in":"path","required":true,"description":"Experiment id","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"apply":{"type":"string","description":"Arm key of the winner, e.g. \"b\""}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/benchmarks":{"get":{"tags":["Insights"],"summary":"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","description":"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\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"sector","in":"query","required":false,"description":"Sector id from the taxonomy","schema":{"type":"string"}},{"name":"subsector","in":"query","required":false,"description":"Subsector id (default other)","schema":{"type":"string"}},{"name":"model","in":"query","required":false,"description":"Business model, e.g. ecommerce","schema":{"type":"string"}},{"name":"region","in":"query","required":false,"description":"Jurisdiction, default trackable_uk_opt_in","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/insights":{"get":{"tags":["Insights"],"summary":"Own rates, and (profile confirmed, sharing on) industry benchmarks, best-banner traits, pooled learnings and the next experiment to run","description":"Own rates, and (profile confirmed, sharing on) industry benchmarks, best-banner traits, pooled learnings and the next experiment to run\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"region","in":"query","required":false,"description":"Jurisdiction compared, e.g. trackable_uk_opt_in; default: the one with most visitors","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/insights/profile":{"get":{"tags":["Insights"],"summary":"The business profile benchmarks are matched on","description":"The business profile benchmarks are matched on\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"put":{"tags":["Insights"],"summary":"Confirm the business profile","description":"Confirm the business profile\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sector","subsector","model","customers","markets","sizeBand","adPlatforms"],"properties":{"sector":{"type":"string"},"subsector":{"type":"string"},"model":{"enum":["ecommerce","lead_generation","content","saas","local_services","non_profit"]},"customers":{"enum":["consumers","businesses","both"]},"markets":{"type":"array","items":{"type":"string","description":"ISO country code"}},"sizeBand":{"enum":["lt10k","10k_100k","100k_1m","gt1m"]},"adPlatforms":{"type":"array","items":{"enum":["google","meta","microsoft","tiktok","linkedin","pinterest","amazon","other"]}}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/insights/opt-in":{"put":{"tags":["Insights"],"summary":"Share anonymised results (and see the industry's); turning on needs agree: true","description":"Share anonymised results (and see the industry's); turning on needs agree: true\n\nScope: `write`.","x-scope":"write","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["on"],"properties":{"on":{"type":"boolean"},"agree":{"type":"boolean","description":"You are allowed to agree to sharing for this site"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/consent-backup":{"get":{"tags":["Consent"],"summary":"Consent log backup to your own S3-compatible storage: settings and state (never the secret)","description":"Consent log backup to your own S3-compatible storage: settings and state (never the secret)\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":["object","null"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"put":{"tags":["Consent"],"summary":"Set where nightly backups go (one CSV per day). A test file is written first; a refusal is a 422 with the reason","description":"Set where nightly backups go (one CSV per day). A test file is written first; a refusal is a 422 with the reason\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider","endpoint","region","bucket","accessKeyId"],"properties":{"provider":{"enum":["aws","r2","b2","gcs","wasabi","other"]},"endpoint":{"type":"string","example":"https://s3.eu-west-2.amazonaws.com"},"region":{"type":"string","example":"eu-west-2"},"bucket":{"type":"string"},"prefix":{"type":"string","description":"Folder, ending with /"},"accessKeyId":{"type":"string"},"secretAccessKey":{"type":"string","description":"Write-only; omit to keep the stored one"},"backfill":{"type":"boolean","description":"Also back up earlier records (up to 13 months)"},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Consent"],"summary":"Stop backups and forget the key (files already written stay)","description":"Stop backups and forget the key (files already written stay)\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"204":{"description":"Removed"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/gtm-audit":{"post":{"tags":["Tracking"],"summary":"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","description":"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\n\nScope: `read`.","x-scope":"read","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["container"],"properties":{"container":{"type":"object","description":"The exported container JSON"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sgtm-template":{"get":{"tags":["Tracking"],"summary":"The sGTM variable template that verifies the signed consent cookie, with the steps to use it","description":"The sGTM variable template that verifies the signed consent cookie, with the steps to use it\n\nScope: `read`.","x-scope":"read","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/audits":{"get":{"tags":["Audits"],"summary":"Prospect audits (scans of any address, not tied to a site) of your organisation","description":"Prospect audits (scans of any address, not tied to a site) of your organisation\n\nScope: `read`.","x-scope":"read","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Audits"],"summary":"Audit any public address now (about a minute)","description":"Audit any public address now (about a minute)\n\nScope: `write`.","x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}}}}},"responses":{"201":{"description":"Audited","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/audits/{id}":{"get":{"tags":["Audits"],"summary":"One prospect audit's full report; format=markdown for Markdown","description":"One prospect audit's full report; format=markdown for Markdown\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"id","in":"path","required":true,"description":"Audit id","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"markdown","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/consents":{"get":{"tags":["Consent"],"summary":"Proof of consent: every decision for one visitor (subjectId) or one receipt (consentId); without either, the consent log newest first, filtered","description":"Proof of consent: every decision for one visitor (subjectId) or one receipt (consentId); without either, the consent log newest first, filtered\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"subjectId","in":"query","required":false,"description":"sub_…","schema":{"type":"string"}},{"name":"consentId","in":"query","required":false,"description":"cns_…","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"YYYY-MM-DD (default 30 days ago)","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string"}},{"name":"action","in":"query","required":false,"description":"accept_all | reject_all | custom | withdraw","schema":{"type":"string"}},{"name":"jurisdiction","in":"query","required":false,"description":"Rules applied, e.g. europe_opt_in","schema":{"type":"string"}},{"name":"country","in":"query","required":false,"description":"ISO country code","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"1–500, default 100","schema":{"type":"integer"}},{"name":"offset","in":"query","required":false,"description":"Default 0","schema":{"type":"integer"}},{"name":"format","in":"query","required":false,"description":"csv: every matching row as CSV","schema":{"type":"string"}},{"name":"all","in":"query","required":false,"description":"1: every record kept, not the last 30 days","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/renew-consents":{"post":{"tags":["Consent"],"summary":"Ask every visitor again: publishes the live settings as a new version that voids every earlier choice (the banner shows again on their next visit). Ordinary changes keep choices. Needs an admin key","description":"Ask every visitor again: publishes the live settings as a new version that voids every earlier choice (the banner shows again on their next visit). Ordinary changes keep choices. Needs an admin key\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/sites/{key}/stats":{"get":{"tags":["Consent"],"summary":"Consent funnel, rates (answered, ignored, accepted, rejected, partly accepted, analytics and marketing allowed, tags loaded), region and device breakdowns, and the pages where visitors answer","description":"Consent funnel, rates (answered, ignored, accepted, rejected, partly accepted, analytics and marketing allowed, tags loaded), region and device breakdowns, and the pages where visitors answer\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"key","in":"path","required":true,"description":"Site key","schema":{"type":"string"}},{"name":"days","in":"query","required":false,"description":"1–395, default 30","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/partners":{"get":{"tags":["Partners"],"summary":"The partner directory: Certified and Premier agencies that install Trackable CMP, Premier first, then the best fit for a platform and region","description":"The partner directory: Certified and Premier agencies that install Trackable CMP, Premier first, then the best fit for a platform and region\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"platform","in":"query","required":false,"description":"Platform id, e.g. shopify","schema":{"type":"string"}},{"name":"region","in":"query","required":false,"description":"uk | eu | us | ca | au | other","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/partner":{"get":{"tags":["Partners"],"summary":"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","description":"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\n\nScope: `read`.","x-scope":"read","parameters":[{"name":"organisationId","in":"query","required":false,"description":"The partner (default: the key's organisation)","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/partner/deals":{"post":{"tags":["Partners"],"summary":"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","description":"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\n\nScope: `write`.","x-scope":"write","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"},"company":{"type":"string"},"note":{"type":"string"},"organisationId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Registered","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/organisations/{id}/agency":{"put":{"tags":["Partners"],"summary":"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","description":"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\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Client organisation id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agencyId"],"properties":{"agencyId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","description":"List webhooks\n\nScope: `admin`.","x-scope":"admin","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Webhooks"],"summary":"Add a webhook (public https only). The signing secret is returned once","description":"Add a webhook (public https only). The signing secret is returned once\n\nScope: `admin`.","x-scope":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string"},"events":{"type":"array","items":{"enum":["consent.recorded","scan.completed","cookies.changed","consent.problem","site.created","site.updated","site.deleted"]}},"description":{"type":"string"},"organisationId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}":{"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","description":"Delete a webhook\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Webhook id","schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}/test":{"post":{"tags":["Webhooks"],"summary":"Send a test delivery (event webhook.test)","description":"Send a test delivery (event webhook.test)\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Webhook id","schema":{"type":"string"}}],"responses":{"202":{"description":"Queued","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/api-keys":{"get":{"tags":["API keys"],"summary":"List keys (never their secrets)","description":"List keys (never their secrets)\n\nScope: `admin`.","x-scope":"admin","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["API keys"],"summary":"Create a key for this organisation or a sub-account, with at most the caller's scopes. The secret is returned once","description":"Create a key for this organisation or a sub-account, with at most the caller's scopes. The secret is returned once\n\nScope: `admin`.","x-scope":"admin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","scopes"],"properties":{"name":{"type":"string"},"scopes":{"type":"array","items":{"enum":["read","write","admin"]}},"organisationId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/api-keys/{id}":{"delete":{"tags":["API keys"],"summary":"Revoke a key","description":"Revoke a key\n\nScope: `admin`.","x-scope":"admin","parameters":[{"name":"id","in":"path","required":true,"description":"Key id","schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"tcmp_… API key"}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}}}}}}}}},"schemas":{"Settings":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"status":{"enum":["active","paused"]},"domains":{"type":"array","items":{"type":"string"},"description":"Hostnames (www.example.com). The banner runs and choices are accepted only on these."},"stagingDomains":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"Staging aliases: the banner works there too, but visits are test data (not counted, scanned or used in experiments)."},"crossDomain":{"type":"boolean","description":"Carry a visitor's choice to the site's other domains through links (a signed code valid 10 minutes). Needs two or more domains."},"strictness":{"enum":["relaxed","balanced","strict"],"deprecated":true,"description":"Deprecated (2026-10-27): accepted and kept for compatibility, but it grants nothing. What runs before a choice is regionDefaults."},"regionDefaults":{"type":"object","description":"The default consent table: per row, which optional categories are on before a visitor chooses (Consent Mode default and the preferences window's starting switches). Rows: eu, uk, ch, br, ca, us (the United States: every state, and US visitors whose state is unknown), other (everywhere else, including unknown locations), plus your own rows for a country (\"FR\") or a country and region (\"US-CA\"); the most specific row wins. GET returns every group row (recommended: necessary and functional everywhere, the UK included; the US everything, with GPC still applied) and your own rows. PATCH merges per row (partial values allowed); null resets a group row to the recommendation or removes your own row. Going beyond the recommendation is allowed but lowers the compliance score. Necessary is always on; Reject all always turns everything optional off.","propertyNames":{"pattern":"^(eu|uk|ch|br|ca|us|other|[A-Z]{2}(-[A-Z0-9]{1,3})?)$"},"additionalProperties":{"type":["object","null"],"properties":{"functionality":{"type":"boolean"},"measurement":{"type":"boolean","description":"Analytics. On before a choice in an opt-in region only under an exemption (for example UK statistics); visitors can object"},"experience":{"type":"boolean","description":"Personalisation"},"marketing":{"type":"boolean"}}}},"consentLifetimeDays":{"type":"integer","minimum":30,"maximum":395},"cookieDomain":{"type":["string","null"],"description":"Domain for the consent cookie (so a tagging subdomain receives it). Default: the shortest site domain."},"gtm":{"type":["object","null"],"properties":{"id":{"type":"string","example":"GTM-ABC1234"},"loaderUrl":{"type":["string","null"],"description":"Stape custom loader (https://…) or Google tag gateway path (/metrics/?id=GTM-…)."}}},"consentMode":{"type":"object","properties":{"adsDataRedaction":{"type":"boolean"},"urlPassthrough":{"type":"boolean"}}},"banner":{"type":"object","properties":{"layout":{"enum":["floating","bar","wall"],"description":"floating: bottom left; bar: along the bottom; wall: Centred, in the middle of the screen, not blocking the page"},"language":{"type":"string","description":"page (the page's <html lang>), browser, or a two-letter code"},"primaryColour":{"type":"string","example":"#0F172A","description":"Must keep white button text readable (WCAG AA)."},"title":{"type":"string","maxLength":80},"description":{"type":"string","maxLength":500},"privacyUrl":{"type":"string"},"cookiesUrl":{"type":"string"},"reopenButton":{"type":"boolean","description":"The reopen button: a cookie icon in the bottom left corner that opens the visitor's cookie settings. Off: the site must link to href=\"#trackable-preferences\" from every page (the compliance score counts it)"},"position":{"type":["string","null"],"enum":["bottom-left","bottom-right","bottom-center","top-left","top-right","top-center","bottom","top",null],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): floating is always bottom left, bar always along the bottom, wall (Centred) in the middle without blocking the page."},"reopenPosition":{"enum":["bottom-left","bottom-right"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): the reopen icon is always bottom left"},"ageGate":{"type":"object","description":"Age confirmation before the cookie banner (not verification).","properties":{"enabled":{"type":"boolean"},"minAge":{"type":"integer","minimum":13,"maximum":25},"minAgeUs":{"type":["integer","null"],"description":"US minimum if different (21 for alcohol)"},"method":{"enum":["yesno","birthdate"]},"rememberDays":{"type":"integer","minimum":0,"maximum":90,"description":"0 = this visit"},"underageUrl":{"type":"string","description":"Where under-age visitors go; empty = a message"}}},"hideOnPages":{"type":"array","items":{"type":"string","example":"/legal/*"},"maxItems":20,"description":"Paths where the banner does not open by itself (a trailing * matches everything under it). Nothing is granted there; the reopen button stays."},"logoUrl":{"type":"string","description":"https:// image shown above the banner title. Empty for none."},"backgroundColour":{"type":"string","example":"#FFFFFF"},"textColour":{"type":"string","example":"#0F172A","description":"Must contrast 4.5:1 with the background"},"cornerRadius":{"enum":["square","rounded","round"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always rounded"},"fontFamily":{"type":"string","deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always the site's own font"},"fontSize":{"type":["integer","null"],"minimum":12,"maximum":20,"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always as the site"},"buttonStyle":{"enum":["solid","outline"],"description":"Reject all and Accept all always share it"},"shadow":{"type":"boolean","deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): the shadow is always on"},"mobileLayout":{"enum":["same","sheet"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): on phones the banner is always a sheet along the bottom with the buttons stacked"},"customCss":{"type":"string","maxLength":5000,"description":"Applied inside the banner. No \"</\" or @import. Not applied at all if it makes Reject all hidden, smaller, faded or harder to read than Accept all"},"imprintUrl":{"type":"string","description":"Imprint (Impressum) link, labelled per language"},"reopenStyle":{"enum":["icon","text"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always the icon"},"reopenSize":{"enum":["small","medium","large"],"deprecated":true,"description":"Ignored since 2026-10-27"},"reopenDevices":{"enum":["all","desktop","mobile"],"deprecated":true,"description":"Ignored since 2026-10-27: shown on every device"},"reopenIconUrl":{"type":"string","deprecated":true,"description":"Ignored since 2026-10-27: always the cookie icon"},"buttonOrder":{"enum":["reject-customise-accept","reject-accept-customise","accept-reject-customise","customise-reject-accept"],"description":"The first banner's buttons, left to right. Default reject-customise-accept"},"buttonMatch":{"enum":["reject-accept","all","reject-customise"],"description":"Which buttons share a style, on the banner and the preferences window. reject-accept (default, recommended): Customise stands out; all: all three alike; reject-customise: Accept stands out (not recommended: lowers the compliance score)"},"standoutColour":{"type":"string","example":"#F59E0B","description":"The stand-out button filled in its own colour; empty = outlined in the brand colour. Text colour chosen for contrast unless standoutTextColour is set"},"buttonTextColour":{"type":"string","example":"#FFFFFF","description":"The text on Reject all and Accept all. Solid: empty = white or dark, whichever reads on the brand colour; outlined: empty = the brand colour. Must reach 4.5:1"},"standoutTextColour":{"type":"string","example":"#0F172A","description":"The stand-out button's text. Filled: empty = white or dark, whichever reads; outlined: empty = the banner text colour. Must reach 4.5:1"},"switchOnColour":{"type":"string","example":"#0F172A","description":"The switches in the cookie settings when on; empty = the brand colour"},"switchOffColour":{"type":"string","example":"#64748B","description":"The switches in the cookie settings when off; empty = a mid grey"},"standoutOutlineColour":{"type":"string","example":"#0F172A","description":"The stand-out button's outline when it is not filled; empty = the brand colour (grey when buttons are outlined)"},"doNotSell":{"type":"boolean","description":"\"Your Privacy Choices\" for US visitors (default true since 2026-10-27): a button bottom right with California's opt-out icon. One click turns off what the browser's opt-out signal would, recorded with source do_not_sell, and shows the visitor their settings. Pages with a #trackable-privacy-choices (or #trackable-do-not-sell) link get no button; the link does the same. false: no button (the compliance score then needs the site's own link)"},"prechecked":{"type":"array","items":{"enum":["experience","measurement","marketing"]},"description":"Pre-checked boxes: categories switched on in the preferences window for a visitor who has not chosen. Ignored where consent comes first beyond that region's defaults; never against GPC; nothing stored or granted until the visitor saves"},"gpcNotice":{"type":"boolean","description":"Confirm to US visitors, on the page they land on, that their browser's opt-out signal was applied. The preferences window and the quick panel always say so (\"Opt-out signal honoured\"), whatever this is"},"wording":{"type":"object","description":"Per language (en, bg, cs, cy, da, de, el, es, et, fi, fr, ga, hr, hu, is, it, lb, lt, lv, mt, nb, nl, nn, pl, pt, ro, sk, sl, sv, zh, he, hi, id, gu, rm), only the fields that differ from the stock wording. A language in a PATCH replaces that language. title/description are wording.en.bannerTitle/bannerText.","additionalProperties":{"type":"object","properties":{"bannerTitle":{"type":"string","maxLength":80,"description":"Banner title"},"bannerText":{"type":"string","maxLength":500,"description":"Banner text"},"rejectAll":{"type":"string","maxLength":40,"description":"Reject all button"},"acceptAll":{"type":"string","maxLength":40,"description":"Accept all button"},"customize":{"type":"string","maxLength":40,"description":"Customise button"},"save":{"type":"string","maxLength":40,"description":"Accept selected button"},"dialogTitle":{"type":"string","maxLength":80,"description":"Preferences title"},"dialogText":{"type":"string","maxLength":500,"description":"Preferences text"},"necessaryTitle":{"type":"string","maxLength":60,"description":"Strictly necessary: name"},"necessaryText":{"type":"string","maxLength":300,"description":"Strictly necessary: description"},"functionalityTitle":{"type":"string","maxLength":60,"description":"Functional: name"},"functionalityText":{"type":"string","maxLength":300,"description":"Functional: description"},"experienceTitle":{"type":"string","maxLength":60,"description":"Personalisation: name"},"experienceText":{"type":"string","maxLength":300,"description":"Personalisation: description"},"measurementTitle":{"type":"string","maxLength":60,"description":"Analytics: name"},"measurementText":{"type":"string","maxLength":300,"description":"Analytics: description"},"marketingTitle":{"type":"string","maxLength":60,"description":"Marketing: name"},"marketingText":{"type":"string","maxLength":300,"description":"Marketing: description"},"reopen":{"type":"string","maxLength":60,"description":"Reopen button label"},"imprint":{"type":"string","maxLength":40,"description":"Imprint link text"},"gpc":{"type":"string","maxLength":200,"description":"Opt-out signal confirmation (US)"},"panelTitle":{"type":"string","maxLength":60,"description":"Cookie settings panel: title"},"panelCurrent":{"type":"string","maxLength":60,"description":"Cookie settings panel: \"Current choice\""},"panelDetails":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Show details\""},"panelDate":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Date and time\""},"panelId":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Consent ID\""},"panelWithdraw":{"type":"string","maxLength":40,"description":"Cookie settings panel: withdraw button"},"panelChange":{"type":"string","maxLength":40,"description":"Cookie settings panel: change button"},"panelAllowed":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Allowed\" (read aloud)"},"panelRefused":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Not allowed\" (read aloud)"},"xdTitle":{"type":"string","maxLength":60,"description":"Shared across sites: title"},"xdText":{"type":"string","maxLength":120,"description":"Shared across sites: text before the list of domains"},"ageTitle":{"type":"string","maxLength":80,"description":"Age confirmation: title"},"ageText":{"type":"string","maxLength":300,"description":"Age confirmation: text ({age} is the minimum age)"},"ageYes":{"type":"string","maxLength":40,"description":"Age confirmation: yes button"},"ageNo":{"type":"string","maxLength":40,"description":"Age confirmation: no button"},"ageDob":{"type":"string","maxLength":60,"description":"Age confirmation: date of birth label"},"ageEnter":{"type":"string","maxLength":40,"description":"Age confirmation: enter button"},"ageUnder":{"type":"string","maxLength":300,"description":"Age confirmation: under-age message"}}}}}},"enrichment":{"type":"object","properties":{"device":{"type":"boolean","description":"consent_enrichment.device in the dataLayer, with analytics consent"},"geo":{"type":"boolean","description":"City and timezone too (off by default)"}}},"usQuestions":{"type":"object","description":"Three yes/no questions about the site for US visitors. Each yes makes categories wait for consent from US visitors (the banner asks): sensitiveTopics (health, sexuality, religion, precise location) analytics and marketing; childrenOrTeens marketing, kept off with no way to opt in in CT, MD and OR; videoWhileLoggedIn marketing (VPPA). PATCH merges","properties":{"sensitiveTopics":{"type":"boolean"},"childrenOrTeens":{"type":"boolean"},"videoWhileLoggedIn":{"type":"boolean"}}},"blocking":{"type":"object","description":"Hold tracker scripts and embeds until consent. Scripts marked type=\"text/plain\" data-tc-category=\"…\" are always held; these switch on the automatic parts.","properties":{"auto":{"type":"boolean","description":"Hold known tracker scripts (Meta, TikTok, Hotjar, LinkedIn…) written in the page or inserted by code"},"embeds":{"type":"boolean","description":"YouTube, Vimeo, Google Maps and social embeds show a consent placeholder"},"cookiebotCompatibility":{"type":"boolean","description":"Answer window.Cookiebot, fire its events and release data-cookieconsent markup"}}},"cookieEnforcement":{"type":"object","description":"Remove cookies of a refused category the moment a script sets them (on by default). Well-known analytics and advertising cookies always; add the site's own names per category (\"name\" or \"prefix*\"), and optionally the site's cookie list (entries a scan or a person confirmed, never assumed ones).","properties":{"enabled":{"type":"boolean"},"useCookieList":{"type":"boolean"},"extraCookies":{"type":"object","properties":{"functionality":{"type":"array","items":{"type":"string"},"maxItems":50},"experience":{"type":"array","items":{"type":"string"},"maxItems":50},"measurement":{"type":"array","items":{"type":"string"},"maxItems":50},"marketing":{"type":"array","items":{"type":"string"},"maxItems":50}}}}},"gpp":{"type":"object","description":"IAB GPP for US visitors (__gpp with the usnat section, from the opt-out and GPC). Takes effect once Trackable's IAB CMP ID is registered; until then nothing is sent.","properties":{"enabled":{"type":"boolean"},"mspaCovered":{"type":"boolean","description":"The site signed the IAB MSPA (covered transactions)"}}},"declaration":{"type":"object","description":"The cookie policy embed (/d/{key}.js).","properties":{"bannerText":{"type":"boolean","description":"Show the banner text above the list"},"showChoice":{"type":"boolean","description":"Show the visitor's current choice and a button to change it"},"providerName":{"type":["string","null"],"description":"White-label: the name shown as provider of the banner's own cookies (tc_consent…) in the declaration and the banner's cookie lists, linking to the site's privacy policy. null = Trackable CMP"},"layout":{"enum":["tables","compact"]}}},"tags":{"type":"object","description":"Tags the CMP loads itself after consent, for sites without GTM. Empty string = not loaded.","properties":{"metaPixelId":{"type":"string"},"tiktokPixelId":{"type":"string"},"uetTagId":{"type":"string"},"clarityProjectId":{"type":"string"},"amazonConsentSignal":{"type":"boolean","description":"Send Amazon's consent signal (ACS) to the site's Amazon Ads tag: granted once marketing is allowed, with the visitor's country"}}},"scanFrequency":{"enum":["daily","weekly","monthly","off"],"description":"Automatic cookie scans; each updates the cookie list."},"scanPages":{"type":"array","items":{"type":"string"},"maxItems":5,"description":"Extra pages automatic scans cover besides the homepage: paths (/cart) or addresses on the site's domains. Cookies are combined across pages before the list is updated."},"monitorRegions":{"type":"array","items":{"enum":["GB","DE","US-CA"]},"description":"After each automatic scan, the homepage is checked again with these regions' rules (Trackable CMP sites). Evidence only: the cookie list is not changed."},"reportEmails":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Who gets the report after each automatic scan."},"scanJourney":{"type":"boolean","description":"The homepage scan also follows product → add to basket → checkout with no choice, after Reject and after Accept, and reports events sent without consent. New must-fix problems raise consent.problem. Default true."},"platform":{"enum":["wordpress","shopify","webflow","wix","squarespace","framer","hubspot","ghost","bigcommerce","godaddy","hostinger-builder","duda","nextjs","nuxt","astro","gatsby","drupal","joomla","custom"],"nullable":true,"description":"What the website is built on (asked or detected): picks the install guide. null = not known yet."}}},"Site":{"type":"object","properties":{"key":{"type":"string"},"organisationId":{"type":"string"},"version":{"type":"integer"},"createdAt":{"type":"string"},"settings":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"status":{"enum":["active","paused"]},"domains":{"type":"array","items":{"type":"string"},"description":"Hostnames (www.example.com). The banner runs and choices are accepted only on these."},"stagingDomains":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"Staging aliases: the banner works there too, but visits are test data (not counted, scanned or used in experiments)."},"crossDomain":{"type":"boolean","description":"Carry a visitor's choice to the site's other domains through links (a signed code valid 10 minutes). Needs two or more domains."},"strictness":{"enum":["relaxed","balanced","strict"],"deprecated":true,"description":"Deprecated (2026-10-27): accepted and kept for compatibility, but it grants nothing. What runs before a choice is regionDefaults."},"regionDefaults":{"type":"object","description":"The default consent table: per row, which optional categories are on before a visitor chooses (Consent Mode default and the preferences window's starting switches). Rows: eu, uk, ch, br, ca, us (the United States: every state, and US visitors whose state is unknown), other (everywhere else, including unknown locations), plus your own rows for a country (\"FR\") or a country and region (\"US-CA\"); the most specific row wins. GET returns every group row (recommended: necessary and functional everywhere, the UK included; the US everything, with GPC still applied) and your own rows. PATCH merges per row (partial values allowed); null resets a group row to the recommendation or removes your own row. Going beyond the recommendation is allowed but lowers the compliance score. Necessary is always on; Reject all always turns everything optional off.","propertyNames":{"pattern":"^(eu|uk|ch|br|ca|us|other|[A-Z]{2}(-[A-Z0-9]{1,3})?)$"},"additionalProperties":{"type":["object","null"],"properties":{"functionality":{"type":"boolean"},"measurement":{"type":"boolean","description":"Analytics. On before a choice in an opt-in region only under an exemption (for example UK statistics); visitors can object"},"experience":{"type":"boolean","description":"Personalisation"},"marketing":{"type":"boolean"}}}},"consentLifetimeDays":{"type":"integer","minimum":30,"maximum":395},"cookieDomain":{"type":["string","null"],"description":"Domain for the consent cookie (so a tagging subdomain receives it). Default: the shortest site domain."},"gtm":{"type":["object","null"],"properties":{"id":{"type":"string","example":"GTM-ABC1234"},"loaderUrl":{"type":["string","null"],"description":"Stape custom loader (https://…) or Google tag gateway path (/metrics/?id=GTM-…)."}}},"consentMode":{"type":"object","properties":{"adsDataRedaction":{"type":"boolean"},"urlPassthrough":{"type":"boolean"}}},"banner":{"type":"object","properties":{"layout":{"enum":["floating","bar","wall"],"description":"floating: bottom left; bar: along the bottom; wall: Centred, in the middle of the screen, not blocking the page"},"language":{"type":"string","description":"page (the page's <html lang>), browser, or a two-letter code"},"primaryColour":{"type":"string","example":"#0F172A","description":"Must keep white button text readable (WCAG AA)."},"title":{"type":"string","maxLength":80},"description":{"type":"string","maxLength":500},"privacyUrl":{"type":"string"},"cookiesUrl":{"type":"string"},"reopenButton":{"type":"boolean","description":"The reopen button: a cookie icon in the bottom left corner that opens the visitor's cookie settings. Off: the site must link to href=\"#trackable-preferences\" from every page (the compliance score counts it)"},"position":{"type":["string","null"],"enum":["bottom-left","bottom-right","bottom-center","top-left","top-right","top-center","bottom","top",null],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): floating is always bottom left, bar always along the bottom, wall (Centred) in the middle without blocking the page."},"reopenPosition":{"enum":["bottom-left","bottom-right"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): the reopen icon is always bottom left"},"ageGate":{"type":"object","description":"Age confirmation before the cookie banner (not verification).","properties":{"enabled":{"type":"boolean"},"minAge":{"type":"integer","minimum":13,"maximum":25},"minAgeUs":{"type":["integer","null"],"description":"US minimum if different (21 for alcohol)"},"method":{"enum":["yesno","birthdate"]},"rememberDays":{"type":"integer","minimum":0,"maximum":90,"description":"0 = this visit"},"underageUrl":{"type":"string","description":"Where under-age visitors go; empty = a message"}}},"hideOnPages":{"type":"array","items":{"type":"string","example":"/legal/*"},"maxItems":20,"description":"Paths where the banner does not open by itself (a trailing * matches everything under it). Nothing is granted there; the reopen button stays."},"logoUrl":{"type":"string","description":"https:// image shown above the banner title. Empty for none."},"backgroundColour":{"type":"string","example":"#FFFFFF"},"textColour":{"type":"string","example":"#0F172A","description":"Must contrast 4.5:1 with the background"},"cornerRadius":{"enum":["square","rounded","round"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always rounded"},"fontFamily":{"type":"string","deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always the site's own font"},"fontSize":{"type":["integer","null"],"minimum":12,"maximum":20,"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always as the site"},"buttonStyle":{"enum":["solid","outline"],"description":"Reject all and Accept all always share it"},"shadow":{"type":"boolean","deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): the shadow is always on"},"mobileLayout":{"enum":["same","sheet"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): on phones the banner is always a sheet along the bottom with the buttons stacked"},"customCss":{"type":"string","maxLength":5000,"description":"Applied inside the banner. No \"</\" or @import. Not applied at all if it makes Reject all hidden, smaller, faded or harder to read than Accept all"},"imprintUrl":{"type":"string","description":"Imprint (Impressum) link, labelled per language"},"reopenStyle":{"enum":["icon","text"],"deprecated":true,"description":"Ignored since 2026-10-27 (still accepted): always the icon"},"reopenSize":{"enum":["small","medium","large"],"deprecated":true,"description":"Ignored since 2026-10-27"},"reopenDevices":{"enum":["all","desktop","mobile"],"deprecated":true,"description":"Ignored since 2026-10-27: shown on every device"},"reopenIconUrl":{"type":"string","deprecated":true,"description":"Ignored since 2026-10-27: always the cookie icon"},"buttonOrder":{"enum":["reject-customise-accept","reject-accept-customise","accept-reject-customise","customise-reject-accept"],"description":"The first banner's buttons, left to right. Default reject-customise-accept"},"buttonMatch":{"enum":["reject-accept","all","reject-customise"],"description":"Which buttons share a style, on the banner and the preferences window. reject-accept (default, recommended): Customise stands out; all: all three alike; reject-customise: Accept stands out (not recommended: lowers the compliance score)"},"standoutColour":{"type":"string","example":"#F59E0B","description":"The stand-out button filled in its own colour; empty = outlined in the brand colour. Text colour chosen for contrast unless standoutTextColour is set"},"buttonTextColour":{"type":"string","example":"#FFFFFF","description":"The text on Reject all and Accept all. Solid: empty = white or dark, whichever reads on the brand colour; outlined: empty = the brand colour. Must reach 4.5:1"},"standoutTextColour":{"type":"string","example":"#0F172A","description":"The stand-out button's text. Filled: empty = white or dark, whichever reads; outlined: empty = the banner text colour. Must reach 4.5:1"},"switchOnColour":{"type":"string","example":"#0F172A","description":"The switches in the cookie settings when on; empty = the brand colour"},"switchOffColour":{"type":"string","example":"#64748B","description":"The switches in the cookie settings when off; empty = a mid grey"},"standoutOutlineColour":{"type":"string","example":"#0F172A","description":"The stand-out button's outline when it is not filled; empty = the brand colour (grey when buttons are outlined)"},"doNotSell":{"type":"boolean","description":"\"Your Privacy Choices\" for US visitors (default true since 2026-10-27): a button bottom right with California's opt-out icon. One click turns off what the browser's opt-out signal would, recorded with source do_not_sell, and shows the visitor their settings. Pages with a #trackable-privacy-choices (or #trackable-do-not-sell) link get no button; the link does the same. false: no button (the compliance score then needs the site's own link)"},"prechecked":{"type":"array","items":{"enum":["experience","measurement","marketing"]},"description":"Pre-checked boxes: categories switched on in the preferences window for a visitor who has not chosen. Ignored where consent comes first beyond that region's defaults; never against GPC; nothing stored or granted until the visitor saves"},"gpcNotice":{"type":"boolean","description":"Confirm to US visitors, on the page they land on, that their browser's opt-out signal was applied. The preferences window and the quick panel always say so (\"Opt-out signal honoured\"), whatever this is"},"wording":{"type":"object","description":"Per language (en, bg, cs, cy, da, de, el, es, et, fi, fr, ga, hr, hu, is, it, lb, lt, lv, mt, nb, nl, nn, pl, pt, ro, sk, sl, sv, zh, he, hi, id, gu, rm), only the fields that differ from the stock wording. A language in a PATCH replaces that language. title/description are wording.en.bannerTitle/bannerText.","additionalProperties":{"type":"object","properties":{"bannerTitle":{"type":"string","maxLength":80,"description":"Banner title"},"bannerText":{"type":"string","maxLength":500,"description":"Banner text"},"rejectAll":{"type":"string","maxLength":40,"description":"Reject all button"},"acceptAll":{"type":"string","maxLength":40,"description":"Accept all button"},"customize":{"type":"string","maxLength":40,"description":"Customise button"},"save":{"type":"string","maxLength":40,"description":"Accept selected button"},"dialogTitle":{"type":"string","maxLength":80,"description":"Preferences title"},"dialogText":{"type":"string","maxLength":500,"description":"Preferences text"},"necessaryTitle":{"type":"string","maxLength":60,"description":"Strictly necessary: name"},"necessaryText":{"type":"string","maxLength":300,"description":"Strictly necessary: description"},"functionalityTitle":{"type":"string","maxLength":60,"description":"Functional: name"},"functionalityText":{"type":"string","maxLength":300,"description":"Functional: description"},"experienceTitle":{"type":"string","maxLength":60,"description":"Personalisation: name"},"experienceText":{"type":"string","maxLength":300,"description":"Personalisation: description"},"measurementTitle":{"type":"string","maxLength":60,"description":"Analytics: name"},"measurementText":{"type":"string","maxLength":300,"description":"Analytics: description"},"marketingTitle":{"type":"string","maxLength":60,"description":"Marketing: name"},"marketingText":{"type":"string","maxLength":300,"description":"Marketing: description"},"reopen":{"type":"string","maxLength":60,"description":"Reopen button label"},"imprint":{"type":"string","maxLength":40,"description":"Imprint link text"},"gpc":{"type":"string","maxLength":200,"description":"Opt-out signal confirmation (US)"},"panelTitle":{"type":"string","maxLength":60,"description":"Cookie settings panel: title"},"panelCurrent":{"type":"string","maxLength":60,"description":"Cookie settings panel: \"Current choice\""},"panelDetails":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Show details\""},"panelDate":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Date and time\""},"panelId":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Consent ID\""},"panelWithdraw":{"type":"string","maxLength":40,"description":"Cookie settings panel: withdraw button"},"panelChange":{"type":"string","maxLength":40,"description":"Cookie settings panel: change button"},"panelAllowed":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Allowed\" (read aloud)"},"panelRefused":{"type":"string","maxLength":40,"description":"Cookie settings panel: \"Not allowed\" (read aloud)"},"xdTitle":{"type":"string","maxLength":60,"description":"Shared across sites: title"},"xdText":{"type":"string","maxLength":120,"description":"Shared across sites: text before the list of domains"},"ageTitle":{"type":"string","maxLength":80,"description":"Age confirmation: title"},"ageText":{"type":"string","maxLength":300,"description":"Age confirmation: text ({age} is the minimum age)"},"ageYes":{"type":"string","maxLength":40,"description":"Age confirmation: yes button"},"ageNo":{"type":"string","maxLength":40,"description":"Age confirmation: no button"},"ageDob":{"type":"string","maxLength":60,"description":"Age confirmation: date of birth label"},"ageEnter":{"type":"string","maxLength":40,"description":"Age confirmation: enter button"},"ageUnder":{"type":"string","maxLength":300,"description":"Age confirmation: under-age message"}}}}}},"enrichment":{"type":"object","properties":{"device":{"type":"boolean","description":"consent_enrichment.device in the dataLayer, with analytics consent"},"geo":{"type":"boolean","description":"City and timezone too (off by default)"}}},"usQuestions":{"type":"object","description":"Three yes/no questions about the site for US visitors. Each yes makes categories wait for consent from US visitors (the banner asks): sensitiveTopics (health, sexuality, religion, precise location) analytics and marketing; childrenOrTeens marketing, kept off with no way to opt in in CT, MD and OR; videoWhileLoggedIn marketing (VPPA). PATCH merges","properties":{"sensitiveTopics":{"type":"boolean"},"childrenOrTeens":{"type":"boolean"},"videoWhileLoggedIn":{"type":"boolean"}}},"blocking":{"type":"object","description":"Hold tracker scripts and embeds until consent. Scripts marked type=\"text/plain\" data-tc-category=\"…\" are always held; these switch on the automatic parts.","properties":{"auto":{"type":"boolean","description":"Hold known tracker scripts (Meta, TikTok, Hotjar, LinkedIn…) written in the page or inserted by code"},"embeds":{"type":"boolean","description":"YouTube, Vimeo, Google Maps and social embeds show a consent placeholder"},"cookiebotCompatibility":{"type":"boolean","description":"Answer window.Cookiebot, fire its events and release data-cookieconsent markup"}}},"cookieEnforcement":{"type":"object","description":"Remove cookies of a refused category the moment a script sets them (on by default). Well-known analytics and advertising cookies always; add the site's own names per category (\"name\" or \"prefix*\"), and optionally the site's cookie list (entries a scan or a person confirmed, never assumed ones).","properties":{"enabled":{"type":"boolean"},"useCookieList":{"type":"boolean"},"extraCookies":{"type":"object","properties":{"functionality":{"type":"array","items":{"type":"string"},"maxItems":50},"experience":{"type":"array","items":{"type":"string"},"maxItems":50},"measurement":{"type":"array","items":{"type":"string"},"maxItems":50},"marketing":{"type":"array","items":{"type":"string"},"maxItems":50}}}}},"gpp":{"type":"object","description":"IAB GPP for US visitors (__gpp with the usnat section, from the opt-out and GPC). Takes effect once Trackable's IAB CMP ID is registered; until then nothing is sent.","properties":{"enabled":{"type":"boolean"},"mspaCovered":{"type":"boolean","description":"The site signed the IAB MSPA (covered transactions)"}}},"declaration":{"type":"object","description":"The cookie policy embed (/d/{key}.js).","properties":{"bannerText":{"type":"boolean","description":"Show the banner text above the list"},"showChoice":{"type":"boolean","description":"Show the visitor's current choice and a button to change it"},"providerName":{"type":["string","null"],"description":"White-label: the name shown as provider of the banner's own cookies (tc_consent…) in the declaration and the banner's cookie lists, linking to the site's privacy policy. null = Trackable CMP"},"layout":{"enum":["tables","compact"]}}},"tags":{"type":"object","description":"Tags the CMP loads itself after consent, for sites without GTM. Empty string = not loaded.","properties":{"metaPixelId":{"type":"string"},"tiktokPixelId":{"type":"string"},"uetTagId":{"type":"string"},"clarityProjectId":{"type":"string"},"amazonConsentSignal":{"type":"boolean","description":"Send Amazon's consent signal (ACS) to the site's Amazon Ads tag: granted once marketing is allowed, with the visitor's country"}}},"scanFrequency":{"enum":["daily","weekly","monthly","off"],"description":"Automatic cookie scans; each updates the cookie list."},"scanPages":{"type":"array","items":{"type":"string"},"maxItems":5,"description":"Extra pages automatic scans cover besides the homepage: paths (/cart) or addresses on the site's domains. Cookies are combined across pages before the list is updated."},"monitorRegions":{"type":"array","items":{"enum":["GB","DE","US-CA"]},"description":"After each automatic scan, the homepage is checked again with these regions' rules (Trackable CMP sites). Evidence only: the cookie list is not changed."},"reportEmails":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Who gets the report after each automatic scan."},"scanJourney":{"type":"boolean","description":"The homepage scan also follows product → add to basket → checkout with no choice, after Reject and after Accept, and reports events sent without consent. New must-fix problems raise consent.problem. Default true."},"platform":{"enum":["wordpress","shopify","webflow","wix","squarespace","framer","hubspot","ghost","bigcommerce","godaddy","hostinger-builder","duda","nextjs","nuxt","astro","gatsby","drupal","joomla","custom"],"nullable":true,"description":"What the website is built on (asked or detected): picks the install guide. null = not known yet."}}},"serverKey":{"type":"string","description":"For the sGTM template that checks the consent cookie"},"install":{"type":"object"}}},"Organisation":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"enum":["direct","agency","client"]},"parentId":{"type":["string","null"]},"sites":{"type":"integer"},"createdAt":{"type":"string"}}},"Member":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":["string","null"]},"role":{"type":"string"},"status":{"enum":["member","invited"]}}},"CookieEntry":{"type":"object","required":["name","category"],"properties":{"name":{"type":"string"},"kind":{"enum":["cookie","localStorage","sessionStorage"]},"category":{"enum":["necessary","functionality","experience","measurement","marketing","unclassified"]},"provider":{"type":"string"},"purpose":{"type":"string"},"duration":{"type":"string"},"source":{"type":"string","readOnly":true},"edited":{"type":"boolean","readOnly":true},"guessed":{"type":"boolean","readOnly":true}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"secret":{"type":"string","description":"Only when created"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"secret":{"type":"string","description":"Only when created"}}}}},"webhooks":{"consent.recorded":{"post":{"summary":"Event consent.recorded","description":"POST with JSON { id, event, createdAt, data }. Headers: X-Trackable-Event, X-Trackable-Delivery, X-Trackable-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>. Reply 2xx within 10 s; failures retry after 1 min, 5 min, 30 min, 2 h, 12 h.","responses":{"200":{"description":"Received"}}}},"scan.completed":{"post":{"summary":"Event scan.completed","description":"POST with JSON { id, event, createdAt, data }. Headers: X-Trackable-Event, X-Trackable-Delivery, X-Trackable-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>. Reply 2xx within 10 s; failures retry after 1 min, 5 min, 30 min, 2 h, 12 h.","responses":{"200":{"description":"Received"}}}},"cookies.changed":{"post":{"summary":"Event cookies.changed","description":"POST with JSON { id, event, createdAt, data }. Headers: X-Trackable-Event, X-Trackable-Delivery, X-Trackable-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>. Reply 2xx within 10 s; failures retry after 1 min, 5 min, 30 min, 2 h, 12 h.","responses":{"200":{"description":"Received"}}}},"consent.problem":{"post":{"summary":"Event consent.problem","description":"POST with JSON { id, event, createdAt, data }. Headers: X-Trackable-Event, X-Trackable-Delivery, X-Trackable-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>. Reply 2xx within 10 s; failures retry after 1 min, 5 min, 30 min, 2 h, 12 h.","responses":{"200":{"description":"Received"}}}},"site.created":{"post":{"summary":"Event site.created","description":"POST with JSON { id, event, createdAt, data }. Headers: X-Trackable-Event, X-Trackable-Delivery, X-Trackable-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>. Reply 2xx within 10 s; failures retry after 1 min, 5 min, 30 min, 2 h, 12 h.","responses":{"200":{"description":"Received"}}}},"site.updated":{"post":{"summary":"Event site.updated","description":"POST with JSON { id, event, createdAt, data }. Headers: X-Trackable-Event, X-Trackable-Delivery, X-Trackable-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>. Reply 2xx within 10 s; failures retry after 1 min, 5 min, 30 min, 2 h, 12 h.","responses":{"200":{"description":"Received"}}}},"site.deleted":{"post":{"summary":"Event site.deleted","description":"POST with JSON { id, event, createdAt, data }. Headers: X-Trackable-Event, X-Trackable-Delivery, X-Trackable-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, \"<t>.<body>\")>. Reply 2xx within 10 s; failures retry after 1 min, 5 min, 30 min, 2 h, 12 h.","responses":{"200":{"description":"Received"}}}}}}