REST API

DPOKit REST API reference — scanner, data map, consent, DSAR, retention, and developer endpoints under the dpo-kit/v1 namespace.

7 min read

REST API

Version: 1.9.0

DPOKit exposes a REST API under the namespace dpo-kit/v1. The base URL is your site's REST root followed by the namespace:

https://example.com/wp-json/dpo-kit/v1

Authentication

Auth TypeDescription
AdminRequires a logged-in WordPress user with the manage_options capability. Use WordPress Application Passwords or a cookie + X-WP-Nonce header.
PublicNo authentication required. Available to unauthenticated visitors.

Using Application Passwords (recommended for headless setups)

  1. Go to Users → Profile in wp-admin and generate an Application Password.
  2. Send requests with HTTP Basic authentication:
Authorization: Basic base64(username:application_password)

Using Cookie + Nonce (JavaScript on the same domain)

fetch( '/wp-json/dpo-kit/v1/consent/stats', {
    headers: {
        'X-WP-Nonce': wpApiSettings.nonce,
    },
    credentials: 'same-origin',
} );

Endpoints

Scanner

POST /dpo-kit/v1/scanner/start

Auth: Admin

Start a new site scan. Returns a scan_id and the list of URLs to crawl.

Request body:

{
    "scan_depth": 50
}

Response:

{
    "scan_id": 42,
    "urls": [ "https://example.com/", "https://example.com/about/" ],
    "total": 2
}

POST /dpo-kit/v1/scanner/scan-page

Auth: Admin

Scan a single URL and save findings.

Request body:

{
    "scan_id": 42,
    "url": "https://example.com/shop/"
}

Response:

{
    "url": "https://example.com/shop/",
    "findings": [ "..." ],
    "count": 3
}

POST /dpo-kit/v1/scanner/complete

Auth: Admin

Mark a scan as completed. Fires the dpo_kit_scan_complete action.

Request body:

{ "scan_id": 42 }

GET /dpo-kit/v1/scanner/results/{scan_id}

Auth: Admin

Retrieve results and vendor summary for a completed scan.

Query params:

  • resource_type (optional) — Filter by type: script, iframe, pixel, cookie, api_call, gtm_tag, form.

Data Map

GET /dpo-kit/v1/data-map

Auth: Admin

List all data map entries.

Query params:

  • status — Filter by status (active, archived).
  • legal_basis — Filter by legal basis.
  • search — Text search.

POST /dpo-kit/v1/data-map

Auth: Admin

Create a data map entry.

Request body:

{
    "vendor_id": 5,
    "purpose": "Analytics",
    "legal_basis": "consent",
    "data_categories": ["IP address", "Page views"],
    "retention_period": "26 months"
}

PUT /dpo-kit/v1/data-map/{id}

Auth: Admin

Update a data map entry.


DELETE /dpo-kit/v1/data-map/{id}

Auth: Admin

Delete a data map entry.


POST /dpo-kit/v1/data-map/bulk-add

Auth: Admin

Bulk add data map entries from scan results.

Request body:

{
    "scan_id": 42,
    "vendors": [ "google-analytics", "meta-pixel" ]
}

Vendor Library

GET /dpo-kit/v1/vendors

Auth: Admin

List all vendors (built-in + custom).

Query params:

  • search — Text search by name or slug.

POST /dpo-kit/v1/vendors

Auth: Admin

Create a custom vendor.

Request body:

{
    "name": "My Analytics",
    "slug": "my-analytics",
    "purpose": "Website analytics",
    "data_categories": ["IP address", "Browser info"],
    "default_retention": "13 months"
}

PUT /dpo-kit/v1/vendors/{id}

Auth: Admin

Update a vendor.


DELETE /dpo-kit/v1/vendors/{id}

Auth: Admin

Delete a custom vendor. Built-in vendors cannot be deleted (returns 403).


Consent

POST /dpo-kit/v1/consent

Auth: Public

Record a consent decision from the front-end banner. Called automatically by the consent banner JavaScript.

Request body:

{
    "visitor_id": "abc123",
    "categories_accepted": ["functional", "analytics"],
    "categories_rejected": ["marketing"],
    "consent_action": "manage"
}

Response:

{ "id": 101, "message": "Consent recorded." }

GET /dpo-kit/v1/consent/status

Auth: Public

Get the consent banner configuration and categories. Use this in headless/decoupled setups to render a custom consent UI.

Response:

{
    "enabled": true,
    "categories": {
        "functional": { "id": "functional", "label": "Functional", "required": true },
        "analytics":  { "id": "analytics",  "label": "Analytics",  "required": false }
    },
    "settings": {
        "position": "bottom",
        "title": "We value your privacy",
        "message": "...",
        "accept_text": "Accept All",
        "reject_text": "Reject All",
        "expiry_days": 365,
        "privacy_url": "https://example.com/privacy"
    }
}

