On this page
withdrawConsent
mutation · in the family Selling
What it does
Record a customer withdrawing a consent, as staff.
STAFF: record a WITHDRAW decision for a NAMED consumer: NO record → dual-birth born withdrawn (PROOF-OF-REFUSAL — prevents re-asking, ruling 4) · granted → the evented transition · already withdrawn → the revision. The same gates + routing verbatim. Template class (classifies WITH the grant — v20).
What happens
Takes effect immediately; the withdrawal is a permanent ledger fact.
Who may call it
Capability area: Selling — Ringing sales, serving customers and issuing invoices.
- Owner
- Manager
- Associate Manager
- Sales Associate
- Cashier
- An API key whose scope allows
api:withdrawConsent
Arguments
| Name | Type | Required | Notes |
|---|---|---|---|
input | ConsentDecisionInput ConsentDecisionInput! | yes | No further notes. |
Returns
ConsentRecord ConsentRecord! — A ConsentRecord — the PROOF-OF-DECISION per (Consumer × Purpose): CONSUMER-parented (parentId = the Consumer id — the LoyaltyMember construct-parented class), family document, SPARSE (a record materializes ONLY on an explicit decision — the ratified DUAL BIRTH: born directly granted on a grant, withdrawn on a withdraw [ruling 4 — an explicit 'no' is proof-of-refusal on EITHER model]). The PERMANENT (consumer × purpose) UNIQ pair marker is BOTH the singleton guarantee AND the O(1) lookup (never released, never taken over; purge reaps). FSM: granted ⇄ withdrawn (bidirectional forever — GDPR Art. 7(3), withdrawal as easy as granting) → doomed ONLY via system:consumer_erased. NO update op — the ONLY writes are the 4 decide ops (grantConsent/withdrawConsent staff · grantMyConsent/withdrawMyConsent consumer) + the system doom; a SAME-decision re-capture is a capture-context REVISION under a new policyVersion (re-consent — route 3; revisions keep every prior capture, the Art. 7(1) proof). Capture context ∈ {policyVersion, captureSurface ∈ [storefront, pos, back_office, cli, import], captureLocale?} reflects the LATEST decision. Effective consent = resolveEffectiveConsent (the myConsents view): consumer doomed ⇒ DENIED · purpose inactive/doomed ⇒ DENIED · granted ⇒ ALLOWED · withdrawn/doomed ⇒ DENIED · ABSENT ⇒ opt_in? DENIED: ALLOWED. AUDIT RIDES EXISTING MACHINERY — NO bespoke ledger. NOT searchable (PII-bearing proof — the stance).
Example request
mutation ExampleWithdrawConsent($input: ConsentDecisionInput!) {
withdrawConsent(input: $input) {
id
sysId
type
caption
status
parentId
rootId
createdAt
updatedAt
revisionNum
revision
purposeId
policyVersion
captureSurface
captureLocale
}
}
Variables:
{
"input": {
"consumerId": "01900000-0000-7000-8000-6e8c92ec0000",
"purposeId": "01900000-0000-7000-8000-3e56c4740000",
"policyVersion": "<policy version>",
"captureSurface": "<capture surface>",
"captureLocale": "<capture locale>"
}
}
Send it with the envelope naming the version: "extensions": {"at": {"version": {"name":"genesis","number":0}}}.
Example response
{
"data": {
"withdrawConsent": {
"id": "01900000-0000-7000-8000-37386ae00000",
"sysId": "CD-EXMP-0000-000F",
"type": "ConsentRecord",
"caption": "Blue jeans",
"status": "granted",
"parentId": "01900000-0000-7000-8000-065235280000",
"rootId": "01900000-0000-7000-8000-a093dd800000",
"createdAt": "2027-01-31T00:00:00.000Z",
"updatedAt": "2027-01-31T00:00:00.000Z",
"revisionNum": 1,
"revision": "01900000-0000-7000-8000-b7960e180000",
"purposeId": "01900000-0000-7000-8000-3e56c4740000",
"policyVersion": "<policy version>",
"captureSurface": "<capture surface>",
"captureLocale": "<capture locale>"
}
},
"extensions": {
"at": {
"callId": "01EXAMPLE-CALL-ID",
"version": {
"requested": {
"name": "genesis",
"number": 0
},
"serviced": {
"name": "genesis",
"number": 0
}
}
}
}
}
Errors this call can answer
VALIDATION/INVALID— Something in the request is not valid. (VALIDATION)AUTHN/REQUIRED— Sign in to do this. (AUTHN)AUTHZ/FORBIDDEN— Your role does not allow this action. (AUTHZ)RATE_LIMIT/THROTTLED— Too many requests in a short time. (RATE_LIMIT)NOT_FOUND/*— That record could not be found. (NOT_FOUND)CONFLICT/*— The record’s state, or a change made in the meantime, does not allow this; the codes are on the CONFLICT page. (CONFLICT)VALIDATION/VERSION_REQUIRED— The request did not say which app version it came from. (VALIDATION)