Contact Erasure
Preview and permanently erase a contact for a right-to-erasure request
Erasure is not an update - it destroys a contact and the data attached to it, permanently, to satisfy a right-to-erasure request.
It is gated twice over:
| Requirement | Detail |
|---|---|
| Scope | CONTACTS_ERASE - deliberately separate from CONTACTS_MANAGE. |
| Role | OWNER, ADMIN or EDITOR. A key is held to the same role bar as a person. |
| Org | Org-scoped. A caller can only erase contacts in the org it is acting on. |
previewErase
previewErase(input: EraseInput!): ErasePreviewType!CONTACTS_ERASE
A dry run. Changes nothing, and tells you exactly what the real call would destroy.
Arguments - input: EraseInput!
| Field | Type | Required | Description |
|---|---|---|---|
contactId | ID! | Yes | The contact to erase. |
organisationId | ID! | Yes | The org it belongs to. |
reason | String | No | Why - recorded for your own audit trail. |
Returns ErasePreviewType!
| Field | Type | Description |
|---|---|---|
contactId | ID! | The contact the preview is for. |
willErase | [EraseCount!]! | What would be destroyed, as { collection, count } pairs. |
warnings | [String!]! | Anything you should see before proceeding. Empty when there is nothing to flag. |
Example
query Preview {
previewErase(input: {
contactId: "6804f4d5a6f9f35f6e66f1c9"
organisationId: "6716b2f0a1c34d0012ab89ef"
}) {
contactId
willErase { collection count }
warnings
}
}{
"data": {
"previewErase": {
"contactId": "6804f4d5a6f9f35f6e66f1c9",
"willErase": [
{ "collection": "messages", "count": 412 },
{ "collection": "chats", "count": 3 },
{ "collection": "fieldValues", "count": 11 }
],
"warnings": []
}
}
}Always call this first and show the result to a human. It is the only chance to notice that the wrong contact was selected, or that a merged contact carries far more history than expected.
eraseContact
eraseContact(input: EraseInput!): EraseResultType!CONTACTS_ERASE
Performs the erasure. Same input as the preview.
Returns EraseResultType!
| Field | Type | Description |
|---|---|---|
contactId | ID! | The contact that was erased. |
erasedAt | DateTime! | When it happened. |
affectedCounts | [EraseCount!]! | What was actually destroyed. |
erasureLogId | ID! | The erasure record - keep it as your proof the request was fulfilled. |
Example
mutation Erase {
eraseContact(input: {
contactId: "6804f4d5a6f9f35f6e66f1c9"
organisationId: "6716b2f0a1c34d0012ab89ef"
reason: "Subject access request #4471"
}) {
erasedAt
erasureLogId
affectedCounts { collection count }
}
}This is irreversible. There is no undo, and no equivalent of a merge split to put the data back. Compare affectedCounts against the preview's willErase - a mismatch means something changed between the two calls.
Store the erasureLogId and your reason on your side. The erasure record is what lets you answer "prove you deleted it" later, and reason is the only field carrying your own ticket reference into it.
A Safe Erase Flow
previewErase- readwillEraseandwarnings.- Put the counts in front of a human and get an explicit confirmation.
eraseContactwith the samecontactIdand areasonnaming your ticket.- Record
erasureLogIdanderasedAt.
Do not skip step 2 in an automated pipeline. An erasure triggered by a bad contact ID cannot be walked back.
Related
- Contacts - read and write contacts.
- Contact Webhooks - the erase event.
- Erase a Contact - what erasure removes and when to use it.