Consent Docs

Consent events

The webhook events sent when a consent record is created, changed, withdrawn or expires, and when an import ends, with payload fields and examples.

Reference5 min readFor developers calling the REST API

Four webhook events report a change to one consent record, and one reports an import from a file. Each arrives in the envelope described in Webhook format.

Payload fields#

data is the same for the four record events: the consent record as the API returns it, plus subject.

Field in data Type Description
consentId string The record's id. The simplest way to match the event to your user.
status string GRANTED, PARTIAL, DENIED, WITHDRAWN, EXPIRED or PENDING.
formId, formVersion, formContentHash UUID, integer, string The form version the person answered.
decisions array One entry for each purpose: purposeKey, purposeName, category, granted and, when the purpose is allowed but a partner was refused, partners.
countryCode, subdivisionCode string or null Where the person was.
lawCode string or null The law that applied, such as DPDP.
collectedOn, expiresOn time When the current answer was given and when it ends.
withdrawnOn time or null When the record was withdrawn.
proofHash string The seal of the record's current state.
test boolean true for a record written with a test key.
subject.type string The type of identifier the record was recorded under.
subject.fingerprint string or null The subject fingerprint of that identifier. null for records made before fingerprints existed, and for records already erased.
subject.reference string or null The identifier as you sent it, only when your project stores a readable copy.
basis, noticeReference, noticeSha256 string For consent brought in from earlier, when set. Present only then.
captureContext object On consent.granted and consent.updated, when the write sent capture. attestedByStaffOnly is true when only your staff attest the consent. See Capture fields.
actingAs object On consent.withdrawn, when a parent, lawful guardian or nominee made the rights request behind it. See Who acted for the person.
processors array On consent.updated, consent.withdrawn and consent.expired: the instructions for your Data Processors. Often empty. See Processor instructions.

The three ways to tell whom an event is about are in Match events to users.

Events#

Sent when

A record is created: the first answer from a person on a form, from the banner, an app, your server or an import. The event is sent whatever the answer was, so read data.status.

Payload

The payload fields, with these values:

Field in data Value
status GRANTED, PARTIAL or DENIED. PENDING for an email opt-in that is not yet confirmed.
withdrawnOn null

Example

JSON
{
  "id": "9a3d7c12-4b6e-4f0a-8c2d-1e5f7a9b3c40",
  "type": "consent.granted",
  "createdOn": "2026-09-20T08:41:10.305Z",
  "projectId": "c2a6f0de-51b3-4f0a-9d7e-8b1f3a6c4e90",
  "test": false,
  "data": {
    "consentId": "cns_3f1c9a7e2b8d4c6fa0e5d1b7c9f2a4e8",
    "status": "PARTIAL",
    "formId": "0b9c6f0e-6a55-4c1e-9d0a-2f6f0f4f7a11",
    "formVersion": 3,
    "formContentHash": "9b1f04c7…",
    "decisions": [
      {
        "purposeKey": "course-updates-by-email",
        "purposeName": "Course updates by email",
        "category": "MARKETING",
        "granted": true
      },
      {
        "purposeKey": "class-reminders-by-sms",
        "purposeName": "Class reminders by SMS",
        "category": "MARKETING",
        "granted": false
      }
    ],
    "countryCode": "IN",
    "subdivisionCode": null,
    "lawCode": "DPDP",
    "collectedOn": "2026-09-20T08:41:10.000Z",
    "expiresOn": "2027-09-20T08:41:10.000Z",
    "withdrawnOn": null,
    "proofHash": "5d1f6e0a…",
    "test": false,
    "subject": {
      "type": "USER_ID",
      "fingerprint": "8c41…",
      "reference": null
    }
  }
}

Sent when

An existing record gets a new answer: a change in the preference centre, a second POST /consent for the same person and form, a PATCH, or an email opt-in being confirmed. Linking identifiers alone sends no event.

Payload

The payload fields, with these values:

Field in data Value
status GRANTED, PARTIAL or DENIED, worked out from the new answers. PENDING when an email opt-in is started again before it is confirmed.
collectedOn, expiresOn Counted again from the change.

Example

