Consent Grain
What is a Consent grain?
A Consent grain records an explicit permission grant or withdrawal by a data subject, scoped to a specific purpose and jurisdiction. Consent grains are the compliance backbone of AI memory in Areev’s context database, providing an immutable, auditable record of who gave (or revoked) permission for what, when, and under which legal basis.
For GDPR, CCPA, LGPD, and other privacy regulations, the AI agent memory system requires verifiable proof that data processing was authorized. Consent grains provide this with DID-based identity, purpose-bounded scoping, and jurisdiction tracking. Because grains in the autonomous memory engine are immutable, consent records cannot be silently modified or deleted — ensuring the audit trail remains intact for regulatory review.
The text representation used for embedding and BM25 indexing describes the consent action: "did:example:john grants did:example:acme" for grants, or "did:example:john withdraws did:example:acme" for withdrawals. This lets you search consent records by data subject or grantee DID.
| Field | Type | Required | Description |
|---|---|---|---|
subject_did | string | yes | DID of the data subject granting or withdrawing consent |
user_id | string | yes | Owner user ID (auto-populated from auth identity in HTTP; required in SDK) |
grantee_did | string | no | DID of the entity receiving the permission |
scope | string | no | Purpose or scope the consent covers (e.g., "marketing-emails") |
is_withdrawal | boolean | no | true if this is a withdrawal of prior consent (default: grant) |
basis | string | no | Legal basis (e.g., "GDPR Art. 6(1)(a)", "CCPA opt-in") |
jurisdiction | string | no | Applicable jurisdiction (e.g., "EU", "US-CA", "BR") |
prior_consent | string | no | Hash of the prior consent grain this one supersedes |
witness_dids | string[] | no | DIDs of witnesses to the consent action |
Plus all common fields (confidence, tags, namespace, etc.).
How do I record a consent grant?
Pass subject_did and the scope, basis, and jurisdiction through the /batch-add endpoint with grain_type: "consent". Both subject_did and user_id are required. When using the HTTP API, user_id is auto-populated from the authenticated caller’s identity if not explicitly provided. Include basis and jurisdiction for regulatory compliance.
The scope field defines what the consent covers — for example, "marketing-emails", "analytics", or "model-training". Keep scopes specific and consistent across your system so that consent checks can match exact scope strings. The basis field records the legal authority for processing (e.g., "GDPR Art. 6(1)(a)" for explicit consent, "CCPA opt-in" for California Consumer Privacy Act).
Use witness_dids to record third-party witnesses to the consent action, which some jurisdictions require for certain types of data processing agreements. The grantee_did identifies the entity receiving the permission — if omitted, the consent applies to the system operator by default.
import areev
db = areev.open("./data")
h = db.add("consent", {
"subject_did": "did:example:john",
"grantee_did": "did:example:acme-corp",
"scope": "marketing-emails",
"basis": "GDPR Art. 6(1)(a)",
"jurisdiction": "EU"
})
POST /api/memories/default/batch-add
Content-Type: application/json
{
"grains": [
{
"grain_type": "consent",
"fields": {
"subject_did": "did:example:john",
"grantee_did": "did:example:acme-corp",
"scope": "marketing-emails",
"basis": "GDPR Art. 6(1)(a)",
"jurisdiction": "EU"
}
}
]
}
areev add consent subject_did=did:example:john grantee_did=did:example:acme-corp scope=marketing-emails basis="GDPR Art. 6(1)(a)"
How do I record a consent withdrawal?
Set is_withdrawal to true and reference the prior consent grain via prior_consent. This creates an auditable chain showing when consent was given and when it was revoked.
The prior_consent field links the withdrawal to the original grant by hash, creating a verifiable consent lifecycle. For compliance audits, this chain provides the full history needed to demonstrate lawful processing under GDPR Article 7 or equivalent regulations — you can show exactly when consent was granted, under which basis, and exactly when it was withdrawn.
Withdrawal takes effect immediately. Once a withdrawal grain exists, any system checking consent for the given subject_did + scope + grantee_did combination will find the withdrawal and should halt the associated data processing. Your application code is responsible for performing this check before processing.
grant_hash = db.add("consent", {
"subject_did": "did:example:john",
"grantee_did": "did:example:acme-corp",
"scope": "marketing-emails",
"basis": "GDPR Art. 6(1)(a)",
"jurisdiction": "EU"
})
withdrawal_hash = db.add("consent", {
"subject_did": "did:example:john",
"grantee_did": "did:example:acme-corp",
"scope": "marketing-emails",
"is_withdrawal": True,
"prior_consent": grant_hash,
"jurisdiction": "EU"
})
POST /api/memories/default/batch-add
Content-Type: application/json
{
"grains": [
{
"grain_type": "consent",
"fields": {
"subject_did": "did:example:john",
"grantee_did": "did:example:acme-corp",
"scope": "marketing-emails",
"is_withdrawal": true,
"prior_consent": "<grant_hash>",
"jurisdiction": "EU"
}
}
]
}
How do I query Consent grains?
Search by data subject DID, grantee DID, scope, or jurisdiction using the standard /recall endpoint with grain_type: "consent".
For compliance checks, query by subject_did to find all consent records for a data subject. This surfaces both grants and withdrawals, letting your application determine the current consent status for each scope. To check a specific permission, search for the combination of subject_did, scope, and grantee_did and look at the most recent grain — if it is a withdrawal, consent is not active.
For bulk compliance audits, query by jurisdiction to find all consent records under a specific regulatory regime. Combine with tags like "needs-review" to flag consent records that require periodic re-confirmation under regulations that mandate renewal (e.g., some LGPD interpretations).
# Find all consent records for a data subject
results = db.recall(query="did:example:john", grain_type="consent")
# Find all marketing consent grants
results = db.recall(query="marketing-emails", grain_type="consent")
POST /api/memories/default/recall
Content-Type: application/json
{"query": "did:example:john", "grain_type": "consent", "limit": 20}
When should I use Consent vs. State?
Use Consent for data-subject permission records that carry legal weight — who granted what, under which legal basis, in which jurisdiction. Use State for general-purpose configuration or session snapshots without compliance semantics.
Consent grains have purpose-built fields for DID-based identity, legal basis, jurisdiction, and withdrawal tracking. A State grain storing consent information would lose these structured fields and would not integrate with Areev’s compliance verification checks. The structured fields on Consent grains enable deterministic compliance queries that would require fragile JSON parsing on State grains.
If you need to track configuration preferences that have no regulatory implications (e.g., UI theme, notification settings), use State. If the preference involves personal data processing rights, use Consent.
Related
- Grain Types: Overview of all 10 OMS grain types and shared fields
- State: For general-purpose snapshots without compliance semantics
- Belief: For knowledge claims derived from consent status
- Event: For recording the moment consent was given or withdrawn