ConsentStackDocs

API Reference

Technical reference for ConsentStack's edge function API endpoints.

ConsentStack exposes three edge-function endpoints that power the consent banner on your site. The SDK calls these automatically — you only need this reference if you are building a custom integration or debugging network requests.

Base URL: https://origins.consentstack.io

All endpoints return JSON and include CORS headers. Every request that references a site must include a valid Origin header matching a domain registered in your dashboard.

GET /functions/v1/config

Returns the published consent configuration for a site, resolved for the visitor's region and language.

GET https://origins.consentstack.io/functions/v1/config?site_key=YOUR_SITE_KEY

Query parameters

ParameterTypeRequiredDescription
site_keystringYesYour public site key (found in the dashboard under Site Settings).
regionstringNoOverride automatic geo-detection with a specific region ID (e.g. gdpr, us_state_laws).
langstringNoOverride automatic language detection with a language code (e.g. de, fr).

Request headers

HeaderRequiredDescription
OriginYesThe requesting domain. Must match a domain registered for this site.

Response (200)

{
  "config": { ... },
  "sdkCategories": [
    {
      "id": "essential",
      "name": "Essential",
      "description": "Required for the website to function properly.",
      "consentModel": "exempt"
    },
    {
      "id": "analytics",
      "name": "Analytics",
      "description": "Help us understand how visitors interact with our website.",
      "consentModel": "opt_in"
    }
  ],
  "resolvedRegion": "gdpr",
  "resolvedLanguage": "en",
  "resolvedContent": {
    "title": "We value your privacy",
    "description": "...",
    "acceptAllText": "Accept All",
    "rejectAllText": "Reject All",
    "customizeText": "Customize",
    "savePreferencesText": "Save Preferences",
    "closeText": "Close"
  },
  "resolvedUi": {
    "required": "Required"
  },
  "showBranding": true,
  "version": 3,
  "site_name": "My Website",
  "scriptRules": [
    { "pattern": "google-analytics.com", "category": "analytics" }
  ]
}

Response fields

FieldTypeDescription
configobjectThe full published config object (appearance, content, categories, regions, consent rules). Falls back to built-in defaults if no config is published.
sdkCategoriesarrayConsent categories resolved for the visitor's region. Each entry includes id, name, description, and the applicable consentModel (opt_in, opt_out, notice_only, or exempt).
resolvedRegionstring | nullThe region ID matched from the visitor's location (e.g. gdpr, us_state_laws, default). null if no region matched.
resolvedLanguagestringThe language code used for content (e.g. en, de). Determined by the lang parameter, the visitor's browser language, or the region's default language.
resolvedContentobjectBanner and preferences UI strings in the resolved language, with consent-model-specific overrides applied.
resolvedUiobjectTranslated UI labels (e.g. the "Required" badge text).
showBrandingbooleanWhether to display ConsentStack branding. true for free-tier sites.
versionnumberThe published config version number. 0 if no config has been published.
site_namestringThe site name from your dashboard.
scriptRulesarrayActive script blocking rules. Each entry has a pattern (domain pattern to match) and a category (the consent category that governs it).

Error responses

StatusBodyCondition
400{"error": "site_key is required"}Missing or invalid site_key parameter.
403{"error": "Site is paused"}The site has been paused in the dashboard.
403{"error": "Missing Origin header"}No Origin header in the request.
403{"error": "Origin not registered for this site"}The requesting domain is not registered for this site key.
404{"error": "Site not found"}No site matches the provided site_key.
500{"error": "Internal server error"}Unexpected server error.

Caching

Responses include Cache-Control: private, no-store. Config changes take effect immediately — there is no CDN caching layer between publish and delivery.

Usage cap

Free-tier sites that exceed their monthly active user cap receive a 200 response with {"disabled": true, "reason": "cap_exceeded"} instead of the config payload. The SDK gracefully hides the banner when it receives this response.


POST /functions/v1/consent

Records a visitor's consent decision. The SDK calls this endpoint when a visitor interacts with the banner (accept, reject, customize) and on page load for returning visitors.

POST https://origins.consentstack.io/functions/v1/consent
Content-Type: application/json

Request body

FieldTypeRequiredDescription
site_keystringYesYour public site key.
anon_idstringYesA client-generated anonymous visitor ID (max 100 chars). Hashed server-side before storage.
categoriesobjectYesA map of category IDs to booleans representing the visitor's consent choices. Example: {"essential": true, "analytics": false, "marketing": false}. Max 50 entries.
event_typestringYesOne of initial (first interaction), update (changed preferences), or impression (banner was shown).
event_actionstringNoThe action taken: opt_in, opt_out, partial, or acknowledge.
config_versionnumberNoThe config version the visitor saw (for audit trail).
regionstringNoThe resolved region ID at the time of consent.
consent_modelstringNoThe active consent model: opt_in, opt_out, or notice_only.
regulationstringNoThe regulation that applied (e.g. gdpr, us_state_laws).
time_to_action_msnumberNoMilliseconds between banner display and visitor action.
interactionstringNoHow the visitor interacted (e.g. accept_all, reject_all, save_preferences). Max 50 chars.
preferences_openedbooleanNoWhether the visitor opened the preferences panel before deciding.
banner_load_time_msnumberNoMilliseconds the banner took to render.
banner_positionstringNoBanner layout position (e.g. bottom-full, center-modal).
page_urlstringNoThe page URL where consent was given. Max 2000 chars.
sdk_versionstringNoThe SDK version that sent the request.
languagestringNoThe visitor's browser language.
resolved_languagestringNoThe language the banner was displayed in.