JSON
{
  "id": "b1e84f07-2c3a-4d59-9e61-7f0a2b4c6d81",
  "type": "consent.updated",
  "createdOn": "2026-09-22T14:05:31.118Z",
  "projectId": "c2a6f0de-51b3-4f0a-9d7e-8b1f3a6c4e90",
  "test": false,
  "data": {
    "consentId": "cns_3f1c9a7e2b8d4c6fa0e5d1b7c9f2a4e8",
    "status": "GRANTED",
    "formId": "0b9c6f0e-6a55-4c1e-9d0a-2f6f0f4f7a11",
    "formVersion": 3,
    "formContentHash": "9b1f04c7…",
    "decisions": [
      {
        "purposeKey": "course-updates-by-email",
        "purposeName": "Course updates by email",
        "category": "MARKETING",
        "granted": true
      },
      {
        "purposeKey": "class-reminders-by-sms",
        "purposeName": "Class reminders by SMS",
        "category": "MARKETING",
        "granted": true
      }
    ],
    "countryCode": "IN",
    "subdivisionCode": null,
    "lawCode": "DPDP",
    "collectedOn": "2026-09-22T14:05:31.000Z",
    "expiresOn": "2027-09-22T14:05:31.000Z",
    "withdrawnOn": null,
    "proofHash": "c07a91d3…",
    "test": false,
    "subject": {
      "type": "USER_ID",
      "fingerprint": "8c41…",
      "reference": null
    }
  }
}

Sent when

A record becomes WITHDRAWN. The cause can be a withdraw call for the record or the person, the banner, an unsubscribe link or the Your consents page. It can also be the console, a rights request your team carried out, or a notice campaign link. Erasing a record that was still in force sends it too. Withdrawing a record that is already withdrawn sends nothing.

Payload

The payload fields, with these values:

Field in data Value
status WITHDRAWN
decisions[].granted false for every optional purpose.
withdrawnOn The time of the withdrawal.
subject When the withdrawal is part of an erasure, taken immediately before the erasure. The fingerprint and the reference are still there.
processors A STOP for each Data Processor the person had allowed. [] when the withdrawal is part of an erasure: the subject.erased event carries the ERASE tasks.

Example

JSON
{
  "id": "4f1c2b9e-7d0a-4c55-9a51-2d8e6f0b3a17",
  "type": "consent.withdrawn",
  "createdOn": "2026-09-24T10:12:03.412Z",
  "projectId": "c2a6f0de-51b3-4f0a-9d7e-8b1f3a6c4e90",
  "test": false,
  "data": {
    "consentId": "cns_3f1c9a7e2b8d4c6fa0e5d1b7c9f2a4e8",
    "status": "WITHDRAWN",
    "formId": "0b9c6f0e-6a55-4c1e-9d0a-2f6f0f4f7a11",
    "formVersion": 3,
    "formContentHash": "9b1f04c7…",
    "decisions": [
      {
        "purposeKey": "course-updates-by-email",
        "purposeName": "Course updates by email",
        "category": "MARKETING",
        "granted": false
      },
      {
        "purposeKey": "class-reminders-by-sms",
        "purposeName": "Class reminders by SMS",
        "category": "MARKETING",
        "granted": false
      }
    ],
    "countryCode": "IN",
    "subdivisionCode": null,
    "lawCode": "DPDP",
    "collectedOn": "2026-09-22T14:05:31.000Z",
    "expiresOn": "2027-09-22T14:05:31.000Z",
    "withdrawnOn": "2026-09-24T10:12:03.000Z",
    "proofHash": "5d1f6e0a…",
    "test": false,
    "subject": {
      "type": "USER_ID",
      "fingerprint": "8c41…",
      "reference": null
    },
    "processors": [
      {
        "taskId": "2b9e4f61-0c3d-4a7e-8f15-6d2c9b0a7e34",
        "key": "nilgiri-mailers",
        "name": "Nilgiri Mailers",
        "action": "STOP",
        "purposes": ["course-updates-by-email"],
        "dueOn": "2026-10-01T10:12:03.412Z",
        "retainLogsUntil": null
      }
    ]
  }
}

Sent when

A record reaches expiresOn while it is still GRANTED, PARTIAL or PENDING. The check runs every hour. Treat the event like a withdrawal, and ask again if you still need the consent.

Payload

The payload fields, with these values:

Field in data Value
status EXPIRED
decisions[].granted false for every optional purpose.
expiresOn The time that has passed.

Example

