Skip to content

Certified consent (Enterprise)

Certified consent is the Enterprise feature set: visitors submit your form — no PRYVC account, no popup — and every submission is sealed into a tamper-evident certificate with a public verification URL. Requires an active business on the Enterprise plan and a verified domain.

Add one script tag to any page with a form:

<script
src="https://cdn.pryvc.com/v1/pryvc.js"
data-client-id="pc_your_client_id"
data-mode="consent"
data-purpose="Discuss insurance options"
data-entities="Your Agency|Your FMO LLC"
data-form-selector="#lead-form"
data-checkbox-selector="#agree"
data-disclosure-selector="#disclosure"
></script>
Attribute Required Meaning
data-client-id yes Your public client id (pc_…)
data-mode="consent" yes Activates consent mode (no button is rendered)
data-purpose yes The stated purpose, recorded in the certificate
data-entities yes Entities receiving the data, |- or comma-separated — the recipient list bound into the fingerprint
data-sp1-entity no Put on a checkbox in your form, one per recipient, valued with a name from data-entities. When present, the certificate records who was accepted and who was declined and binds both sets into the fingerprint. The SDK only ever reads these — it never ticks one.
data-form-selector no CSS selector of the form; defaults to the first <form>
data-checkbox-selector no Consent checkbox that must be checked before certification
data-disclosure-selector no Element whose text is the disclosure as displayed
data-disclosure-text no Literal disclosure text alternative
data-field-map no JSON map of CSS selector → field key, e.g. {"#em":"email"}; heuristics and data-pryvc-field attributes are the fallback
  1. On submit, the widget intercepts, collects the mapped fields, captures the disclosure text, and calls POST /v1/consent.
  2. On success it injects <input type="hidden" name="pryvc_cert_id" value="cc_…"> and re-submits the form — your backend receives the certificate id with the lead.
  3. It fails open: if certification errors (network, misconfiguration), the form still submits without a cert. Listen for failures rather than blocking your funnel.

Both events bubble from the form element:

form.addEventListener('pryvc:consent', (e) => {
// e.detail = { cert_id, fingerprint, verify_url }
});
form.addEventListener('pryvc:consent-error', (e) => {
// e.detail = { code }
});

Programmatic init is also available: window.Pryvc.initConsent({ clientId, entities, purpose, … }).

Called by the widget; you can also call it server-side from a verified origin.

{
"client_id": "pc_your_client_id",
"fields": { "first_name": "", "email": "" },
"disclosure_text": "…as displayed to the visitor…",
"entities": ["Your Agency", "Your FMO LLC"],
"purpose": "Discuss insurance options",
"page_url": "https://yoursite.com/lead"
}

Constraints: the browser Origin and the page_url host must sit on one of your verified domains; the business must be active on the Enterprise plan (402 otherwise). Field keys use the standard PRYVC field vocabulary. Rate limited per IP.

Response (201):

{
"cert_id": "cc_14dyhv5l6av8cslibs",
"fingerprint": "7353f891…",
"issued_at": "2026-07-27T21:20:18.586Z",
"verify_url": "https://verify.pryvc.com/c/cc_14dyhv5l6av8cslibs"
}

Two public surfaces, no authentication:

  • Human pagehttps://verify.pryvc.com/c/{cert_id} — a clean verification page for consumers, partners, carriers, and auditors. Every open is recorded as evidence: view count, timestamp, IP, user agent, and OS. Businesses see the view trail in the portal (Consent certs → detail) and the count per cert in the grid.
  • JSONGET https://api.pryvc.com/v1/certs/{cert_id}/verify — for programmatic validation.

No authentication. Returns everything except subject PII (the subject appears masked, e.g. j***@e***.com): business name, status, entity list, disclosure text and hash, purpose, origin domain, fingerprint, and timestamps. Hand this URL to carriers, buyers, auditors, or the consumer.

Authenticated with your sk_live_… key (Authorization: Bearer), scoped to your own certificates.

GET /v1/certs?page=1&per_page=20&status=active&subject_email=jane@example.com&q=insurance
GET /v1/certs/:cert_id
  • List returns masked subjects with paging metadata (total, page, per_page); subject_email matches exactly via a blind index, q searches the purpose.
  • Detail returns the decrypted subject fields plus full evidence (page URL, IP, user agent) — treat responses as PII.

