Get Cookie Consent Status
Public endpoint that works for both anonymous and authenticated users. Returns the current policy version, the user's last-saved version (null for anonymous), and a flag telling the UI whether to re-show the consent banner.
GET /api/v1/consent/cookies/status โ ๐ Public ยท Rate limit: 10 req / minute
Drives the cookie banner. Works for both anonymous and authenticated users โ the bearer token is optional. Returns the current platform privacy version (legal.privacy_version admin config, default '1.0'), the user's last-saved consent version (or null if anonymous / never consented), and requiresReConsent: true when the banner should be shown.
Banner display rule: requiresReConsent === true in three cases:
- Anonymous request (no bearer) โ always.
- Authenticated user, never consented โ
userVersion = null. - Authenticated user consented to an older version (
userVersion !== currentVersion) โ policy bumped.
When admin updates legal.privacy_version, every existing user's userVersion !== currentVersion until they re-consent.
Tied to privacy policy version, not cookie-specific. The documentVersion stored on ConsentRecord is the same legal.privacy_version config used by AuthService at registration. Cookie consent and privacy consent share a version axis โ if you bump the privacy policy, the cookie banner re-shows too. (Designed this way: cookies are a substantive part of the privacy policy.)
Request
No body, no params.
| Header | Required | Notes |
|---|---|---|
Authorization: Bearer <accessToken> | optional | When present, fetches the user's saved consent. When absent, treats as anonymous (always requiresReConsent: true). |
Response
200 OK
{
"success": true,
"data": {
"currentVersion": "1.2",
"userVersion": "1.0",
"requiresReConsent": true
}
}(Not strongly DTO-typed โ controller returns the bare object; the response interceptor wraps it in { success, data }.)
| Field | Type | Notes |
|---|---|---|
currentVersion | string | Current platform privacy version from admin config legal.privacy_version (default '1.0') |
userVersion | string | null | The user's last-saved ConsentRecord.documentVersion for documentType = 'COOKIE_CONSENT'. null for anonymous OR authenticated-never-consented. |
requiresReConsent | boolean | userVersion !== currentVersion โ true when the banner should be shown |
Errors
| HTTP | code / i18nKey | Reason |
|---|---|---|
429 | (throttle) | Rate limit exceeded (10 req/min) |
Side effects
- Read
legal.privacy_versionfromConfigService(default'1.0'). - Anonymous (no
userId) โuserVersion = null. Skip DB lookup. - Authenticated โ
consentRecord.findFirst({ where: { userId, documentType: 'COOKIE_CONSENT' }, orderBy: createdAt desc, select: { documentVersion } }). Uselatest?.documentVersion ?? null. - Compute
requiresReConsent = (userVersion !== currentVersion). - Return
{ currentVersion, userVersion, requiresReConsent }. No mutations.
Code samples
curl https://api.bio.re/api/v1/consent/cookies/status
# โ requiresReConsent always true for anonymouscurl https://api.bio.re/api/v1/consent/cookies/status \
-H "Authorization: Bearer $ACCESS_TOKEN"type CookieConsentStatus = {
currentVersion: string;
userVersion: string | null;
requiresReConsent: boolean;
};
async function getCookieStatus(accessToken?: string): Promise<CookieConsentStatus> {
const headers: Record<string, string> = {};
if (accessToken) headers.Authorization = `Bearer ${accessToken}`;
const res = await fetch('https://api.bio.re/api/v1/consent/cookies/status', { headers });
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Status fetch failed'), {
code: json?.error?.code,
});
}
return json.data;
}import { useQuery } from '@tanstack/react-query';
export const consentKeys = {
cookieStatus: (signedIn: boolean) => ['consent', 'cookies', 'status', signedIn] as const,
};
export function useCookieStatus(signedIn: boolean) {
return useQuery({
queryKey: consentKeys.cookieStatus(signedIn),
queryFn: async () => {
// Browser auto-attaches the auth cookie/token via shared fetch wrapper
const res = await fetch('/api/v1/consent/cookies/status');
const json = await res.json();
if (!res.ok || !json.success) {
throw Object.assign(new Error(json?.error?.message ?? 'Status fetch failed'), {
code: json?.error?.code,
i18nKey: json?.error?.i18nKey,
});
}
return json.data as CookieConsentStatus;
},
// Refresh on focus โ admin may have bumped the policy version
staleTime: 60_000,
refetchOnWindowFocus: true,
});
}Try it
Response Body
application/json
curl -X GET "https://loading/api/v1/consent/cookies/status"{
"success": false,
"error": {
"code": "AUTH_UNAUTHORIZED",
"message": "Invalid credentials",
"i18nKey": "auth.login.invalid_credentials",
"i18nVars": {
"field": "email"
},
"details": [
{
"message": "email must be an email"
}
],
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}Source
| Source | Path | Lines |
|---|---|---|
| Controller | apps/api-core/src/modules/content/cookie-consent.controller.ts | 58โ85 (getStatus) |
| Config | (admin-managed via ConfigService) | legal.privacy_version (default '1.0') |
| Prisma model | packages/prisma/prisma/schema.prisma | ConsentRecord (filter documentType = 'COOKIE_CONSENT', ordered by createdAt desc) |
Get Cookie Policy
Public cookie policy. Returns the 4 cookie categories (essential / functional / analytics / marketing) with localized name and description.
Save Cookie Consent
Public endpoint to save user's consent choices. Works for anonymous (userId null) and authenticated. Stores under documentType COOKIE_CONSENT with current privacy version. IP captured ONLY when analytics consented (GDPR).