TracePass
Passports

Mark a passport for deletion

Step one of two. Deleting a passport takes two steps: mark it for deletion here, then call DELETE /api/v1/passports/{id} (a never-published draft or in_review passport can be deleted directly). The delete is a soft delete: nothing is erased, but the passport disappears from the API and from every public surface. Scanning its QR code shows a page saying the passport has ended, and its machine-readable formats answer 410 Gone.

POST/api/v1/passports/{id}/mark-for-deletion
Download OpenAPI 3.1
POST/api/v1/passports/{id}/mark-for-deletion

Mark a passport for deletion

Step one of two. Deleting a passport takes two steps: mark it for deletion here, then call DELETE /api/v1/passports/{id} (a never-published draft or in_review passport can be deleted directly). The delete is a soft delete: nothing is erased, but the passport disappears from the API and from every public surface. Scanning its QR code shows a page saying the passport has ended, and its machine-readable formats answer 410 Gone.

A marked passport can no longer be edited, and marking a published passport frees its plan slot. A passport in any status except archived can be marked; marking it a second time answers 409 already_marked_for_deletion. Fires the passport.marked_for_deletion webhook.

Battery passports need a reason. Under the Battery Regulation a battery passport ends only once the battery has been recycled (Art. 77(8)), so the request names why this one ends: recycled, never_placed (never placed on the market) or duplicate_or_error. Without one, a battery passport answers 400 reason_required. For other categories reason is optional; when given, it must be one of the same three values.

Refused while a newer passport links to it. While a newer second-life battery passport in your account names this one as its predecessor, the mark answers 409 has_live_successor; delete the newer passport first.

Deletion through the API needs a paid plan: on Free the mark answers 403 deletion_not_on_plan. Counts as one v1 write. Honours Idempotency-Key. POST /api/v1/passports/by-serial/{serial}/mark-for-deletion is the by-serial alternate (it accepts the ?gtin= disambiguator).

never_placed is refused on a placed passport. A passport registered as placed on the market answers 409 reason_contradicts_placement for that reason. recycled and duplicate_or_error stay available.

Path parameters

  • idrequired

    string (24 hex chars)

    Passport ID.

Headers

  • Authorizationrequired

    string

    Bearer <token> — either a tp_ API key (Developer → API Keys; simplest, for server-to-server) or an OAuth 2.0 access token (Developer → OAuth Apps; for user-authorized apps, scoped + revocable). The Authentication page has the full OAuth flow and scope list.

    e.g. Bearer tp_REDACTED_xxxxxxxxxxxx

  • Idempotency-Key

    string

    UUID v4.

Body fields

  • reason

    enum

    recycled, never_placed or duplicate_or_error. Required for battery passports, optional for other categories.

    e.g. recycled

Request

curl -sS -X POST \
  https://app.tracepass.eu/api/v1/passports/6650b2c3d4e5f6a7b8c9d0e1/mark-for-deletion \
  -H "Authorization: Bearer tp_REDACTED_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4f9c2a7e-1b3d-4c5e-8f60-7a8b9c0d1e2f" \
  -d '{ "reason": "recycled" }'

Response

{
  "_id": "6650b2c3d4e5f6a7b8c9d0e1",
  "status": "marked_for_deletion",
  "markedForDeletionAt": "2026-11-01T10:00:00.000Z",
  "markedForDeletionReason": "recycled"
}