Skip to content

Documentation · API

Public API

01 · Quickstart

Five minutes, REST and JSON

The ConsentLab public API (/v1) exposes your consent statistics, your register, the banner configuration and scan triggering, all in REST/JSON, authenticated by key. It is included on the Business (site ≥ 500,000 sessions) and Agency plans.

The full interactive reference lives at /v1/docs, the raw OpenAPI schema at /v1/openapi.json. This page is a hand-written guide: if you are unsure about an exact field, those two resources are authoritative.

Open the interactive docs /v1/docsOpenAPI schema /v1/openapi.json

Create an API key

From your dashboard (Settings → API), create a key by choosing the scopes (permissions) you need and the Site(s) it may reach. The key, in the format cl_live_…, is shown only once: copy it immediately into a secrets manager.

First authenticated call

Every request carries the Authorization: Bearer cl_live_… header (snippet on the right). The site id returned is the parameter for every other endpoint. A staging environment is available for your tests.

02 · Recipes

Three use cases, three scripts

Agency reporting

For a client dashboard, combine the aggregates (consent-stats: acceptance rate, volumes) with the detail when needed (consents).

Archiving the register

To keep the consent proof in your own warehouse, paginate consents by cursor (limit ≤ 100) until it is exhausted (script on the right).

Banner config in CI/CD

Version your banner configurations and apply them from your pipeline with PUT banner-config. Store the key in your CI’s encrypted environment (a secret), never in the repo: a write:config key can read or delete nothing else, that is least privilege.

03 · Endpoints

Six endpoints, the whole v1 surface

Six endpoints cover the whole v1 surface. Parameter and response-schema details are on the interactive docs /v1/docs; the scopes shown match the v1 contract, the interactive docs are authoritative if an endpoint evolves.

MethodPathRequired scopeDescription
GET/v1/sitesnoneList the sites the key can access.
GET/v1/sites/:id/consent-statsread:statsConsent aggregates (rates, volumes).
GET/v1/sites/:id/consentsread:consentsConsent register, cursor-paginated.
GET/v1/sites/:id/banner-configread:config / write:configCurrent banner configuration.
PUT/v1/sites/:id/banner-configwrite:configUpdate the banner configuration.
POST/v1/sites/:id/scanstrigger:scanTrigger a cookie scan for the site.

04 · Limits

Errors, rate limiting, pagination

Error codes

Errors follow standard HTTP statuses, with a stable machine code in the JSON body. For VALIDATION_FAILED, it is in the code field; the other codes below are the value of the message field.

HTTPError codeCause
400VALIDATION_FAILEDInvalid request (missing or malformed parameter). Field details are in <code>message</code> (array).
401INVALID_API_KEYMissing, malformed, revoked or expired key.
403INSUFFICIENT_SCOPEThe key lacks the scope required by the endpoint.
403API_ACCESS_REQUIREDThe plan does not include API access (Business ≥ 500k or Agency).
403IP_NOT_ALLOWEDCall made from an IP outside the key’s configured allowlist.
404SITE_NOT_FOUNDSite does not exist or is outside the key scope.
404CONFIG_NOT_FOUNDNo banner configuration exists yet for this site.
429RATE_LIMIT_EXCEEDEDRate exceeded: see Retry-After.

Rate limiting

Every response carries the quota headers (example on the right). The guaranteed floors are 300 requests/min/IP and 600 requests/min/key; X-RateLimit-Reset is expressed in seconds remaining. Counters are shared across all our instances, so the limits are exact and enforced against the real client IP, with no drift from load balancing.

On a 429 RATE_LIMIT_EXCEEDED, honour the Retry-After header before retrying (backoff). Do not loop without waiting: you would stay blocked.

05 · Versioning

v1 in the path, 12 months notice

The API is versioned in the path (/v1/). Backwards-compatible changes (new fields, new endpoints) ship without a version bump; any breaking change would go through a new version (/v2/).

Deprecation policy: 12 months. If a version or endpoint is deprecated, it keeps being served for at least 12 months after the announcement, giving you time to migrate calmly.

Changelog

v1: initial release. Per-Site scoped API keys, endpoints sites, consent-stats, consents, banner-config, scans, cursor pagination and rate limiting.

06 · Security

