Troubleshooting: proof-of-deletion certificate errors on GET /compliance/dsar/erasure-requests/{id}/certificate
The certificate endpoint issues the signed proof-of-deletion
certificate for a completed Article-17 erasure: the receipt a data
subject or supervisory authority accepts as evidence that the right
to erasure was fulfilled. This page covers every response the
endpoint can return, how to read a 200 that looks wrong, how to
verify the certificate you hold, and what to do while the erasure is
still in flight.
The normative reference is
Data Subject Access Requests; the step-by-step
operational sequence lives in the
Proof-of-Deletion Certificate Runbook.
What the certificate is, and who asks for it
Article 17 obliges you to erase personal data when the right applies; Article 12 obliges you to demonstrate to the data subject that you did. The certificate is that demonstration in portable form: a dated, signed, per-subsystem statement of what was purged, when, under which request, and against which tamper-evident audit anchor. A data subject asks for it to close their request; a supervisory authority or auditor asks for it as GDPR Art. 17 evidence in an investigation or proceeding. Orbit signs the artifact’s integrity. Whether the certificate discharges your legal obligation in a given proceeding is a determination for your counsel, consistent with Orbit’s tenant-owned compliance posture.The endpoint, end to end
GET /compliance/dsar/erasure-requests/{id}/certificate requires an
owner or admin credential. On a 200 it derives the certificate on
demand from the immutable executed request row and its audit-chain
anchor, self-signs it with a detached HMAC-SHA256 tag, and returns
{ "certificate": ..., "signature": ... }. Nothing is persisted:
re-issuing at any time reproduces the same certificate_id for the
same execution.
The failing states, in the order the endpoint checks them:
- 401
UNAUTHORIZED— no valid credential on the request. Attach your API key and retry. - 403
INSUFFICIENT_PERMISSIONS— the credential is valid but its role is below owner/admin; the message readsThis action requires one of: owner, admin. Switch to an owner- or admin-scoped credential. This is a permissions posture, not a defect. - 404
NOT_FOUND— no erasure request with this id exists in your tenant. Certificates are tenant-scoped: a request that belongs to another organization is indistinguishable from one that never existed. Re-copy the id fromGET /compliance/dsar/erasure-requests. - 409
ERASURE_NOT_EXECUTED— the request exists but is notexecuted. The message names the live status (pending,executing,cancelled, orfailed). Only a completed erasure can be certified; work the grid below.
pending → executing → executed, with terminal
branches cancelled and failed. The executor ticks every five
minutes; once the cooling-off window lapses, a healthy erasure moves
from pending to executed in minutes, not hours.
Error grid
A 200 with an unexpected status-shaped field
The certificate carries no lifecycle status field. A 200 means the
backing row was executed at read time, and the fields that read as
surprises are honest flags, not failures:
records_erased.by_resourceisnullfor a subsystem whose table does not exist on your tenant: nothing existed there to purge. A number, including 0, is a confirmed count.records_erased.totalisnullwhen every purge ran but no count could be confirmed. It does not mean nothing was deleted.destination_propagation.total: 0is a signed, honest “no external destinations were notified” (internal-only erasure), not a missing section.destination_propagation.failedorskippedentries mean a downstream destination rejected or was not configured for the fan-out. Re-run propagation, then issue again: the re-issue keeps the samecertificate_idand folds the updated trail under a freshissued_atand signature.attempt_countabove 1 means an earlier attempt hit a transient fault and the executor retried. The committed result is still all-or-nothing.
erasure_request_id and data_subject_contact_id before trusting
the file you opened: certificates are derived per request, and a
stale id in your script is the usual cause of a “wrong” 200.
Verifying the certificate against the executed erasure
Two independent checks, in increasing order of strength: Audit-chain cross-reference (yours to run). The certificate’saudit_log_id names a row in your organization’s audit chain with
action gdpr.erasure_executed. Its resource_counts must equal
records_erased.by_resource, and its timestamp must equal
executed_at. Every issuance also appends a
compliance.dsar_erasure_certificate_issued row naming the
certificate_id, so your audit export shows who issued which
certificate and when. A certificate whose anchor is missing or
disagrees should be treated as altered or mis-cited. The
certificate_id itself is deterministic, derived from the request
id and executed_at, so re-issuing the same executed request always
yields the same id: the digest you filed stays comparable against
any later re-issue.
Signature recompute (held by the signing-key holder). The tag is
a self-signature by Devotel Orbit over the canonicalised body; the
recipe is published for transparency:
- Canonicalise the
certificateobject with RFC 8785 (JCS) style rules: object keys sorted ascending, no insignificant whitespace. - Compute HMAC-SHA256 over the string
orbit.dsar.erasure-certificate.v1.<canonical-json>. - Base64url-encode and compare with
signature.valueusing a timing-safe equality check.
orbit.dsar.erasure-certificate.v1) is mixed into every tag, and
this is the deterministic-build contract the certificate service
documents: the signed byte sequence depends only on the immutable
executed row, the audit anchor, and issued_at, never on read
timing or row and key order. A mismatched or malformed tag verifies
false; verification never fails open.
Reading subject-bound data while the request is pending
The certificate exists only after completion. While an erasure ispending or executing, the subject-bound data still exists, and
the path to read it is the Article-15 access export, not the
certificate:
GET /compliance/dsar/{id}/decryptedreturns the plaintext access bundle for a completed, unexpired access request, decrypted for the verified controller (owner or admin) and audit-logged.- It applies to access-class requests only. An Article-17 erasure
produces no access export and returns
409 DSAR_NOT_ACCESS_REQUEST: the two request types close different obligations and their artifacts do not substitute for each other. - If the pending request is a delete and you need to inspect what will be destroyed, read a completed access export for the same subject where one exists; otherwise wait for the erasure to finalize and present the certificate.
Your control, your posture
Issuing the certificate is a tenant-triggered control: Orbit makes the artifact available on every executed erasure, and you decide when to issue it, whom to hand it to, and how long it lives in your privacy register. The platform does not auto-issue, auto-publish, or auto-expire certificates on your behalf, and no regulator interaction is driven by Orbit. Whether a presented certificate discharges your obligation is your counsel’s determination, not a platform default.Worked example
Issue the certificate and keep the artifact verbatim:certificate + signature pair (the
runbook shows
the full body). If instead you receive:
executed, then
re-run the same call.
See also
- Data Subject Access Requests (DSAR) — the normative reference for intake, verification, erasure, and the certificate.
- Proof-of-Deletion Certificate Runbook — the operational sequence, including regulator presentation and retention of the certificate itself.
- Pending compliance and erasure gates — the send-side gates an in-flight erasure raises elsewhere.
- Error code reference — the full
envelope and where
ERASURE_NOT_EXECUTEDsits in the catalog.