The consent lifecycle
A consent in Agreely moves through five stages, each a distinct artifact. The
company issues an offer, the person approves it with a passkey, that answer
becomes a receipt, the receipt updates a single enforcement record, and your code
reads that record on every use. The whole point is that each stage leaves proof,
so the final check is not a bare boolean but the tip of a verifiable chain.
1. Offer
The company issues a signed consent request for a set of catalog cells,
delivered to the person as a secure deep link. The offer is signed by the
company's DID key and commits to a Merkle root over the exact
(category, purpose) cells being requested, so the person approves precisely
what was offered and nothing can be swapped in afterward.
2. Passkey approval
The person approves per-cell in the citizen portal with a WebAuthn passkey. The passkey signs a challenge bound to the offer's Merkle root, which is what ties a specific human's authenticator to a specific set of cells at a specific moment. Approval is granular: a person can approve some cells of an offer and decline others.
The passkey signs the root, not the plaintext
The challenge the passkey signs is bound to the offer's Merkle root. That is enough to prove the person approved exactly those cells, and it means the citizen side never has to hold the company's plaintext customer identifier to produce a valid approval.
3. ConsentReceipt
The approval becomes a ConsentReceipt, a W3C Verifiable Credential that carries both the company signature and the citizen's passkey assertion. This is the portable, independently verifiable record of what happened. Anyone holding it can verify the receipt without trusting Agreely.
A manual or offline consent, where a person signs on paper rather than in the portal, instead yields a company-attested receipt. It carries the company signature alone: the company attests that it holds a hand-signed document whose hash matches. It does not carry a passkey assertion, and it does not prove a human signed. A verbal consent, given by telephone, yields a weaker receipt still, documented by the company: it names the version of the script read and carries no document digest, because there is no document. See assurance tiers below.
4. Enforcement record
The receipt updates a single authoritative enforcement record, keyed per cell
and carrying a consent_ref, a status, and an assurance_tier. This is the row
a check reads. It is keyed by the company's own plaintext customer_id, and no citizen
DID is ever written here. That separation is what keeps the company side and the
citizen side from being trivially joined; see
unlinkability.
5. The /v1 check
Your code calls the synchronous /v1 check,
a default-deny read of exactly that enforcement status. A withdrawal flips the
record to revoked, and the very next call denies, with no chain wait. The
chain is never read on this path; the enforcement record is authoritative the
instant a grant or withdrawal commits.
The response carries the consent's end, validUntil, and, after a withdrawal,
revokedAt, the instant from which Agreely treats the consent as withdrawn. For a box
left blank on a signed paper it is the signature date; for a withdrawal recorded
through /withdrawal or /revoke it is the moment it was recorded, not necessarily
when the person expressed it: stop the use as soon as the person asks, and record the
withdrawal without delay. validUntil is an upper bound: a withdrawal
ends the consent earlier, and only a system that checks again learns it. So never
cache a check.
Renewal and the consent chain
A consent is never rewritten. When it is renewed or confirmed, a new consent takes over for the same purpose, and the check follows it at once; the old one stays recorded as it was. Three cases form such a chain:
- a new sheet signed on paper takes over a sheet or a call still in force for the same purpose;
- the signed paper that comes back after a call confirms the verbal consent: its ticked purposes move into a new company-attested consent, dated from the call;
- a call may renew a sheet whose end falls within 30 calendar days. Those 30 days are an Agreely product rule, not a period set by law.
A link may not end before the one it takes over: Agreely treats a shorter consent as a withdrawal, recorded as such. A passkey-signed consent is never renewed by telephone; it is renewed with a new online request.
A withdrawal attaches to the purpose
A withdrawal does not target one isolated record, it targets the purpose. Withdrawing through any reference in the chain (the renewal or the sheet it renews, the call or the sheet that confirmed it) withdraws the running consent at the same instant, and the check denies from the next call. A consent dated before a withdrawal recorded for the same purpose never reopens it.
A withdrawal always remains possible:
- after the relationship ended, because the right to withdraw outlives the relationship;
- during a billing lapse: the
/v1withdrawal route is the only one that never answers402, because honoring a withdrawal is a duty, not a paid service. Every other route refuses until billing is restored.
A withdrawal the organization records on the person's behalf is the organization's
attestation, never the person's signature: its response says so
(recordedOnBehalf: true, assurance: "company_attested").
Assurance tiers
Two vocabularies describe how a consent was obtained. Map them, do not mix them.
/v1/check returns both: tier and assurance.
fullmaps tocitizen_signed: the consent was approved by passkey in the portal.manualmaps tocompany_attested: it was signed by hand on a sheet, recorded by the company.verbalmaps tocompany_documented: it was given by telephone and documented by the company, with no document at all.
The order of strength is full > manual > verbal. A client that only knows the
first two assurance values must treat an unknown value as not acceptable.
All three tiers enforce identically
A citizen_signed consent carries the person's passkey assertion. A company_attested consent is the company's attestation that it holds a hand-signed document whose hash matches, and it does not prove a human signed. A company_documented consent records the company's statement that a call took place, and does not prove the call. At check time all three enforce exactly the same way: only the tier differs, so your system judges how strong the proof is and decides what each tier unlocks.
Next
- Unlinkability: why the enforcement record and the citizen DID are kept apart.
- Honest boundaries: what a company-attested receipt does and does not prove.
- The protocol for the cryptography underneath.