Quickstart
Provision a tenant, capture consent in the browser, gate your backend. ~10 minutes.
Provision, capture, gate, prove
Provision (required before anything else works)
0a — Stand up the server
Self-hosting: clone dpdp-suite and start the stack with Postgres included. If your operator already runs a hosted instance, skip to 0b and use the URL they give you.
# pull and start (Postgres + API in one compose profile) git clone https://github.com/noidme-git/dpdp-suite cd dpdp-suite docker compose --profile pg up -d # API will be reachable at http://localhost:3000 # (override with DPDP_PORT if you need a different port)
0b — Bootstrap the first operator key
On a fresh database there are no users. Bootstrap creates the root operator account exactly once. Two equivalent methods — use whichever fits your workflow:
# Method A — CLI seed command (interactive; safe to run against a running server)
npm run seed-operator
# Method B — env-var fallback (useful for unattended / container first-boot)
# Set before the server starts; it creates the operator on startup and is ignored
# on subsequent boots once the record exists.
DPDP_BOOTSTRAP='{"email":"ops@example.com","password":"…"}' docker compose up -dBoth paths emit an ok_live_… operator key. Store it securely — it is shown once.
0c — Create a tenant and mint API keys in the console
Sign in to the admin console at /console with the operator account, then:
- Tenants → New tenant — fill name + domain, save.
- Activate the tenant (status must be
activebefore it can accept consent events). - API keys → Mint — the console shows
pk_live_…(publishable, browser-safe) andsk_live_…(secret, server-only) once. Copy both now.
See Authentication → for a full breakdown of all five credential types and what each can reach.
0d — Author and approve a §5 notice
Every consent event is linked to an approved notice. Draft yours, then approve it. The notice id returned by /approve is what you put in data-notice.
export API=https://api.noidme.com # or http://localhost:3000 for self-host
export SK=sk_live_… # the secret key you just minted
# 1. Draft the notice
curl -sX POST $API/v1/notices \
-H "Authorization: Bearer $SK" \
-H "Content-Type: application/json" \
-d '{"title":"Marketing consent","purposes":["marketing","analytics"]}' \
| jq .id
# → "ntc_0abc123…" ← copy this
# 2. Approve it (status moves to approved; generates the §5 hash)
curl -sX POST $API/v1/notices/ntc_0abc123…/approve \
-H "Authorization: Bearer $SK"
# → { "id": "ntc_0abc123…", "status": "approved", … }Only approved notices are accepted by the consent-capture endpoints. Drafts and archived notices return 422.
Add the consent banner (browser)
Drop the embed with your publishable key and the notice id from step 0d. It blocks non-essential scripts until consent and records the choice against the approved notice.
<script src="https://cdn.noidme.com/dpdp-embed.js" data-api="https://api.noidme.com" data-key="pk_live_…your publishable key…" data-notice="ntc_…your approved notice id…" defer></script>
data-principal attribute (or the noidme.init({ principalId }) JS call after the script loads) so you can tie a consent record to your own stable, pseudonymous identifier — for example a UUID you store in a first-party cookie. Use the same principalId in your backend gate (step 2). The API rejects PII-shaped values (email address, phone number, national ID) with 422 PII_PRINCIPAL — use an opaque handle instead.noidme.js enforcement — so the same banner that records the §6(10) receipt also unblocks (or keeps blocked) outgoing requests in the browser. This is Layer-1 honest-SDK enforcement: reliable against eager third-party tags, not against deliberately hostile in-page scripts. See noidme.js →Check consent before processing (server)
The hard gate. Allow/deny plus the §6(10) tamper-evident proof. Use the same principalId the embed recorded under.
curl -sX POST $API/v1/consent/can-process \
-H "Authorization: Bearer $SK" \
-H "Content-Type: application/json" \
-d '{
"principalId": "usr_7f3a…", # same opaque id the embed used
"noticeId": "ntc_0abc123…", # the approved notice from step 0d
"purpose": "marketing"
}'
# → { "allowed": true, "reason": "granted",
# "proof": { "seq": 42, "hash": "9f3c…", "noticeId": "ntc_0abc123…" } }Or with the Node SDK:
import { createClient } from "@noidme/dpdp-server-sdk";
const dp = createClient({
baseUrl: process.env.API, // https://api.noidme.com
apiKey: process.env.SK, // sk_live_…
});
const { allowed } = await dp.consent.canProcess({
principalId: "usr_7f3a…", // same opaque id as the embed
noticeId: "ntc_0abc123…", // approved notice id
purpose: "marketing",
});
if (allowed) {
// …safe to process
}Prove it later (audit)
Pull a regulator-ready evidence pack for a principal, or verify the entire consent chain integrity:
# Evidence pack for a single principal (returns signed PDF + JSON trail)
curl -sX POST $API/v1/admin/evidence-pack \
-H "Authorization: Bearer $SK" \
-d '{"principalId":"usr_7f3a…"}'
# Full ledger integrity check (tamper-evident hash chain)
curl -sX POST $API/v1/admin/verify-chain \
-H "Authorization: Bearer $SK"Next steps
Wire your real keys, explore every endpoint, handle principal rights, or browse an SDK.