Getting started with the Cookie Munch API
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
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 |
|---|---|
| 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 log, stats, CSV export (read); preference-center records (read/write). |
| List DSARs (read); create/advance DSARs (write). |
| List vendors (read); create a vendor (write). |
| List RoPA entries (read); create a RoPA entry (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/meandGET /v1/usagerequire 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/v1If 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/jsononPOST/PUT/PATCHrequests 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) acceptfrom/toquery parameters instead of pages.The one unauthenticated route on
/v1isGET /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 |
|---|---|
| Success (read, or a write that returns the updated resource). |
| Created (site, DSAR, vendor, RoPA entry, webhook, banner, API key). |
| Accepted — an async job (a cookie scan) was started; poll for status. |
| Success, no body (delete, OPTIONS preflight). |
| Malformed request — a missing or invalid field. |
| Missing or invalid API key. |
| Authenticated but forbidden — insufficient scope, or a plan/verification gate. |
| Not found, or it belongs to another org — these are indistinguishable by design: the API never confirms that another org's resource exists. |
| Conflict — e.g. a |
| Semantically invalid — e.g. assigning a |
| 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/sdkimport { 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 |
|
Go |
|
.NET / C# |
|
Ruby |
|
PHP |
|
Java |
|
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
/docs/developer/rest-sites — sites, config, snippets, scans
/docs/developer/rest-consent — consent log, stats, export, receipts
/docs/developer/rest-auth — full authentication & scopes reference
/docs/developer/rest-conventions — the full conventions & error reference
/docs/developer/rest-privacy — DSAR, vendors, RoPA
/docs/developer/rest-banners — the account-level banner library
/docs/developer/webhooks — subscribing to consent and DSAR events
/docs/developer/sdk-install and /docs/developer/sdk-reference — the JS/TS SDK in depth
/docs/developer/mcp-setup — wiring the API up for an AI agent
/docs/developer/openapi — the machine-readable OpenAPI 3.1 document