All endpoints

DocsAPIBanner

PUT/sites/{siteId}/banner/design

Change the banner's colours and placement

Saves and publishes the banner's theme tokens and, optionally, where it sits.

Auth header

Authorization: Bearer tsk_live_…

The key needsbanner:write

Parameters

  • siteIdstringin pathrequired

    The site id, from GET /v1/sites.

Request body

  • thememap of stringrequired

    CSS custom properties. An absent token keeps our shipped default. Refused if a contrast check fails.

  • presentationobjectoptional

    Absent keeps the stored placement. {} resets it to where we ship it.

  • presentation.layoutstringoptional

    One of bar_bottom, bar_top, box_bottom_left, box_bottom_right, box_top_left, box_top_right, modal_centre

  • presentation.overlaybooleanoptional

    The scrim behind a first-visit banner. Off also drops the focus trap.

  • presentation.actionsstringoptional

    One of inline, stacked

  • presentation.orderstringoptional

    One of reject_first, accept_first

  • presentation.closeXstringoptional

    Always retains_defaults

  • presentation.launcherobjectoptional
  • presentation.launcher.positionstringoptional

    One of bottom_left, bottom_right, top_left, top_right

  • presentation.launcher.triggerstringoptional

    A CSS selector for your own 'Cookie settings' control. Falls back to the floating pill when it matches nothing.

Example request

curl -X PUT "https://app.tagsentry.ai/api/v1/sites/3f6c1b8e-2d4a-4c7e-9a51-0b8f2e6d7c10/banner/design" \  -H "Authorization: Bearer tsk_live_…" \  -H "Content-Type: application/json" \  -d '{"theme":{"--ts-panel-bg":"…"},"presentation":{"layout":"bar_bottom","overlay":false,"actions":"inline","order":"reject_first","closeX":"retains_defaults","launcher":{"position":"bottom_left","trigger":"…"}}}'

Response 200

  • savedbooleanrequired

    Always true

  • changestringrequired

    One of design, wording, links

  • bannerobjectrequired
  • banner.titlestringrequired
  • banner.bodystringrequired
  • banner.acceptAllstringrequired
  • banner.rejectAllstringrequired
  • banner.managestringrequired
  • banner.thememap of string | nullrequired
  • banner.presentationmap of any | nullrequired
  • banner.policyLinksmap of string | nullrequired
  • designModestring | nullrequired
  • artifactWarningstring | nullrequired

    Set when the save stored but the copy visitors fetch did not refresh yet. It retries; the save stands.

Example response

{  "saved": true,  "change": "design",  "banner": {    "title": "…",    "body": "…",    "acceptAll": "…",    "rejectAll": "…",    "manage": "…",    "theme": {      "key": "…"    },    "presentation": {      "key": null    },    "policyLinks": {      "key": "…"    }  },  "designMode": "…",  "artifactWarning": "…"}
More about this endpoint

The same save the Design screen makes, with the same refusals: a theme whose text or buttons fail the contrast check is refused with the audit in detail, and nothing is stored.

A DESIGN WRITE CANNOT CHANGE A WORD. Every string a visitor reads is carried from the stored banner, because each consent record quotes the banner verbatim. Use the wording endpoint for words.

Saving IS publishing: visitors get the new design on their next page view. The site's colours are marked as yours from here, so a later scan does not re-derive over them.

Errors400 · 401 · 403 · 404 · 409 · 429 · 500
  • 400The request did not validate against this operation's schema.
  • 401Missing, malformed, unknown, revoked or expired API key. These are deliberately indistinguishable in the response -- distinguishing them would confirm to a caller that a token was once real.
  • 403The key authenticated but does not carry the scope(s) this operation requires, or (`domain_not_verified`) the site's domain is not verified, so its consent records are not released.
  • 404No such resource on this account. A site id belonging to a DIFFERENT account answers 404, never 403 -- a 403 would confirm the id exists somewhere.
  • 409The request conflicts with existing state.
  • 429A rate limit or quota was exceeded. The body names WHICH one.
  • 500Something failed on our side. The requestId in the body is what to quote.

Every error has the same body: { error: { code, message, requestId } }.

From the OpenAPI document, version 2026-08-26. Raw OpenAPI