GET /dpo-kit/v1/consent/records

Auth: Admin

List consent records.

Query params:

  • consent_action — Filter by action: accept_all, reject_all, manage.
  • date_from — Start date (YYYY-MM-DD).
  • date_to — End date (YYYY-MM-DD).
  • search — Search by visitor ID.
  • per_page — Records per page (default: 50).
  • offset — Pagination offset.

GET /dpo-kit/v1/consent/stats

Auth: Admin

Get aggregate consent statistics (totals, breakdown by action, category acceptance rates).


Script Registry

GET /dpo-kit/v1/scripts

Auth: Admin

List registered consent-gated scripts.

Query params:

  • category — Filter by consent category.
  • is_active — Filter by active status (1 or 0).
  • search — Text search.

POST /dpo-kit/v1/scripts

Auth: Admin

Register a consent-gated script.

Request body:

{
    "handle": "my-chat-widget",
    "label": "Live Chat",
    "category": "functional",
    "script_url": "https://chat.example.com/widget.js",
    "blocking_method": "type_attribute"
}

PUT /dpo-kit/v1/scripts/{id}

Auth: Admin

Update a registered script.


DELETE /dpo-kit/v1/scripts/{id}

Auth: Admin

Delete a registered script.


DSAR (Headless / Decoupled)

POST /dpo-kit/v1/dsar/intake

Auth: Public

Submit a Data Subject Access Request from a headless front-end (e.g. a React or Next.js app).

Spam protection: Include a X-PV-HP-Check header with an empty value (omit entirely for real requests). Bots that send all headers will be rejected.

Request body:

{
    "request_type": "access",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "additional_info": "Please include all marketing communications."
}

Valid request types: access, deletion, rectification, portability, objection

Response (201):

{
    "id": 15,
    "reference": "DSR-20260311-A1B2C3",
    "deadline_date": "2026-04-10",
    "message": "Your request has been received. You will receive an acknowledgement email shortly."
}

GET /dpo-kit/v1/dsar/status

Auth: Public

Check the status of a DSAR case. Requires both the reference number and the requestor's email address to prevent enumeration.

Query params:

  • reference (required) — Case reference number (e.g. DSR-20260311-A1B2C3).
  • email (required) — Email address used to submit the request.

Response:

{
    "reference": "DSR-20260311-A1B2C3",
    "request_type": "access",
    "status": "in_progress",
    "status_label": "In Progress",
    "deadline": "2026-04-10",
    "submitted": "2026-03-11 09:00:00",
    "completed": null
}

Retention

GET /dpo-kit/v1/retention/policies

Auth: Admin

List retention policies.

Query params:

  • active_only — Return only active policies (1).
  • data_category — Filter by data category slug.

POST /dpo-kit/v1/retention/run

Auth: Admin

Trigger a retention enforcement run. Supports dry-run mode.

Request body:

{
    "dry_run": true,
    "policy_id": 3
}

Omit policy_id to run all active policies.

Response:

{
    "results": [
        { "policy_name": "Old Comments", "data_category": "comments", "action": "anonymise", "records_affected": 12 }
    ],
    "policies_run": 1,
    "total_affected": 12,
    "dry_run": true
}

Developer

GET /dpo-kit/v1/developer/hooks

Auth: Admin

List all documented action and filter hooks provided by DPOKit.

Query params:

  • type — Filter by type: action or filter.

GET /dpo-kit/v1/developer/extensions

Auth: Admin

List all third-party extensions currently registered via the dpo_kit_register_extensions action.

Response:

{
    "extensions": {
        "dsar_sources":    [ { "id": "my-crm", "label": "CRM Records" } ],
        "consent_scripts": [ { "handle": "my-tracker", "label": "My Tracker" } ],
        "vendors":         [ { "slug": "my-analytics", "name": "My Analytics" } ]
    },
    "totals": {
        "dsar_sources": 1,
        "consent_scripts": 1,
        "vendors": 1
    }
}

Error Responses

All error responses follow the standard WordPress REST API error format:

{
    "code":    "not_found",
    "message": "No request found matching that reference number and email address.",
    "data":    { "status": 404 }
}

Common error codes:

CodeHTTP StatusMeaning
rest_forbidden401 / 403Not authenticated or insufficient permissions
not_found404Resource not found
invalid_email422Email address failed validation
dsar_disabled503DSAR intake is currently disabled
spam_detected400Honeypot triggered
create_failed500Database write failed
update_failed500Database update failed
delete_failed403Cannot delete protected resource