/v1-consent records a visitor's per-purpose consent decisions (an audit trail)
and reads back the latest one. It's the server-side source of truth behind the
Web SDK's consent namespace,
which POSTs here for you — but you can call it directly from any client.
Records consent — does not enforce it (yet)
/v1-consent records decisions to an audit trail; it does not yet block
ingestion when a visitor denies. A recorded granted: false does not stop
future events from being collected. The only consent enforced at ingestion today
is the fingerprint-strip gate (context.fingerprint is dropped without an
explicit grant — see Event
ingestion).
Server-side enforcement of analytics consent is planned; until then, gate
tracking client-side — see Consent — DPDP &
GDPR.
The path is /v1-consent (one segment)
The endpoint is <apiHost>/v1-consent — a single hyphenated segment, like
/v1-batch. /v1/consent (two segments) is not a route and returns 404.
Authentication
/v1-consent uses method-aware key
permissions:
| Method | Purpose | Key required |
|---|---|---|
POST | Record a decision | write or admin (uk_live_) |
GET | Read the latest decision | read or admin (uk_read_) |
Any other method returns 405 Method not allowed. The endpoint is rate-limited
to 60 requests per minute per (organization, client IP) — see Errors & rate
limits.
Record a decision — POST /v1-consent
curl -X POST https://YOUR_PROJECT_REF.supabase.co/functions/v1/v1-consent \
-H "Authorization: Bearer uk_live_YOUR_WRITE_KEY" \
-H "Content-Type: application/json" \
-d '{
"purpose": "analytics",
"granted": true,
"anonymousId": "anon_xyz789",
"userId": "user_456"
}'Request body
| Field | Type | Required | Notes |
|---|---|---|---|
purpose | string | yes | The consent purpose, e.g. analytics, fingerprinting. Max 64 characters. |
granted | boolean | yes | true = consent given, false = denied. |
anonymousId | string | yes | The subject's anonymous ID. Max 128 characters. |
userId | string | no | The known user ID, once identified. Max 128 characters. |
The decision is stored against a canonical id — your userId when present,
otherwise the anonymousId — so a decision recorded while anonymous still
applies after the visitor is identified. The server also records the request IP,
user-agent, and a source of sdk.
Response
{ "success": true, "purpose": "analytics", "granted": true }Validation failures return 400 with the reason in error (e.g.
purpose is required (non-empty string), purpose exceeds 64 chars,
granted is required (boolean), anonymousId exceeds 128 chars). A storage
failure returns 500 Failed to record consent decision.
Read the latest decision — GET /v1-consent
curl "https://YOUR_PROJECT_REF.supabase.co/functions/v1/v1-consent?purpose=analytics&anonymousId=anon_xyz789" \
-H "Authorization: Bearer uk_read_YOUR_READ_KEY"Query parameters
| Parameter | Required | Notes |
|---|---|---|
purpose | yes | The purpose to look up. Missing → 400. |
anonymousId | yes | The subject's anonymous ID. Missing → 400. |
userId | no | If present, used as the canonical id for the lookup (matching how the decision was recorded). |
Response
When a decision exists, the most recent one is returned:
{ "purpose": "analytics", "granted": true, "recorded": true, "created_at": "2026-06-10T10:00:00.000Z" }When none exists:
{ "purpose": "analytics", "granted": null, "recorded": false }Next
- Consent — DPDP & GDPR — the compliance framing and how the SDK records consent for you.
- Web SDK reference → Consent —
consent.grant()/deny()/hasConsent()in the browser. - Event ingestion → the context object — the fingerprint-consent gate that is enforced today.
Last updated 2026-06-10