POST /v1/business/portal/integrate (portal session) with { url, mode: "share" | "consent", purpose, entities } fetches a page on one of your verified domains, maps the form with Workers AI, and returns a deterministic, paste-ready snippet plus the field mapping. The same feature is available in the portal UI under Integration AI.

When a certificate is issued, PRYVC also captures the origin domain’s privacy policy and terms text as of that moment, keyed by domain and deduped by content hash — certificates issued while the text is unchanged share one immutable snapshot; any policy edit creates a new one. Snapshot capture runs after the 201 response and never delays your form.

  • The public verify endpoint lists each snapshot’s kind, source URL, SHA-256 content hash, and capture date.
  • The API-key and portal detail endpoints include the full captured text (policies[] with a text field), so you can produce the exact wording that was in force at opt-in.

Every certificate issuance — and every share grant, revocation, and cease acknowledgement — is also anchored into Engrave, an external append-only ledger with Ed25519-signed tree heads and client-verifiable Merkle proofs. What leaves PRYVC is hashes and generic metadata only: the event type, entity id, fingerprint, origin domain, and timestamp — never names, emails, field values, or any linkable identifier.

  • The public verify endpoint and page include the anchor receipt (anchor: ledger tx reference, entry hash, signed-root snapshot, anchor time).
  • On top of per-event anchors, PRYVC checkpoints its audit hash-chain head into Engrave every 15 minutes, so every audit row is covered even if an individual anchor write was missed, and verifies ledger consistency proofs on each cycle.
  • Practical meaning for auditors: rewriting any historical PRYVC record would require consistently rewriting two independent systems and breaking a Merkle consistency proof — evidence packs are available on request.

Anchoring is strictly fail-open: ledger unavailability never delays or blocks a consent flow.

Each certificate’s fingerprint is a SHA-256 over the canonical JSON of: cert id, business, disclosure hash, sorted entity list, origin domain, purpose, subject hash, and timestamp — and the issuance is recorded in PRYVC’s hash-chained audit log. The exact composition, canonicalization algorithm, and test vectors are published in the open Share Protocol specification. See the compliance guide for what this proves.

By default a certificate records every recipient you named. If you need to record which recipients the visitor actually agreed to — CMS requires this for Medicare marketing — render a checkbox per recipient and mark each with data-sp1-entity:

<p id="disclosure">Acme Insurance and Partner FMO LLC may contact me about coverage.</p>
<label><input type="checkbox" data-sp1-entity="Acme Insurance"> Acme Insurance may contact me</label>
<label><input type="checkbox" data-sp1-entity="Partner FMO LLC"> Partner FMO LLC may contact me</label>

The certificate then carries entities_accepted and entities_rejected, both bound into the fingerprint.

The absent case is meaningful. If your form offers no per-recipient checkboxes, both keys are omitted entirely and the certificate hashes exactly as it did before this feature existed — so existing integrations are unaffected. An empty entities_rejected means “asked, declined nobody”, which is a different fact from “never asked”, and the two deliberately do not hash alike.

A stray data-sp1-entity naming a recipient you did not declare in data-entities is ignored, so an unrelated checkbox elsewhere on the page cannot silently change what the certificate commits to.

A certificate subject has no account with you or with PRYVC, so withdrawal happens on the certificate’s own public verification page: they enter the address recorded on the certificate, receive a six-digit code there, and confirm.

When that happens the certificate moves to revoked, a 10-business-day cease-contact deadline starts, and the owner on your account is emailed with the certificate id and the deadline. Nothing is deleted — the record and every hash remain, with the withdrawal timestamped.

You also receive it programmatically. certificate.revoked is emitted on the events feed and delivered to your webhooks:

{
"id": "1dc485ed-...",
"type": "certificate.revoked",
"created_at": "2026-07-31T22:32:51.614Z",
"share_id": null,
"cert_id": "cc_q3a6goxdvyddqn2dpb",
"data": null
}

cert_id is populated for certificate events and share_id for share events; neither is set for both. The event carries no personal data — fetch the certificate with your API key if you need the subject.