Request headers

HeaderRequiredDescription
OriginYesMust match a registered domain for the site.

Example request

{
  "site_key": "sk_live_abc123",
  "anon_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "categories": {
    "essential": true,
    "analytics": true,
    "marketing": false
  },
  "event_type": "initial",
  "event_action": "partial",
  "config_version": 3,
  "region": "gdpr",
  "consent_model": "opt_in",
  "time_to_action_ms": 4200,
  "interaction": "save_preferences",
  "preferences_opened": true,
  "page_url": "https://example.com/pricing",
  "sdk_version": "0.1.0"
}

Server-side enrichment

The server adds several fields before storing the consent log:

  • Visitor ID hashing -- The anon_id is hashed with SHA-256 before storage. The raw ID is never persisted.
  • User-Agent parsing -- Browser name, OS, and device type (desktop, mobile, tablet) are extracted from the User-Agent header.
  • Country detection -- The visitor's country code is read from infrastructure headers at the network edge.
  • Config linkage -- The consent log is linked to the published config ID for a complete audit trail.

Response codes

StatusBodyCondition
201{"success": true}Consent log recorded successfully.
400{"error": "..."}Validation error (missing fields, unknown category IDs, invalid JSON).
403{"error": "Site is paused"}The site is paused.
403{"error": "Origin not registered for this site"}Domain not registered.
404{"error": "Site not found"}No site matches the provided site_key.
405{"error": "Method not allowed"}Request used a method other than POST.
500{"error": "Internal server error"}Unexpected server error.

Category IDs in the categories object are validated against your published config. Sending an unknown category ID returns a 400 error with the invalid IDs listed in the message. Impression events skip this validation.


POST /functions/v1/scripts

Reports third-party scripts detected on the page. The SDK scans the DOM for script elements, extracts their domains, and sends them to this endpoint. The server upserts each script and auto-categorizes known tracker domains.

POST https://origins.consentstack.io/functions/v1/scripts
Content-Type: application/json

Query parameters

ParameterTypeRequiredDescription
sync_idstring (UUID)NoLinks this report to a tracker sync session initiated from the dashboard.

Request body

FieldTypeRequiredDescription
site_keystringYesYour public site key.
page_urlstringYesThe page URL where scripts were detected. Max 500 chars.
scriptsarrayYesArray of detected scripts (max 100). Each entry contains the fields below.
timestampnumberYesUnix timestamp of the detection.
sync_idstringNoUUID linking to a dashboard-initiated sync (deprecated in body; use query parameter).
errorstringNoError message if the scan encountered issues. Max 500 chars.

Script entry fields

FieldTypeDescription
srcstringThe full script src URL. Max 2000 chars.
domainstringThe extracted domain of the script (e.g. google-analytics.com). Max 500 chars.
categorystring | nullThe SDK's best-guess category from its local known-tracker list, or null if unknown.
blockedbooleanWhether the SDK blocked this script from executing.

Example request

{
  "site_key": "sk_live_abc123",
  "page_url": "https://example.com/",
  "scripts": [
    {
      "src": "https://www.google-analytics.com/analytics.js",
      "domain": "google-analytics.com",
      "category": "analytics",
      "blocked": true
    },
    {
      "src": "https://cdn.example.com/widget.js",
      "domain": "cdn.example.com",
      "category": null,
      "blocked": false
    }
  ],
  "timestamp": 1709654400
}

Server-side behavior

For each reported script, the server:

  1. Upserts by domain -- If the domain has been seen before for this site, the existing record is updated. New domains are inserted.
  2. Auto-categorizes -- Known tracker domains are matched against a built-in database and assigned a category automatically.
  3. Updates sync status -- If a sync_id is provided, the corresponding tracker sync record is marked as complete (or failed, if an error was included).

Response codes

StatusBodyCondition
200{"success": true}Scripts processed successfully.
400{"error": "..."}Validation error (invalid body or sync_id format).
404{"error": "Site not found"}No site matches the provided site_key.
405{"error": "Method not allowed"}Request used a method other than POST.
500{"error": "Internal server error"}Unexpected server error.

Rate limiting

All endpoints are rate-limited at the CDN edge: 20 requests per 10 seconds per IP address (~120 requests/minute). This limit is for abuse prevention and should not affect normal SDK usage.

What's next