Skip to content

Preference requests

A business’s hosted preference pages deliver each request to one webhook URL, set in the portal under Preferences. PRYVC holds the person’s details only until that delivery succeeds, then deletes them — so the delivery is your only copy.

A POST with a JSON body, signed exactly like every other PRYVC webhook (Webhooks & signing): Pryvc-Signature: t=…,v1=… where v1 = HMAC-SHA256(secret, "{t}.{raw_body}"). The signing secret is shown once in the portal when you set the URL.

{
"kind": "pryvc.preference_request",
"ref": "pr_Zk3v9Qm1xT7aB2cD",
"request_kind": "dnc",
"channels": ["sms", "phone", "email", "mail"],
"received_at": "2026-11-11T18:04:22.000Z",
"due_at": "2026-11-25T18:04:22.000Z",
"site": { "slug": "acme", "domain": "acme.com" },
"subject": {
"email": "jane@example.org",
"phone": "+14155550123",
"name": "Jane Doe",
"address": "1 Market Street\nSan Francisco, CA 94105"
},
"verified": false,
"matched_certificates": [],
"compliance": {
"page_version": 3,
"content_hash": "sha256:9f2c…",
"notice_version": "2026-11-11",
"submission_hash": "sha256:41ab…",
"receipt_url": "https://verify.pryvc.com/r/pr_Zk3v9Qm1xT7aB2cD",
"ledger_url": "https://verify.pryvc.com/ledger/preference_request/6a0e…"
}
}
Field Meaning
ref The reference you and the person both use. Store it with the request.
request_kind dnc (do not contact), optout (do not sell or share), or unsub (unsubscribe from email).
channels For dnc, any of sms, phone, email, mail — only the ones the person chose. optout is always ["sale_or_sharing"]; unsub is always ["email"].
due_at The date you must act by: 10 business days after received_at.
subject What the person entered. Fields they left empty are null. Phone numbers are E.164.
verified Always false. A request is never refused for lack of verification, so it is not proof of who made it.
matched_certificates Ids of active consent certificates you hold for the same email. A flag for you to act on; PRYVC revokes nothing.
compliance.page_version, content_hash The version of your page the person was shown.

A test delivery from the portal’s Send a test button has the same shape plus "test": true. It creates no request.

Respond 2xx only once you have stored the request. PRYVC deletes its copy on a 2xx and cannot send it again. A failed delivery is retried four more times over the following hours; after that the request is sent to your owners in the encrypted daily backup email instead.

Authenticate with an API key (Authorization: Bearer sk_live_…). API keys need the Business or Enterprise plan; on the Site Watch plan, use the portal queue.

GET https://api.pryvc.com/v1/preferences/requests
Query
state open (not done, not yet due), overdue, or completed.
kind dnc, optout, or unsub.
email, phone Find requests made with this address or number. Matched by keyed hash; the value is never returned.
page, per_page Pagination; per_page up to 100.
{
"ok": true,
"data": {
"requests": [
{
"ref": "pr_Zk3v9Qm1xT7aB2cD",
"kind": "dnc",
"channels": ["sms", "phone", "email", "mail"],
"site": "acme",
"state": "delivered",
"received_at": "2026-11-11T18:04:22.000Z",
"delivered_at": "2026-11-11T18:04:23.000Z",
"due_at": "2026-11-25T18:04:22.000Z",
"completed_at": null,
"matched_certificates": [],
"receipt_url": "https://verify.pryvc.com/r/pr_Zk3v9Qm1xT7aB2cD"
}
],
"total": 1,
"page": 1,
"per_page": 20
}
}

state is received (not yet delivered), delivered, completed, or overdue. There are no contact details in any API response: PRYVC does not have them.

GET https://api.pryvc.com/v1/preferences/requests/{ref}

The same fields, plus shown: the heading, your wording, PRYVC’s fixed notice and the content hash of the page version the person saw.

POST https://api.pryvc.com/v1/preferences/requests/{ref}/complete

Call this when you have acted on the request. The person’s receipt then says you confirmed it. The call is idempotent: the first confirmation stands, and later calls return "already": true.

{ "ok": true, "data": { "ref": "pr_Zk3v9Qm1xT7aB2cD", "completed": true, "completed_at": "2026-11-12T09:15:00.000Z", "already": false } }