Public API Routes
Base path: /consenti/api/v1 (default — set via basePath in createConsenti()). No authentication required.
| Method | Path | Description |
|---|---|---|
| GET | /profiles/:tenantId/:complianceGroup/:locale | Hot-serve — serve locale JSON directly from disk (zero DB) |
| GET | /profiles/:tenantId/:profileId/:version/:locale | Serve a specific version locale JSON (dashboard preview) |
| GET | /resolve-profile | Geo-resolve compliance group, return file path + locale |
| GET | /profiles/:id | Get profile by ID (DB-backed, default locale) |
| GET | /profiles/:id/:locale | Get profile by ID and locale (DB-backed) |
| GET | /profiles/auto/:locale | Legacy: geo-resolve and return matching active profile |
| POST | /consent | Submit a consent record |
| GET | /consent/:visitorId | Get current consent for a visitor |
| PUT | /consent/:visitorId | Update consent for a visitor |
| DELETE | /consent/:visitorId | GDPR erasure — delete all data for visitor |
| GET | /consent/:visitorId/verify | Verify consent is still valid |
Static profile file serving (hot path)
The primary way to serve profiles at scale. Locale JSON files are written to disk when a profile is activated in the dashboard. These routes serve them directly from the filesystem — no DB query on the hot path.
GET /profiles/:tenantId/:complianceGroup/:locale
Serves the active locale JSON for a compliance group from ${storage.path}/profiles/${tenantId}/${complianceGroup}/${locale}.json. Returns Cache-Control: public, max-age=3600, stale-while-revalidate=60 — safe for CDN caching.
If the requested locale file does not exist, responds with 303 See Other to .../default, which serves default.json (the defaultLocale content).
// GET /consenti/api/v1/profiles/default/opt-in/en HTTP/1.1GET /profiles/:tenantId/:profileId/:version/:locale
Serves a specific immutable version of a profile locale JSON — used by the dashboard version history viewer. These files are written once and never modified.
// GET /consenti/api/v1/profiles/default/my-profile-uuid/2/fr-FR HTTP/1.1Resolve profile
GET /resolve-profile
Used by widgets configured with compliance.type: 'auto'. Call this once on page load to discover which compliance group and locale file the visitor should receive. The widget then fetches that file directly — zero subsequent DB queries.
Geo resolution uses the geoDataProvider configured in createConsenti(). When S3 sync is enabled, the returned path is an S3 URL.
| Query param | Description |
|---|---|
tz | IANA timezone string (e.g. Europe/Paris). |
lang | Accept-Language value (e.g. fr-FR,fr;q=0.9). |
locale | Preferred BCP 47 locale (e.g. fr-FR). |
// GET /consenti/api/v1/resolve-profile?tz=Europe/Paris&lang=fr-FR&locale=fr-FR HTTP/1.1warning: 'locale_not_found' field is present only when the requested locale was unavailable and the path was redirected to default.json.DB-backed profile routes
These routes query the database on each request. Use them for server-side rendering or when you need a fully resolved profile object including the translations map. For high-traffic public-facing widget use, prefer the static file serving routes above.
Both endpoints return the same response shape. The only difference is which locale is resolved: /profiles/:id uses the profile's defaultLocale, while /profiles/:id/:locale uses the requested locale (falling back to defaultLocale if no translation exists).
Response shape
Both endpoints return a fully-resolved profile — banner text, modal copy, and button labels are already merged for the active locale. There is no raw translations map.
| Field | Type | Description |
|---|---|---|
| id | string | Profile UUID |
| version | number | Schema version — bump triggers re-consent |
| defaultLocale | string | BCP 47 locale used as the translation fallback |
| currentLocale | string | Locale whose content is present in this response |
| locales | string[] | All locale keys defined on the profile |
| cookies | Cookie[] | Cookies/purposes managed by this profile |
| mainBanner | MainBanner | Banner config resolved for currentLocale |
| preferenceModal | PreferenceModal | Modal config resolved for currentLocale |
| gpcBanner? | GpcBanner | GPC-specific banner variant (omitted if not configured) |
| resolvedComplianceGroup? | ComplianceGroupId | Present only on /profiles/auto/:locale — the geo-resolved compliance group |
GET /profiles/:id
Returns the profile resolved in its defaultLocale. currentLocale will equal defaultLocale.
// GET /consenti/api/v1/profiles/my-profile-id HTTP/1.1GET /profiles/:id/:locale
Same response shape as /profiles/:id, but currentLocale is set to :locale and all banner/modal strings are resolved for that locale. If the requested locale has no translation, the response falls back to defaultLocale (and currentLocale reflects the requested locale regardless).
// GET /consenti/api/v1/profiles/my-profile-id/fr HTTP/1.1locales in the response to build a locale switcher — it lists every locale key the profile has translations for, so you can offer only the languages that are actually configured.GET /profiles/auto/:locale Legacy
Legacy geo-resolution route — returns a fully resolved profile object from the database. Prefer GET /resolve-profile (above) for new integrations: it returns a file path so the widget fetches the locale JSON directly from disk or CDN, removing all DB overhead from the hot path.
Geo-resolves the visitor's compliance group from geo signals, finds the active profile tagged to that group, and returns it resolved for :locale. The response includes resolvedComplianceGroup. Falls back to the default profile when no active profile exists for the resolved group.
Requires compliance.type: 'auto' in createConsenti().
| Query param | Description |
|---|---|
tz | IANA timezone string (e.g. Europe/Paris). Used when geoDataProvider: 'timezone'. |
lang | Accept-Language header value (e.g. fr-FR,fr;q=0.9). Used when geoDataProvider: 'language'. |
// GET /consenti/api/v1/profiles/auto/en?tz=Europe/Paris HTTP/1.1Consent
Consent records are keyed by visitorId. The visitor ID is persisted in a cookie (consenti_vid) set by the widget after the first submission.
POST /consent
Creates or updates a consent record. If visitorId is omitted, the server generates one and sets it as a cookie in the response.
// POST /consenti/api/v1/consent HTTP/1.1
// Content-Type: application/json
{
"profileId": "my-profile-id", // required
"consentJson": { // required
"necessary": "granted",
"analytics": "granted",
"marketing": "denied"
},
"visitorId": "uuid-v4", // optional — generated if omitted
"profileVersion": 3, // optional — defaults to 1
"locale": "en", // optional — defaults to "en"
"gpcDetected": false, // optional — defaults to false
"source": "banner" // optional — "banner" | "api" | "import"
}GET /consent/:visitorId
// GET /consenti/api/v1/consent/visitor-uuid HTTP/1.1PUT /consent/:visitorId
Updates an existing consent record. Only the supplied fields are applied.
// PUT /consenti/api/v1/consent/visitor-uuid HTTP/1.1
// Content-Type: application/json
{
"consentJson": { // required
"necessary": "granted",
"analytics": "denied",
"marketing": "denied"
},
"locale": "fr", // optional
"gpcDetected": true // optional
}DELETE /consent/:visitorId
GDPR right-to-erasure. Deletes the consent record, consent history, and visitor record for the given visitor ID. Also expires the consent cookie in the response.
// DELETE /consenti/api/v1/consent/visitor-uuid HTTP/1.1GET /consent/:visitorId/verify
Checks whether the stored consent record is still valid — i.e., the profile version matches and the record has not expired. The UI widget calls this on page load to decide whether to re-show the banner.
// GET /consenti/api/v1/consent/visitor-uuid/verify HTTP/1.1POST /consent after the visitor accepts, then calls GET /consent/:visitorId/verify on subsequent page loads to skip the banner if consent is still valid.