Docs

Getting started with the Cookie Munch API

AdminUpdated Sep 15, 2026

Getting started with the Cookie Munch API

Cookie Munch is a self-hosted Consent Management Platform — a Cookiebot/CookieYes alternative that does real prior-blocking of third-party scripts, keeps a tamper-evident, hash-chained consent ledger, and implements Google Consent Mode v2, IAB TCF/GPP/US Privacy, geo/GPC targeting, a cookie scanner, policy generators, a preference center, and DSAR workflows.

The Developer API is the stable, versioned /v1 HTTP surface behind all of that. It's the same API the dashboard and the official SDKs use under the hood, so anything you can do by hand in the dashboard, you can automate here.

What you can build

With the Developer API you can:

  • Manage sites — register a site, read/write its banner config, fetch the install snippet, trigger a cookie scan, verify domain ownership, and read A/B test results.

  • Read the consent ledger — per-day consent stats, the raw consent log, a CSV export, and signed, third-party-verifiable consent receipts.

  • Aggregate consent across surfaces — look up one end user's consent decisions across every site in your org (web, mobile, desktop) by a stable subjectId.

  • Run privacy operations — submit and advance DSARs (access/deletion/rectification/ portability/opt-out requests), maintain a vendor registry with risk scoring, and keep a RoPA (Record of Processing Activities).

  • Manage the account — issue/list API keys, invite and manage org members, check plan usage, and register webhooks for consent and DSAR events.

  • Reuse banner designs — an account-level banner library you can create, assign to sites, and publish independently of any one site's config.

Every operation is scoped to your organization — the org is derived from the API key itself, so there's no orgId parameter to get wrong, and a key from one org can structurally never see another org's data.

Authentication

Creating a key

Issue an API key from Settings → API keys in the dashboard. You can also mint one from the API itself, once you have a full-access key to bootstrap with:

curl -X POST https://api.cookiemunch.net/v1/keys \
  -H "Authorization: Bearer fck_existingkey…"
{
  "key": "fck_8f2a91c0b3d4e5f6...",
  "prefix": "fck_8f2a91c0"
}

Keys use the fck_… prefix. The full key value is returned exactly once, at creation time — the server only ever stores a hash of it. If you lose it, revoke it and issue a new one; GET /v1/keys only ever shows you the non-secret prefix for identification.

Sending the key

Two equivalent header forms are accepted on every request:

# Authorization: Bearer (recommended)
curl https://api.cookiemunch.net/v1/me \
  -H "Authorization: Bearer fck_…"

# ...or X-API-Key
curl https://api.cookiemunch.net/v1/me \
  -H "X-API-Key: fck_…"

GET /v1/me needs no scope and is the cheapest way to confirm a key is valid:

{ "orgId": "org_9k2m", "plan": "pro", "keyPrefix": "fck_8f2a91c0" }

Scopes

Keys can be unscoped (full access to everything below) or scoped to a least-privilege allow-list of resource:action pairs:

Scope

Grants

sites:read / sites:write

List/get sites, read config, cookies/scan-status/A-B results, install snippet, list/create brand kits, read a signed receipt, export a subject's records (read); create/delete site, verify domain, save config, delete brand kit, trigger a scan, erase a subject's consent (write).

consent:read / consent:write

Consent log, stats, CSV export (read); preference-center records (read/write).

dsar:read / dsar:write

List DSARs (read); create/advance DSARs (write).

vendors:read / vendors:write

List vendors (read); create a vendor (write).

ropa:read / ropa:write

List RoPA entries (read); create a RoPA entry (write).

banners:read / banners:write

List/get banner-library entries (read); create/update/delete (write).

A single narrow receipt:read scope also exists for fetching one signed receipt by stamp without granting the broader consent:read.

