Skip to content
← BlogDeveloperAnalysis

DELETE /v1/people/:id vs. people:erase: two buttons that look similar and aren't

DELETE archives a contact and is reversible. people:erase is a separate, audited GDPR flow that destroys PII forever. Conflating the two is a real compliance bug.

By Gabriel Lara, Developer Relations, Norbelys

Founder-reviewed ·How we research and correct articles

It’s a natural assumption: a user asks you to “delete my data under GDPR,” so you call DELETE /v1/people/:id, mark the ticket resolved, and move on. That assumption is wrong on the Norbelys API, and it’s wrong in a way that matters — because the two operations behave completely differently, and shipping the wrong one is a compliance gap you won’t notice until an audit or a data subject access request surfaces it.

Two operations, same-looking name, opposite guarantees

DELETE /v1/people/:idPOST /v1/people/:id:erase
What it doesSoft-archives the rowScrubs PII permanently
Reversible?
Data after the callRow intact, dateArchived setEmail/name/custom fields destroyed
Shows up in default lists?No (excluded by default)No — the row is gone as PII
Analytics historyFully intactAnonymized counts only
Suppression effectNone automaticallyAddress hash added to suppression
Audited as a GDPR action?
Right operation for a GDPR erasure request?

DELETE is soft-archive — reversible, ordinary, everyday

DELETE /v1/people/:id follows the same rule every DELETE in the API follows: it never hard-deletes. It sets dateArchived on the row and excludes it from default list results (pass ?includeArchived=true to see it again). Nothing about the underlying data is destroyed — the row, its history, and its place in past analytics are all still there, just marked archived. This is the routine “remove this contact from my working list” operation, and it’s designed to be reversible because most of the time, that’s exactly what people want: undo room for a mistake, not permanent destruction.

DELETE /v1/people/con_9f2k...
  → 200 { id: "con_9f2k...", dateArchived: "2026-07-17T09:12:00Z", ... }

This is true of every resource in the API, not just people — archiving a sender, a program, or a domain works the same way. It’s one general rule (§13 of the API surface: “DELETE is always a soft archive”), not a per-resource special case.

people:erase is a different button entirely

The right to erasure under GDPR is not “remove from my list” — it’s “make this person’s personal data gone.” That’s a fundamentally different operation, and Norbelys models it as one: a separate, explicit, audited action, never triggered by an ordinary DELETE.

POST /v1/people/con_9f2k...:erase
  → 200 { id: "con_9f2k...", erasedAt: "2026-07-17T09:14:02Z" }
erase-a-person.sh
$ curl -s -X POST https://api.norbelys.com/v1/people/con_9f2k...:erase \$ -H "Authorization: Bearer $NORBELYS_API_KEY" \$ -H "Idempotency-Key: erase-con_9f2k-2026-07-17"{ "id": "con_9f2k...", "erasedAt": "2026-07-17T09:14:02Z" }

What actually happens when this call runs:

  • PII is scrubbed from the contact row — email, name, and any custom fields are destroyed, not just hidden behind a flag.
  • Anonymized event counts survive. The person’s past opens, clicks and replies remain countable in aggregate analytics — so a campaign’s historical funnel numbers don’t silently change — but nothing in that surviving data identifies who they were.
  • A hash of the address is added to suppression. This is the detail that’s easy to miss: erasure doesn’t just forget the person, it makes sure they can’t accidentally be re-imported and contacted again later from a stale CSV or CRM sync via a future bulk import job. The hash matches on re-import without storing the plaintext address anywhere.
  • It’s audited. Unlike a DELETE, this action is logged as the compliance-relevant event it is — because if a regulator or the data subject later asks “was this actually erased, and when,” you need a real answer, not a guess based on dateArchived.

This is the one operation in the entire API that truly destroys data. Every other write in the system is deliberately non-destructive — versioned, soft-deleted, archived — specifically so that erase can be the sole, unambiguous exception.

Why this is a compliance bug waiting to happen, not just an API nuance

If your integration’s “handle a deletion request” code path calls DELETE because that’s the verb that sounds right, you’ve built a system that looks like it’s honoring erasure requests — the contact disappears from your dashboard, the ticket closes, everyone moves on — while the actual PII sits untouched in Postgres, fully recoverable, unaudited as an erasure. That gap is invisible until someone checks, which in GDPR terms is usually during an audit or a follow-up subject access request, exactly the worst time to discover it.

The fix is definitional, not technical: treat “a user wants their contact record removed from my active list” and “a data subject has exercised their right to erasure” as two different intents from the start of your workflow, each mapped to its own endpoint. If your product surfaces both actions in your own audience management tooling, label them differently too — “Remove contact” and “Erase personal data (GDPR)” are not the same button, and neither should look like it might be.

For the general DELETE-vs-action pattern across every resource in the API, see the developer portal and the note on typed error handling for how a misapplied action typically surfaces as a 403 rather than silently succeeding when your credential lacks the erase permission. If you’re paginating through people to find records due for erasure in bulk, the same cursor pagination pattern applies here as everywhere else in the API.

Erase vs. delete FAQ

Can I undo a people:erase call?

No. Unlike DELETE, erasure is deliberately irreversible — PII is scrubbed from the row, not flagged. That's the entire point of it being a separate, explicit action instead of a DELETE variant.

Does erasing a contact delete their historical campaign performance?

No — anonymized event counts stay in the analytics store so aggregate analytics (open rates, funnel counts) remain accurate. What's destroyed is anything that identifies who the events belonged to.

If I erase a contact, can they end up back on a mailing list from a future CSV import?

No — erasure hashes their address into suppression, so a later import of the same address is caught and skipped rather than silently re-creating an active, contactable record.

Is people:erase the same action as an unsubscribe?

No. Unsubscribing stops future sends and is one of several things that can add an address to suppression, but it doesn't touch the stored PII. Erasure is specifically the GDPR right-to-erasure operation and always scrubs the underlying data.