Account

Request account deletion (asynchronous finalize)

Fail-closed account-delete request. Flow:

  1. Confirmation gate (?confirm=<your-email>).
  2. Stale-pending outgoing transfers are swept (flipped to expired) so they don't show up as live blockers.
  3. The server re-runs /account/deletion-preview inside a BEGIN IMMEDIATE transaction. If any blocker remains → 409 with error.blockers/error.ownedAppCount and an ACCOUNT_HAS_* code (see below). The caller resolves blockers via the existing routes (DELETE /apps/:ref, share/revoke, transfer/cancel, etc.) and retries.
  4. On a clean account: users.status flips to deleting, deletion_requested_at + deletion_blocker_snapshot get stamped, API tokens are revoked server-side in the same transaction (so the caller's next request returns 401), the account.delete_requested audit row is written, and an account_delete job is enqueued. Response: 202 { status: 'deleting', finalizeJobId }.

The finalizer (account_delete job handler) runs AccountDeletionService.runFinalize() off the request path: re-validates blockers; cleans up github_installations, incoming shared_access rows keyed on the user's email, and pending incoming app_transfers to that email; throwing-inserts the account.deleted audit row; then DELETE FROMs the user row gated on status='deleting'. If a blocker reappears between the route's accept and the finalizer running, the finalizer flips status back to active and emits account.delete_aborted — the only path where users.status moves backward.

Error codes (409): ACCOUNT_HAS_APPS, ACCOUNT_HAS_COLLABORATORS, ACCOUNT_HAS_PENDING_INVITES, ACCOUNT_HAS_ACTIVE_PR_PREVIEWS, ACCOUNT_HAS_PENDING_TRANSFERS, ACCOUNT_HAS_DEPLOYS_IN_PROGRESS, ACCOUNT_HAS_ACTIVE_RESTORE. Plus ACCOUNT_DELETION_IN_PROGRESS (concurrent delete or status already flipped). Auth-middleware also raises ACCOUNT_DELETION_IN_PROGRESS (403) for any further request from a deleting user.

delete/account

Request

  • Base URL: https://api.percher.run
  • URL: https://api.percher.run/account
  • Auth: HTTP bearer

Query parameters

confirmstring required

Must match the authenticated user's email address.

acknowledge'forfeit-export-window'

Sunset override (only meaningful during read-only mode). Set to forfeit-export-window together with a valid single-use X-Sunset-Forfeit-Grant token header to delete during the sunset window. Both are required; the grant is minted only by the dashboard password-reauth flow, so CLI/MCP clients cannot supply it.

Response

Deletion accepted; finalization runs asynchronously. Body: { status: 'deleting', finalizeJobId: string }. API tokens are revoked server-side in the same transaction — the caller's next request will 401.

Changes

No recorded changes to this operation across all 1 revision of this API.