Security notes:

  • GET /v1/me and GET /v1/usage require no scope — every key, scoped or not, can call them.

  • The org-admin surfaces (/v1/members, /v1/keys, /v1/webhooks) can only be called with an unscoped (full-access) key. There is no scope that grants them — by design, since they can mint durable human or programmatic access to your org.

  • A request whose key lacks the required scope gets a 403:

    { "error": "insufficient_scope", "message": "missing required scope: consent:write" }
  • Every /v1/* response carries permissive CORS headers (Access-Control-Allow-Origin: *) since these are server-to-server bearer credentials, not cookies — there's no session to leak cross-origin. Treat your key like a password: keep it server-side, out of client-side JS and version control, and scope it down to only the resources an integration actually needs.

Base URL, versioning, and content types

https://api.cookiemunch.net/v1

If you're self-hosting, swap in your own origin — the /v1 prefix is the same. The SDKs take the origin (without /v1) as baseUrl and append the version prefix for you.

  • All request and response bodies are JSON. Send Content-Type: application/json on POST/PUT/PATCH requests that take a body.

  • There is currently no pagination — list endpoints (GET /v1/sites, GET /v1/dsar, GET /v1/vendors, etc.) return the full collection. Time-ranged endpoints (consent log, stats, export) accept from/to query parameters instead of pages.

  • The one unauthenticated route on /v1 is GET /v1/openapi.json, a machine-readable OpenAPI 3.1 document you can feed into a client generator or API explorer.

Your first request

List the sites (properties) registered to your org:

curl https://api.cookiemunch.net/v1/sites \
  -H "Authorization: Bearer fck_…"
[
  { "cbid": "acme-com-9f3k", "orgId": "org_9k2m", "domain": "acme.com" },
  { "cbid": "shop-acme-com-2la8", "orgId": "org_9k2m", "domain": "shop.acme.com" }
]

From there, cbid (the Cookie Munch ID assigned when you register a site) is the path parameter used across the rest of the API — for example GET /v1/sites/{cbid}/config to read a site's banner config, or GET /v1/sites/{cbid}/consent/stats?from=...&to=... for consent stats over a date range.

Errors & conventions

Every error body has the same minimal shape:

{ "error": "site not found" }

Scope errors add a machine-readable code alongside a human message:

{ "error": "insufficient_scope", "message": "missing required scope: consent:write" }

Common status codes:

Status

Meaning

200

Success (read, or a write that returns the updated resource).

201

Created (site, DSAR, vendor, RoPA entry, webhook, banner, API key).

202

Accepted — an async job (a cookie scan) was started; poll for status.

204

Success, no body (delete, OPTIONS preflight).

400

Malformed request — a missing or invalid field.

401

Missing or invalid API key.

403

Authenticated but forbidden — insufficient scope, or a plan/verification gate.

404

Not found, or it belongs to another org — these are indistinguishable by design: the API never confirms that another org's resource exists.

409

Conflict — e.g. a cbid already claimed, a scan already running, an illegal DSAR status transition.

422

Semantically invalid — e.g. assigning a cbid outside your org to a banner.

501

The endpoint exists in this API version but isn't wired up on this deployment (common on minimal self-hosts, e.g. cookie scanning without Playwright configured).

There's no separate idempotency-key mechanism today; retries of a GET are always safe, and POST endpoints that create resources (sites, DSARs, keys) will create a new one on each call unless you dedupe on your side by a natural key (e.g. cbid for sites, which returns 409 on a repeat).

SDKs

JavaScript / TypeScript — @cookiemunch/sdk

A small, fully-typed REST client with no required dependencies beyond fetch. It mirrors every /v1 route and works in Node, Deno, Bun, and the browser.

npm install @cookiemunch/sdk
import { createCookieMunch, CookieMunchApiError } from '@cookiemunch/sdk';

const client = createCookieMunch({
  apiKey: process.env.COOKIEMUNCH_API_KEY!,
  baseUrl: 'https://api.cookiemunch.net', // /v1 is appended for you
});

try {
  const sites = await client.sites.list();
  const stats = await client.consent.stats(sites[0].cbid, { from: Date.now() - 30 * 86_400_000 });
  console.log(stats);
} catch (err) {
  if (err instanceof CookieMunchApiError) {
    console.error(err.status, err.message, err.code);
  }
  throw err;
}

The client never accepts or sends an orgId — the API key alone determines the org, so cross-org access is structurally impossible from client code.

Other languages

The same REST surface has official, tested SDKs for server-side integrations in every major backend language:

Language

Package

Python

cookiemunch (PyPI)

Go

github.com/cookiemunch/cookiemunch-go

.NET / C#

CookieMunch (NuGet)

Ruby

cookiemunch (RubyGems)

PHP

cookiemunch/cookiemunch (Composer)

Java

net.cookiemunch:cookiemunch (Maven)

Each follows the same shape as the TS client: construct with an API key and a base URL, call resource methods (sites, consent, dsar, vendors, ropa, webhooks, …), and get typed errors back on non-2xx responses. If you're integrating a native mobile/desktop app instead of a backend, use the platform SDK (@cookiemunch/react-native, the Swift/Kotlin/Flutter packages) rather than the REST client directly — they add consent gating and Consent Mode signal plumbing on top of the same ledger.

There's also @cookiemunch/mcp, an MCP server that exposes this same API as tools an AI agent can call directly, built on top of @cookiemunch/sdk.

Next steps

Was this page helpful?