JSON
{
  "id": "e2c5a8f1-6d7b-4a39-b0c4-3f8e1d2a5b96",
  "type": "consent.expired",
  "createdOn": "2027-09-22T15:00:04.871Z",
  "projectId": "c2a6f0de-51b3-4f0a-9d7e-8b1f3a6c4e90",
  "test": false,
  "data": {
    "consentId": "cns_3f1c9a7e2b8d4c6fa0e5d1b7c9f2a4e8",
    "status": "EXPIRED",
    "formId": "0b9c6f0e-6a55-4c1e-9d0a-2f6f0f4f7a11",
    "formVersion": 3,
    "formContentHash": "9b1f04c7…",
    "decisions": [
      {
        "purposeKey": "course-updates-by-email",
        "purposeName": "Course updates by email",
        "category": "MARKETING",
        "granted": false
      },
      {
        "purposeKey": "class-reminders-by-sms",
        "purposeName": "Class reminders by SMS",
        "category": "MARKETING",
        "granted": false
      }
    ],
    "countryCode": "IN",
    "subdivisionCode": null,
    "lawCode": "DPDP",
    "collectedOn": "2026-09-22T14:05:31.000Z",
    "expiresOn": "2027-09-22T14:05:31.000Z",
    "withdrawnOn": null,
    "proofHash": "71be40c9…",
    "test": false,
    "subject": {
      "type": "USER_ID",
      "fingerprint": "8c41…",
      "reference": null
    }
  }
}

Sent when

An import from a file in the console finishes or is stopped: one event for the whole file. A check that was never written sends none. No event is sent for each record the import writes.

Payload

Field in data Type Description
importId UUID The import run. Open its records in the console at Records with Show records under Past imports.
status string COMPLETED, or STOPPED when it was stopped or left idle for 30 minutes.
complete boolean true when every row of the file was handled.
test boolean true for an import of test records.
propertyId, formId, formKey, formVersion string, integer The form version the records were made against.
basis, noticeReference, noticeSha256 string or null What the import stated for every row.
fileSha256 string The SHA-256 of the file, as the browser reported it.
rowsInFile integer Rows in the file.
created, updated, skipped, failed integer Row counts.
reasons object Each skip or failure reason with its count. See Consent import file.
startedOn, finishedOn time When the import started and ended.

The event carries no file name, no person and no identifier.

Example

JSON
{
  "id": "0c7e1a94-3b2d-4f68-a5e1-9d4c2b7f0a36",
  "type": "consent.imported",
  "createdOn": "2026-11-02T06:22:48.511Z",
  "projectId": "c2a6f0de-51b3-4f0a-9d7e-8b1f3a6c4e90",
  "test": false,
  "data": {
    "importId": "6f0d8a52-2c7e-4b8e-9f4d-0c1a7e3b5d21",
    "status": "COMPLETED",
    "complete": true,
    "test": false,
    "propertyId": "8c2a5e10-3f4b-4c6d-9e7f-1a2b3c4d5e6f",
    "formId": "0b9c6f0e-6a55-4c1e-9d0a-2f6f0f4f7a11",
    "formKey": "kaveri-account-opening",
    "formVersion": 1,
    "basis": "PRE_COMMENCEMENT",
    "noticeReference": "AOF-2019 rev 3",
    "noticeSha256": null,
    "fileSha256": "9c1e5b2f…",
    "rowsInFile": 48210,
    "created": 47002,
    "updated": 830,
    "skipped": 312,
    "failed": 66,
    "reasons": {
      "CONSENT_NEWER_ON_RECORD": 280,
      "CONSENT_WITHDRAWN_ON_RECORD": 30,
      "CONSENT_ERASED_ON_RECORD": 2,
      "PHONE_NOT_E164": 41,
      "UNREADABLE_DATE": 25
    },
    "startedOn": "2026-11-02T05:31:44.000Z",
    "finishedOn": "2026-11-02T06:22:48.000Z"
  }
}

Processor instructions#

processors lists one instruction for each partner you registered as a Data Processor that must stop or erase. Pass each one to the processor and report back. See Pass instructions to processors.

Field Type Description
taskId UUID The task. Report against it.
key, name string The processor's partner key and name.
action string STOP, or ERASE in erasure events.
purposes array The purposes concerned.
dueOn time When the task is due, by the days in the register.
retainLogsUntil time or null On an ERASE: until when the processor may keep processing logs.

consent.granted carries no processors. A person known only by a cookie or session id gets none.

↑↓ to move, Enter to open