Delete my account (right-to-erasure)
Me
Delete my account (right-to-erasure)
Soft-delete the user’s account after re-authentication. The 30-day hard-delete worker tombstones the row and removes PII.
DELETE
Delete my account (right-to-erasure)
Overview
The user’s GDPR right-to-erasure entry point. Calling this:- Re-authenticates the caller via
currentPassword— defense in depth, the bearer token alone is not enough. The same access token that just logged you in is not sufficient to delete your account. - Soft-deletes the user row (
users.deletedAt = now,users.deletedReason = 'user-request'). The row physically remains so foreign-key references (audit_logs, subscriptions, conversations) stay valid. - Cascades soft-delete to the only child table that has a
deletedAtfield today —current_homes. Other child rows are hard-deleted 30 days later by the daily gdpr-erasure worker. - Revokes all active refresh tokens for the user. Every device is logged out on the next API call.
- Writes a
user.deletedadmin-audit row (actorType: USER).
deletedAt is returned unchanged.
See GDPR data lifecycle for the full 30-day clock, tombstoning, and the carve-outs (audit_logs, subscriptions).
Authentication
Bearer <accessToken> (user scope) required. Re-auth via currentPassword in the body is also required — see request body.
Path parameters
None.Query parameters
None.Request body
| Field | Type | Required | Notes | Example |
|---|---|---|---|---|
currentPassword | string | yes | 1..256 chars. The user’s current password. Verified server-side with argon2 against the stored hash. Wrong password returns 401 ADMIN_INVALID_CREDENTIALS — note the reused user-side code from the auth surface. | correct-horse-battery-staple |
Example payload
Response — 200 OK
| Field | Type | Notes | Example |
|---|---|---|---|
deletedAt | string (ISO 8601) | Server clock at soft-delete. On re-calling for an already-deleted user, the existing deletedAt is returned (idempotent). | 2026-05-23T09:14:11.412Z |
Error responses
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_FAILED | currentPassword missing, empty, or longer than 256 chars. |
| 401 | UNAUTHENTICATED | Missing / malformed / expired token. |
| 401 | ADMIN_INVALID_CREDENTIALS | The supplied currentPassword did not match the stored hash. Code name is reused from the auth-shared module; the message is generic to avoid leaking which factor failed. |
Example error — 401 wrong password
Side effects
| Effect | Notes |
|---|---|
| User row | deletedAt = now, deletedReason = 'user-request'. Row physically remains for FK integrity. |
current_homes row | Soft-deleted (deletedAt = now). Best-effort — a cascade failure is logged and swallowed; the erasure worker will catch any leak. |
| Refresh tokens | All active tokens revoked. The user is logged out of every device. |
| Audit row | action: user.deleted, actorType: USER, actorId: <userId>. |
| 30-day hard-delete | The daily gdpr-erasure worker (04:00 UTC) picks up users with deletedAt < now-30d and tombstones the row + hard-deletes child data. |
What happens to my access token?
The current access token continues to work until it expires (15 min default) — the access-token check is stateless. However the refresh token is revoked, so when the access token expires the next refresh call returnsTOKEN_REVOKED and the client is forced into the logged-out state. New logins are blocked because the user row’s status and deletedAt are checked at login time.
Changed your mind? (reactivation)
The deletion is reversible for the full 30-day grace window. If the user logs in during that window,POST /auth/login returns 403 ACCOUNT_PENDING_DELETION (carrying meta.deletionScheduledAt) rather than a session — the cue to show a reactivation screen. The user then calls POST /auth/reactivate with their credentials to clear the pending deletion and get a fresh session. After day 30 the row is tombstoned and reactivation is no longer possible.
See also
- Reactivate account — undo this deletion within the 30-day window.
- Request GDPR data export — the right-of-access counterpart. Export it before you erase it.
- GDPR data lifecycle — the full 30-day clock, tombstoning, carve-outs (audit_logs, subscriptions, gdpr_export_jobs).
- Manual erasure trigger — the SUPER-only manual kick of the daily worker.
curl
Postman
Seedocs/postman/swappr.postman_collection.json → Me → Delete Account.