Untitled
Legal Document Snapshot Integration
This guide defines the 2.0 groundwork for legal-document consent flows such as terms and conditions, privacy policies, and DPAs.
Goal
The client should be able to record acceptance for the exact document release the user saw without needing to know c15t's internal policyId.
That means the preferred client contract is:
- A terms server renders or resolves the active legal document release.
- The terms server issues a signed
documentSnapshotTokenfor that release. - The client sends that token back when the user accepts or rejects the document.
- c15t verifies the token and stores append-only consent evidence against the matching legal-document release.
System Responsibilities
Terms Server
The terms server is the source of truth for the document release that was shown to the user.
It is responsible for:
- resolving the current legal document release
- knowing the release metadata:
typehashversioneffectiveDate
- minting a signed
documentSnapshotToken - returning the rendered document and token to the client
The terms server should own signing. c15t should not expose a production-safe browser helper that can mint these tokens because doing that would require shipping the signing key to the client.
Client SDK / UI
The client should:
- render the document content from the terms server
- hold the
documentSnapshotTokenreturned for that rendered release - call c15t accept or reject primitives with that token when the user acts
The client may know policyHash, but it should not need to know policyId.
c15t Backend
The c15t backend is responsible for:
- verifying the signed
documentSnapshotToken - extracting authoritative release metadata from the token
- resolving the matching legal-document policy row
- storing append-only consent evidence for the subject and document release
Preferred Request Contract
For legal-document consent writes, the preferred lookup order is:
documentSnapshotTokenpolicyHashpolicyIdas a compatibility fallback only
documentSnapshotToken is the auditable path because it proves which release the user saw without forcing the client to understand c15t internals.
policyHash remains useful as a lightweight fallback for integrations that can identify the rendered document release but do not yet have a signing service.
policyId should not be the long-term client contract.
Snapshot Token Claims
The signed token should carry enough metadata for c15t to verify and resolve the document release:
iss: token issueraud: intended c15t audiencesub: release hashtenantId: tenant that owns the release, when applicabletype: legal document typeversion: release version stringhash: stable release hasheffectiveDate: ISO timestamp for the effective dateiat: issued-at timestampexp: expiration timestamp
The current demo helper uses that shape so the wire contract is established now, even though real issuance should move to a dedicated server flow.
Auditability and Compliance
For a fully auditable flow:
- the rendered release must be versioned
- the release must have stable metadata, especially
hash - acceptance must be append-only
- the evidence should tie the subject, action, time, and exact release together
- signed snapshot tokens should be issued by a trusted server, not the browser
This gives c15t a defensible record of what document release was accepted and when.
What Ships in 2.0
This PR is groundwork, not the full terms-platform rollout.
Included now:
- token-first legal-document consent inputs in c15t
policyHashfallback support- an example terms demo that identifies the user first and then records acceptance
- a demo-only unsafe browser signer in
examples/demofor local testing when no real terms server exists yet
Deferred until the next phase:
- a production terms server that owns rendering and token issuance
- automatic release resolution from a real document service
- signed snapshot delivery from server to client as part of document rendering
Demo-Only Unsafe Signer
examples/demo/lib/unsafe-demo-legal-document-snapshot.ts exists only to let the example app exercise the contract before the real terms server lands.
It is intentionally unsafe for production use because it requires exposing a signing key to the browser bundle.
Use it only for local development or temporary internal demos.
If You Already Have a Privacy Policy Without a Hash
That is not a blocker for 2.0 groundwork, but it is not the end state either.
Short term:
- you can continue using existing legal-document records
policyIdcompatibility can still exist server-sidepolicyHashfallback can be added once release hashing exists
Long term:
- every rendered legal-document release should have a stable hash
- the terms server should issue snapshot tokens using that hash
Without a stable release hash, the audit trail is weaker because the acceptance cannot be tied as precisely to the rendered document version.