RESTful API: Complete documentation for developers
Authentication with a public API key, JSON responses, 500 req/min rate limit. Every endpoint is documented in detail with cURL, JavaScript and PHP examples.
Base URL and Authentication
All API calls are made over HTTPS via the base URL below. HTTP requests are redirected to HTTPS with a 301 redirect.
Base URL
https://cerez.io/api/v1
OpenAPI 3.1 Specification
Machine-readable OpenAPI 3.1 definition of all endpoints. Import it into Postman, Insomnia, code generators and interactive clients.
Download openapi.jsonAuthentication: Public API Key
The SDK API uses a public API key: passed in the URL path for GET requests and in the request body for POST requests. This key is used by the browser-side SDK, so it is expected to be visible on the client. The Authorization: Bearer header is not used. You can get your API key from admin panel > Installation.
curl https://cerez.io/api/v1/banner/YOUR_API_KEY
/api/v1/banner/{api_key}
Returns the active banner configuration for a domain. The SDK calls this endpoint on every page load; the response is cached server-side for 5 minutes.
Path Parameter
| Parameter | Type | Description |
|---|---|---|
api_key | string | The public API key for your domain (required) |
Query Parameters (optional)
| Parameter | Type | Description |
|---|---|---|
lang | string | tr | en | de (banner language; default: domain setting) |
preview | boolean | If true, no consent cookie is written (for live testing in the Banner Builder) |
Example Request
curl https://cerez.io/api/v1/banner/YOUR_API_KEY
Successful Response 200 OK
{ "success": true, "data": { "domain": "example.com", "position": "bottom", "theme": "modern", "language": "tr", "texts": { "title": "Çerez Tercihleriniz", "description": "Sitemiz deneyiminizi iyileştirmek için çerez kullanır...", "accept_all": "Tümünü Kabul Et", "reject_all": "Tümünü Reddet" }, "categories": [ { "id": "necessary", "required": true }, { "id": "analytics", "required": false }, { "id": "marketing", "required": false } ], "consent_expiry_days": 180, "products": { "cookie": true, "accessibility": false } } }
/api/v1/consent/log
Records the user's consent decision on the server. The record is retained for 90 days to meet the KVKK and GDPR burden of proof.
Body Parameters (JSON)
| Parameter | Type | Description |
|---|---|---|
api_key | string | Public API key (required) |
visitor_id | string | Anonymous visitor ID, up to 100 characters (required) |
action | string | accept_all | reject_all | partial | update (required) |
categories_accepted | object | { necessary, analytics, marketing, functional } with boolean values (required) |
banner_variant | string | A | B (optional, A/B test) |
tc_string | string | IAB TCF TC String (optional) |
device_type | string | desktop | mobile | tablet (optional) |
external_id | string | Your own user ID (optional) |
user_agent | string | Captured automatically; sending it manually is optional |
Example Request
curl -X POST https://cerez.io/api/v1/consent/log \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d '{ "api_key": "YOUR_API_KEY", "visitor_id": "vis_a1b2c3d4", "action": "partial", "categories_accepted": { "necessary": true, "analytics": true, "marketing": false }, "device_type": "desktop" }'
Response 200 OK
{ "status": "ok" }
Note: add the Accept: application/json header to the request so validation errors return 422.
/api/v1/heartbeat
Increments the pageview counter and marks the domain as active. The SDK calls this endpoint once per page load.
Body Parameters
| Parameter | Type | Description |
|---|---|---|
api_key | string | Public API key |
session_id | string | Session ID (for unique pageview tracking) |
page_url | string | Current page URL |
referrer | string | document.referrer value (optional) |
Response
{ "success": true, "pageview_count_month": 42183, "plan_limit": 100000, "usage_percent": 42.18 }
All SDK Endpoints
All /api/v1 endpoints that work with the public API key. For each one's full request and response schema, see the machine-readable OpenAPI 3.1 definition.
Cookies and Consent
| Method | Endpoint | Description |
|---|---|---|
| GET | /banner/{api_key} | Banner configuration (language, theme, categories) |
| POST | /consent/log | Consent logging (fallback path: /consent-log) |
| GET | /consent/state/{api_key} | Server-side consent lookup (server-side GTM) |
| GET | /consent/group/{api_key} | Cross-domain consent synchronization |
| POST | /preferences | Universal preference center save |
Accessibility
| Method | Endpoint | Description |
|---|---|---|
| GET | /a11y/{api_key} | Accessibility widget configuration |
| GET | /a11y/{api_key}/ai-labels | AI-generated alt-text and aria-label suggestions |
| POST | /a11y/feature-used | Accessibility feature usage telemetry |
| POST | /a11y/easy-read | AI text simplification (Easy Read) |
| POST | /a11y/ci-report | CI/CD accessibility gate report |
TCF and Vendor List
| Method | Endpoint | Description |
|---|---|---|
| GET | /tcf/{api_key} | IAB TCF configuration and GVL metadata |
| GET | /gvl.json | Global Vendor List (24-hour edge cache) |
| GET | /tcf-validator-test | TCF validator test page (HTML) |
Telemetry and System
| Method | Endpoint | Description |
|---|---|---|
| POST | /heartbeat | Pageview and liveness signal |
| POST | /interactions | Interaction telemetry (off by default per KVKK) |
| POST | /telemetry | Anonymous SDK performance metrics |
| GET | /meta | Version and capability discovery (public, read-only) |
Response Envelopes
For historical reasons, SDK endpoints use different response envelopes; these shapes are preserved for backward compatibility. Parse responses according to the table below.
| Envelope | Endpoints |
|---|---|
{ ... } (no envelope, direct object) | GET /banner, GET /a11y, GET /tcf, GET /gvl.json |
{ "status": "ok" } | POST /consent/log, POST /heartbeat, POST /a11y/feature-used |
{ "success": true } | POST /preferences, POST /a11y/ci-report |
{ "ok": true } | POST /telemetry |
{ "found": ... } | GET /consent/state, GET /consent/group |
{ "data": ..., "meta": ... } | All Management API endpoints (/api/mgmt/v1) |
API Version
You can fetch the current API and SDK versions along with TCF/GVL metadata at runtime from the GET /api/v1/meta endpoint (public, read-only).
GET /api/v1/meta
{
"api_version": "1.0.0",
"sdk_version": "2.6.2",
"products": ["cookie", "accessibility"],
"tcf": { "gvl_version": 123, "policy_version": 5 },
"docs": "https://cerez.io/kaynaklar/api-referans"
}
OpenAPI 3.1 Specification
All 18 SDK endpoints in machine-readable form (Postman import / client generation).
Management API (server-to-server)
A separate API for programmatic server-side access. The SDK API (public api_key) is for the banner and consent; the Management API uses the secret_key to pull your domain data (cookie inventory, consent records, statistics, accessibility score). Read-only.
Base URL
https://cerez.io/api/mgmt/v1
Authentication: Bearer secret_key
Send your secret key in the Authorization: Bearer header. Get the secret key from admin panel > Installation > API and store it ONLY in a secure server environment; never place it on the client.
curl https://cerez.io/api/mgmt/v1/domain \ -H "Authorization: Bearer YOUR_SECRET_KEY"
{ "data": ..., "meta": ... }. Errors are returned as RFC 9457 application/problem+json. Rate limit: 60 requests/minute.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /domain | Plan, subscription and settings |
| GET | /cookies | Cookie categories and scanned cookies |
| GET | /stats?period=30 | Accept/reject rate, device breakdown, daily series |
| GET | /consents?from&to&cursor | Consent records (cursor-paginated, KVKK/GDPR evidence) |
| GET | /a11y/score | Latest WCAG scan score and violation breakdown |
| GET | /consents/receipt?visitor_id= | Consent evidence for a single visitor (KVKK/GDPR) |
| POST | /scan | Trigger a cookie scan (synchronous, up to 3 pages) |
| GET | /scan/{id} | Scan status and result |
| GET | /webhooks | Webhook list (secret masked) |
| POST | /webhooks | Create webhook (url + events) |
| DELETE | /webhooks/{id} | Delete webhook |
| POST | /webhooks/{id}/test | Send a test event |
| GET | /dsar/export?visitor_id= | Export data subject data (GDPR Art. 15) |
| POST | /dsar/erasure | Anonymize data subject data (two-step) |
Successful Response 200 OK
GET /api/mgmt/v1/domain
{
"data": {
"id": 42,
"site_name": "Örnek",
"domain_url": "https://example.com",
"products": ["cookie", "accessibility"],
"subscriptions": [
{ "product": "cookie", "plan_slug": "cookie_pro", "status": "active" }
],
"settings": { "kvkk_enabled": true, "consent_expiry_days": 180 }
},
"meta": { "api": "mgmt/v1", "generated_at": "2026-06-30T12:00:00+00:00" }
}
Webhooks HMAC-SHA256
When low-frequency events occur, a signed POST is sent to your registered endpoints: scan.completed, cookies.new_found, scan.error. High-volume consent events are not sent via webhook.
Example payload and headers
POST https://ornek.com/webhooks/cerez
X-Cerez-Event: scan.completed
X-Cerez-Timestamp: 1782475200
X-Cerez-Signature: sha256=3a7b...e0
{
"event": "scan.completed",
"created_at": "2026-06-30T12:00:00+00:00",
"domain_id": 42,
"data": { "total_cookies": 31, "new_cookies": 2 }
}
Signature verification (receiver side)
The signature is derived from the timestamp and the raw body. Verify with a constant-time comparison and confirm the timestamp is not older than 5 minutes (replay protection).
// Node.js
const crypto = require('crypto');
const expected = 'sha256=' + crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(timestamp + '.' + rawBody)
.digest('hex');
const ok = crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signatureHeader)
);
// PHP
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
$ok = hash_equals($expected, $signatureHeader);
DSAR (Data Subject Requests) KVKK m.11 / GDPR m.15-17
Helps you respond to access and erasure requests for a visitor's data. Erasure = anonymization: direct identifiers (visitor_id, external_id, user_agent, region) are removed; consent proof (action, categories, TCF string, timestamps) is PRESERVED. You verify the visitor's identity.
Anonymization is two-step (accidental-deletion protection)
# 1. Önizleme (confirm_token yok) — hiçbir şey değişmez curl -X POST https://cerez.io/api/mgmt/v1/dsar/erasure \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "visitor_id": "vis_a1b2c3" }' # -> { "data": { "dry_run": true, "matched_count": 3, "confirm_token": "..." } } # 2. Uygula (önizlemeden gelen confirm_token ile) curl -X POST https://cerez.io/api/mgmt/v1/dsar/erasure \ -H "Authorization: Bearer YOUR_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "visitor_id": "vis_a1b2c3", "confirm_token": "..." }' # -> { "data": { "dry_run": false, "affected_count": 3 } }
If the record count changes between preview and apply, the token becomes invalid (409). Access and erasure are written to the audit log on every successful call. This tool helps you meet your compliance obligations; consult qualified counsel for legal validity.
OpenAPI 3.1 Specification
Machine-readable OpenAPI 3.1 definition of the Management API (Postman/codegen).
Management API openapi.jsonRequest Limits
Applied per IP address. When the limit is exceeded, the response includes a header indicating the wait time.
Retry-After header specifies the wait time in seconds. Exponential backoff (1s, 2s, 4s, 8s...) is recommended for burst protection. For a custom rate limit increase on the Enterprise plan, contact the sales team.
HTTP Status Codes
| Code | Description | Typical Cause |
|---|---|---|
| 200 | OK | Request successful |
| 202 | Accepted | Accepted (telemetry / interaction, async) |
| 304 | Not Modified | Not modified (ETag; gvl.json) |
| 402 | Payment Required | Active subscription required (product disabled) |
| 403 | Forbidden | Outside the IP whitelist or plan limit exceeded |
| 404 | Not Found | API key or resource not found |
| 422 | Unprocessable | Validation error; check the errors field in the response |
| 429 | Too Many Requests | Rate limit exceeded (500/min) |
| 502 | Bad Gateway | Upstream service (AI / scan) temporary error |
| 503 | Service Unavailable | Service temporarily unavailable; Retry-After |
Error Response Format
{ "success": false, "error": { "code": "INVALID_API_KEY", "message": "API key bulunamadı veya devre dışı", "details": { "field": "api_key" } } }
Event Notifications Live
Webhook support is available through the Management API. For low-frequency events a POST signed with HMAC-SHA256 is sent to your registered endpoint. See the Management API section for setup and signature verification.
scan.completed
Triggered when a cookie scan completes (total and new cookie counts)
cookies.new_found
Triggered when new cookies are found in a scan
scan.error
Triggered when a scan fails
The questions on your mind
What is the difference between the SDK and the API?
Is there a batch endpoint?
How does the IP whitelist work?
Is there webhook support?
What happens if the rate limit is exceeded?
Retry-After header indicates how many seconds you need to wait. Exponential backoff (1s, 2s, 4s, 8s...) is recommended for burst protection. The rate limit can be raised on the Enterprise plan.Want to test the API?
Get your API key with a 14-day free Pro trial, copy the code and start integrating right away.