Docs

Banner library

AdminUpdated Sep 15, 2026

Banner library

The banner library is an account-level store of reusable banner designs — distinct from a single site's live config. A design is a json payload (in practice a v2 { v: 2, flow, categories, ... } banner config) that isn't tied to any one site: build it once, assign it to any number of cbids, and publish to push it live everywhere it's assigned. Assignment is one-design-per-site — assigning a cbid to a new design silently moves it off whatever design it was previously assigned to.

All routes live under /v1/banners, require an API key, and are scoped to the calling key's org (a key can never read or write another org's designs). Scoped keys need banners:read for GETs and banners:write for everything else; a legacy unscoped key has full access regardless. publish only ever overlays banner-presentation keys (v, theme, categories, customCss, flow) onto a site's existing config — it can never smuggle a site-level or plan-gated field (tcf, blocking, geoRules, …) past the same plan-gating a direct PUT /v1/sites/{cbid}/config enforces.

If this deployment has no banner-library store wired up (self-hosted only — never true against the hosted API), every route below returns 501 { "error": "banner library not configured" }.

List designs

GET /v1/banners

Scope: banners:read

Returns lightweight summaries only — no json payload — so listing stays cheap regardless of library size.

curl -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
  https://api.cookiemunch.net/v1/banners
[
  {
    "id": "bnr_8f2c1a",
    "name": "EU cookie banner — dark",
    "updatedAt": 1730332800000,
    "assignedCbids": ["site_abc123", "site_def456"]
  }
]
const banners = await client.banners.list();

Create a design

POST /v1/banners

Scope: banners:write

Field

Type

Required

Description

name

string

yes

Display name for the design.

json

object

yes

A v2 banner config ({ v: 2, flow, categories, ... }). Validated the same way the Studio editor validates a live config.

curl -X POST https://api.cookiemunch.net/v1/banners \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "EU cookie banner — dark",
    "json": { "v": 2, "flow": { "views": [] }, "categories": [] }
  }'

201 Created:

{
  "id": "bnr_8f2c1a",
  "orgId": "org_9f01",
  "name": "EU cookie banner — dark",
  "json": { "v": 2, "flow": { "views": [] }, "categories": [] },
  "createdAt": 1730332800000,
  "updatedAt": 1730332800000
}

Errors: 400 { "error": "name required" } / { "error": "json required" } for missing fields; 400 { "error": "invalid_config", "issues": [...] } if json fails validation/lint.

const banner = await client.banners.create({ name, json });

Get / update / delete a design

GET    /v1/banners/{id}
PUT    /v1/banners/{id}
DELETE /v1/banners/{id}

Scope: banners:read for GET, banners:write for PUT/DELETE.

PUT accepts a partial patch ({ name?, json? }) and re-validates json when it's supplied.

curl -X PUT https://api.cookiemunch.net/v1/banners/bnr_8f2c1a \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "EU cookie banner — dark v2" }'

DELETE refuses while the design is still assigned to any site:

{ "error": "Banner is assigned to 2 site(s): site_abc123, site_def456", "code": "banner_in_use", "cbids": ["site_abc123", "site_def456"] }

Errors: 404 { "error": "banner not found" }. 409 (the banner_in_use body above) from DELETE while assigned — unassign every site first. 400 { "error": "invalid_config", "issues": [...] } from PUT if the patched json fails validation.

const banner = await client.banners.get('bnr_8f2c1a');
await client.banners.update('bnr_8f2c1a', { name: 'EU cookie banner — dark v2' });
await client.banners.delete('bnr_8f2c1a');

Assignments

GET /v1/banners/{id}/assignments
PUT /v1/banners/{id}/assignments

Scope: banners:read for GET, banners:write for PUT.

GET returns the cbids currently pointed at this design. PUT replaces the entire assignment set in one call — any cbid you drop reverts to unassigned (its already-published config is untouched), and any cbid you add is moved off whichever other design previously owned it.

Field

Type

Required

Description

cbids

string[]

yes

The complete set of site ids this design should own.

curl -X PUT https://api.cookiemunch.net/v1/banners/bnr_8f2c1a/assignments \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "cbids": ["site_abc123", "site_def456"] }'
{ "cbids": ["site_abc123", "site_def456"] }

Errors: 400 { "error": "cbids must be an array of strings" }. 422 { "error": "cbid_not_in_org", "code": "cbid_not_in_org" } if any cbid doesn't belong to the calling key's org — the whole call is rejected, none of the assignments are applied. 404 if id doesn't exist.

const { cbids } = await client.banners.assignments('bnr_8f2c1a');
await client.banners.setAssignments('bnr_8f2c1a', ['site_abc123', 'site_def456']);

Publish

POST /v1/banners/{id}/publish

Scope: banners:write

Compiles the design and overlays it onto the live SiteConfig of every currently-assigned site — this is the call that actually reaches visitors. Re-run it after every edit to a published design; PUT /v1/banners/{id} alone does not push changes live.

curl -X POST https://api.cookiemunch.net/v1/banners/bnr_8f2c1a/publish \
  -H "Authorization: Bearer $COOKIEMUNCH_API_KEY"
{ "publishedCbids": ["site_abc123", "site_def456"] }

Publishing fires a banner.published webhook per site (see webhooks).

Errors: 400 { "error": "invalid_config", "issues": [...] } if the design has drifted into an invalid state since it was last saved. 404 if id doesn't exist.

const { publishedCbids } = await client.banners.publish('bnr_8f2c1a');

Note: publishing one design across a fleet of sites — say, all EU properties sharing a brand — is the fastest way to keep them visually consistent. Build once, then call this endpoint (or wire it into a deploy pipeline) whenever the design changes, instead of editing every site's config individually.

Next: cookies, scan & verify to see what feeds a banner's cookie table, or API keys, members, webhooks & usage for the full webhook event catalogue.

Was this page helpful?