API keys, members, webhooks & usage
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
API keys, members, webhooks & usage
Org-administration endpoints: invite/manage members, issue/list API keys, subscribe to webhooks, and read usage. All require an API key (see authentication); the org is always derived from the key you authenticate with — no route in this section accepts an orgId parameter, so a key can only ever act on its own org.
Note: these are admin-only surfaces. A scoped API key (one issued with an explicit
scopeslist) can never call/v1/members,/v1/keys, or/v1/webhooks— every request gets403 { "error": "insufficient_scope", "message": "this key may not use admin endpoints; manage them in the dashboard" }regardless of which scopes it holds. Only a legacy, unscoped key (scopes: null— the default for keys issued before scoped keys existed, and for keys issued viaPOST /v1/keysitself) can reach this section. Manage scoped keys' permissions from the dashboard instead.
Members
List members
GET /v1/memberscurl -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
https://api.cookiemunch.net/v1/members[
{ "userId": "usr_1", "email": "owner@example.com", "role": "owner" },
{ "userId": "usr_2", "email": "teammate@example.com", "role": "admin" }
]Invite a member
POST /v1/membersField | Type | Required | Description |
|---|---|---|---|
| string | yes | Email of the person to invite. |
|
| yes | Role to assign. |
curl -X POST https://api.cookiemunch.net/v1/members \
-H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "teammate@example.com", "role": "admin" }'Response 201: { "member": { "userId": "usr_2", "email": "teammate@example.com", "role": "admin" } }. 409 if the email is already a member.
Note: inviting a member grants durable human access — that person keeps access to the dashboard independently of the API key that invited them. Treat
members:write-capable keys with the same care as an admin password.
Change a member's role
PATCH /v1/members/{userId}Field | Type | Required | Description |
|---|---|---|---|
|
| yes | New role. |
curl -X PATCH https://api.cookiemunch.net/v1/members/usr_2 \
-H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "role": "viewer" }'400 { "error": "the owner's role cannot be changed" } if userId is the org owner.
Remove a member
DELETE /v1/members/{userId}curl -X DELETE https://api.cookiemunch.net/v1/members/usr_2 \
-H "Authorization: Bearer $COOKIEMUNCH_API_KEY"400 if userId is the owner, or if they're the org's last remaining member. Otherwise 200 { "ok": true }.
SDK equivalent
await client.members.list();
await client.members.invite('teammate@example.com', 'admin');
await client.members.setRole('usr_2', 'viewer');
await client.members.remove('usr_2');API keys
List key prefixes
GET /v1/keysReturns display metadata only — the secret is never retrievable after issuance.
curl -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
https://api.cookiemunch.net/v1/keys[{ "prefix": "fck_a1b2c3d4", "createdAt": 1730332800000 }]501 { "error": "key listing not configured" } on a self-host without key metadata storage wired.
Issue a new key
POST /v1/keysTakes no body. The key is returned once — store it immediately; it can't be recovered later, only revoked and replaced.
curl -X POST https://api.cookiemunch.net/v1/keys \
-H "Authorization: Bearer $COOKIEMUNCH_API_KEY"{ "key": "fck_9e8d7c6b5a4f3e2d1c0b", "prefix": "fck_9e8d7c6b" }Note: keys issued this way are unscoped (full access), because this route is itself admin-only and reachable only by unscoped keys. Create scoped, least-privilege keys from the dashboard's API Keys settings page.
SDK equivalent
await client.keys.list();
const { key, prefix } = await client.keys.issue();Usage
GET /v1/usageCurrent resource usage / quota summary for the org (plan-relative).
curl -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
https://api.cookiemunch.net/v1/usage{ "domains": 4, "seats": 3, "monthlyEvents": 128430 }501 { "error": "usage reporting not configured" } on a self-host without usage tracking wired. Unlike members/keys/webhooks, usage needs no scope — any valid key (scoped or not) can read it.
SDK equivalent
const usage = await client.usage();Webhooks
Full event catalogue, payload shape, and signature verification are covered in Webhooks & events. This section is the CRUD reference.
List subscriptions
GET /v1/webhooksThe signing secret is omitted from list responses.
curl -H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
https://api.cookiemunch.net/v1/webhooks[
{
"id": "whk_1",
"orgId": "org_9f01",
"url": "https://example.com/hooks/cookiemunch",
"events": ["consent.recorded", "dsar.created"],
"cbid": null,
"active": true,
"createdAt": 1730332800000
}
]Create a subscription
POST /v1/webhooksField | Type | Required | Description |
|---|---|---|---|
| string | yes | HTTPS endpoint to deliver events to. |
| string[] | yes | Non-empty list from the event catalogue. |
| string | no | Scope delivery to a single site. Omit for all sites in the org. |
curl -X POST https://api.cookiemunch.net/v1/webhooks \
-H "Authorization: Bearer $COOKIEMUNCH_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://example.com/hooks/cookiemunch", "events": ["consent.recorded", "dsar.created"] }'Response 201 includes the signing secret once:
{
"id": "whk_1",
"orgId": "org_9f01",
"url": "https://example.com/hooks/cookiemunch",
"secret": "whsec_3f9a...",
"events": ["consent.recorded", "dsar.created"],
"cbid": null,
"active": true,
"createdAt": 1730332800000
}Delete a subscription
DELETE /v1/webhooks/{id}curl -X DELETE https://api.cookiemunch.net/v1/webhooks/whk_1 \
-H "Authorization: Bearer $COOKIEMUNCH_API_KEY"204 No Content on success.
SDK equivalent
await client.webhooks.list();
await client.webhooks.create({ url, events, cbid });
await client.webhooks.delete('whk_1');