Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Account deletion

A player can delete their own account from inside the game. The Apple App Store and Google Play expect apps that allow account creation to also offer in-app account deletion; this endpoint meets that expectation. Deletion is irreversible: neither the player nor an operator can bring a deleted account back.

Request

First get a CSRF token (Sessions and CSRF); then:

POST /v1/auth/account/delete
content-type: application/json
x-crx-env: <environment-id>
x-csrf-token: <csrf-token>

{ "confirm": "delete_my_account" }

The player id does not come from the body; it comes from the session. confirm is an explicit confirmation; a missing or different value is rejected with 422. A successful request returns 204 and clears the session and refresh cookies.

Note

This endpoint works only with a player session. You cannot delete a player through it with a server key (Bearer crx_…); you get 401. To delete a player as an operator, use the player page in the panel.

Recent sign-in rule

  • A guest account is deleted directly.
  • For an account with a linked identity (email/password, Google or another provider) the session’s sign-in moment must be at most 10 minutes ago. Otherwise the server deletes nothing and answers 403 with this body:
{ "code": "recent_sign_in_required" }

The app then has the player sign in again and repeats the request. The time is counted from the sign-in itself, not from a session refresh; even a player who has been in an open session all day must sign in again. If the sign-in moment cannot be proven, the server stays on the safe side and gives the same 403.

What is erased and what stays?

Deletion runs in a single database transaction; either everything happens or nothing does:

DataResult
SessionsAll are revoked; open realtime connections close.
Linked identities (email/password, Google…)Detached; the password and provider tokens are erased. The same email or the same Google account can later start as a new player.
Player data (player data blobs)Erased.
Player rowNot removed; it is anonymized (Deleted player, email and image cleared) and marked deleted.
Audit eventsUnchanged. The deletion is added as a new player_self_deleted event; the event carries no email or provider id.
Wallet ledger and plugin recordsUnchanged (append-only); because the player row is anonymous, the person cannot be resolved from these records.

Warning

Free-form personal data that plugins keep in their own tables is not erased by this endpoint. If your plugin stores personal data, you must wire up your own deletion flow separately.

Errors and limits

StatusMeaning
204The account was deleted.
401No/invalid session, the player is not active (banned or already deleted), or a server key was presented. A banned player cannot escape the ban through deletion.
403 without a bodyCSRF rejection.
403 recent_sign_in_requiredA fresh sign-in is required; nothing was deleted.
422confirm is missing or is not delete_my_account.
429The limit of 5 attempts per hour per player was exceeded.

SDK

In the TypeScript SDK:

try {
  await client.session.deleteAccount({ confirm: "delete_my_account" });
  // the state is now signedOut; take the player to the sign-in screen.
} catch (error) {
  if (error instanceof CrxError && error.reason === "recent_sign_in_required") {
    // have the player sign in again, then repeat the call
  } else {
    throw error;
  }
}

On success the SDK ends the session as a password change does and returns { status: "signedOut" }. On recent_sign_in_required the session and the account are unchanged. If the response is lost after the request was sent, the outcome is uncertain (UnknownOutcome): the SDK does not retry blindly, and the app’s restore() call decides the real state. The Unity SDK does not have this method yet.

App-store privacy note

Put an in-app “Delete my account” button where players can reach it, ask for an explicit confirmation before the click is acted on, and wire the button to the deleteAccount call. State in your privacy text which data remains after the account is deleted (the wallet ledger stays, anonymized). The deleted account’s email and provider id are freed; if the same person registers again they start from scratch.