Keys that do not leak

  • Format and one-time display · A cl_live_… key is shown only at creation. We store only a fingerprint of it: it can never be shown again.
  • Least privilege · Grant only the scopes you need among the five available (read:stats, read:consents, read:config, write:config, trigger:scan). A reporting job only needs read access; to read the banner config without being able to change it, read:config alone is enough.
  • Per-Site scoping · A key can only reach the Sites you attached it to. Create one key per integration rather than a single catch-all key.
  • Time-to-live (TTL) · At creation, set an expiry (expiresInDays, from 1 to 3650 days). Past that point the key is automatically rejected (401 INVALID_API_KEY): ideal for temporary access (audit, contractor, POC).
  • Two-step rotation · Create the new key, deploy it, then revoke the old one. A 24h grace period lets your services switch over without downtime.
  • Immediate revocation · A revoked key stops working instantly (401 INVALID_API_KEY). Revoke at the slightest doubt.
  • Auto-revocation on leak · Our key prefixes (cl_live_…) are registered with GitHub secret scanning. If a key is accidentally pushed to a public repository, we are alerted and the key is revoked automatically: a leaked key does not stay usable.
  • Never commit a key · Environment variable or secrets manager, never in the repo nor in front-end code (keys are server-to-server).

Restrict a key to IPs

You can restrict a key to a list of source IP addresses or CIDR ranges (IPv4 and IPv6). Any call coming from an IP outside that allowlist is rejected with a 403 IP_NOT_ALLOWED, however valid the key is. Ideal for pinning a server integration to the fixed egress IP of your infrastructure or CI runner.

Can I use an API key in my front-end?

No. cl_live_… keys are server-to-server: exposed on the client, they would be stolen. For the browser-side banner, the widget’s public identifier (data-cc-key) is what is used, see the Installation tab.

I lost my key, how do I get it back?

It cannot be shown again (we only keep a fingerprint). Create a new one with the same scopes, deploy it, then revoke the old one.

Which plan gives API access?

API access is included on the Business (site ≥ 500,000 sessions/month) and Agency plans. On a plan without access, endpoints return 403 API_ACCESS_REQUIRED.

Ready to automate your compliance?

Create a key from your dashboard, or explore the interactive API reference.

First call

# Authenticate every request with the Authorization: Bearer header
curl "https://api.consentlab.eu/v1/sites" \
  -H "Authorization: Bearer $CONSENTLAB_API_KEY"

Response

[
  { "id": "3f2a9c7e-1b4d-4e8a-9f2c-7a1b2c3d4e5f", "name": "mysite.com", "created_at": "2026-01-15T09:24:00Z" }
]

Environments

# Production
https://api.consentlab.eu/v1
# Staging (pré-production)
https://dev.api.consentlab.eu/v1

Agency reporting

# Consent aggregates for a site (acceptance rate, volumes…)
curl "https://api.consentlab.eu/v1/sites/3f2a9c7e-1b4d-4e8a-9f2c-7a1b2c3d4e5f/consent-stats" \
  -H "Authorization: Bearer $CONSENTLAB_API_KEY"   # scope: read:stats

Archiving the register

#!/usr/bin/env bash
# Exports the whole consent register as JSON Lines, page by page.
# The key lives in an environment variable, never hard-coded in the script.
SITE="3f2a9c7e-1b4d-4e8a-9f2c-7a1b2c3d4e5f"
cursor=""
while : ; do
  resp=$(curl -s "https://api.consentlab.eu/v1/sites/$SITE/consents?limit=100&cursor=$cursor" \
    -H "Authorization: Bearer $CONSENTLAB_API_KEY")   # scope: read:consents
  echo "$resp" | jq -c '.data[]' >> register.jsonl
  # Exact pagination field: see /v1/openapi.json
  cursor=$(echo "$resp" | jq -r '.next_cursor // empty')
  [ -z "$cursor" ] && break
done

Config in CI/CD

# Apply the banner config from your pipeline (scope: write:config).
# The JSON body is illustrative, exact schema: /v1/openapi.json
curl -X PUT "https://api.consentlab.eu/v1/sites/3f2a9c7e-1b4d-4e8a-9f2c-7a1b2c3d4e5f/banner-config" \
  -H "Authorization: Bearer $CONSENTLAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "primary_color": "#0F766E", "position": "bottom" }'

Rate-limit headers

HTTP/1.1 200 OK
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 598
X-RateLimit-Reset: 42          # seconds until the window resets
# On a 429, the Retry-After header tells you how long to wait.