/api/v1/passports/{id}Delete a passport permanently
**Permanent and irreversible** — the passport row plus every cascaded dependent is removed from the database. Cascade includes AI extractions, agent-session state, supplier requests linked to this passport alone, scan + service events, and any uploaded documents whose only reference was this passport (documents shared across other passports/products stay). R2 storage under the passport's folder is swept too.
**Only never-published passports are eligible.** A passport with status `draft` or `in_review` and `publishedAt: null` can be deleted; everything else returns `409 Conflict` with a `reason` field naming the policy. This is deliberate: the compliance moat protecting printed QRs in the wild is preserved — a passport that has ever resolved publicly cannot be quietly destroyed.
**Paid-plan feature.** The endpoint returns `403 Forbidden` with `reason` on Free plans; use `POST /api/v1/passports/{id}/archive` instead — archive keeps the row in your audit trail and works on every plan.
Counts as one v1 write. Honours `Idempotency-Key`. No webhook fires (the audit `billingEvents` entry is the trail).
Path parameters
- idrequired
ObjectId
Passport ID.
Headers
- Authorizationrequired
string
`Bearer <api-key>`.
- Idempotency-Key
string
UUID v4.
Request
curl -sS -X DELETE \
https://app.tracepass.eu/api/v1/passports/6650b2c3d4e5f6a7b8c9d0e1 \
-H "Authorization: Bearer tp_REDACTED_xxxxxxxxxxxx"Response
{
"message": "Passport permanently deleted",
"summary": {
"passportId": "6650b2c3d4e5f6a7b8c9d0e1",
"serialNumber": "SN-001",
"gtin": "09506000134369",
"deletedCounts": {
"extractions": 3,
"agentSessions": 1,
"serviceEvents": 0,
"scanEvents": 0,
"ownershipTransfers": 0,
"supplierRequestRefsRemoved": 0,
"supplierRequestsDeleted": 0,
"epcisEventRefsRemoved": 0,
"epcisEventsDeleted": 0,
"documentRefsRemoved": 1,
"documentsDeleted": 1,
"r2ObjectsDeleted": 4,
"documentR2ObjectsDeleted": 1
},
"dppsActiveDelta": -1
}
}