Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.pylonsync.com/llms.txt

Use this file to discover all available pages before exploring further.

DELETE /api/auth/account is the “user clicked Delete Account” button. It wipes the user’s auth state across every system Pylon owns — sessions, API keys, linked OAuth accounts, trusted-device records, and the User row itself — in one transactional sweep. App-owned tables that reference the user are not cascade-deleted (see below) — the host schema is the source of truth for what gets purged.

Endpoint

EndpointMethodAuthPurpose
/api/auth/accountDELETEsessionHard-delete the caller’s account

What gets wiped

Pylon performs the following in order:
  1. Revoke all sessions for the user. The caller’s current session is invalidated first so a slow user-row delete can’t leave a usable session.
  2. Revoke all API keys owned by the user (pk.* bearer tokens).
  3. Unlink all OAuth accounts — Google, GitHub, Apple, etc. credentials that were linked to this user.
  4. Revoke all trusted devices — the pylon_trusted_device records for this user.
  5. Delete the User row itself from the entity backing the auth user.
  6. Clear the session cookie on the response so the browser drops it.
  7. Audit log an AccountDelete event with counts of each category.
curl -X DELETE https://your-app/api/auth/account \
  -H 'Authorization: Bearer pylon_token'
Response:
{
  "deleted": true,
  "revoked_sessions": 3,
  "revoked_api_keys": 2,
  "unlinked_accounts": 1
}
Errors:
StatusCodeReason
401AUTH_REQUIREDNo session
403API_KEY_AUTH_FORBIDDENAPI-key auth can’t delete the account — real session required
400(storage error code)The User row delete failed (storage layer rejection)

App-owned tables don’t cascade

This is the most important caveat: Pylon does NOT cascade-delete your app’s tables. If the user has 47 Project rows pointing at their user_id, those rows survive the delete. The host schema is the source of truth — your app declares its own deletion semantics. The canonical pattern is a plugin hook that fires before the user row is wiped:
// crates/plugin/src/builtin/before_delete_user.ts (sketch)
import { plugin } from "@pylonsync/sdk";

export default plugin({
  name: "delete-user-data",
  on: { delete: { entity: "User" } },
  async beforeDelete(ctx, { id: userId }) {
    // Purge app tables that point at this user.
    const projects = await ctx.db.query("Project", { ownerId: userId });
    for (const p of projects) await ctx.db.delete("Project", p.id);
    // ...etc
  },
});
Or do it inside a mutation wrapper, or with a scheduled cleanup job after the delete. The framework leaves the policy decision to your app — some apps tombstone, some hard-delete, some anonymize the user_id and keep history.

Confirming first

Don’t expose this endpoint without a confirmation step in your UI. Pylon doesn’t require a password / TOTP re-prompt on the API itself — design the front-end flow to confirm:
// Dashboard flow:
// 1. User clicks "Delete account"
// 2. Modal asks them to type their email to confirm
// 3. Frontend calls /password/login to verify the password (or /totp/verify for 2FA)
// 4. Only then calls /api/auth/account DELETE
For high-stakes apps, gate the call on a fresh TOTP code or re-issued session within the last 5 minutes.

Audit trail

The AccountDelete audit event is written before the user row is deleted, so the event row survives. Read via /api/auth/audit — gives operators a record of which users self-deleted and when, with counts of what was wiped.

Where to go next

  • Sessions — revoke a single session without deleting the account
  • API keys — revoke a single key without deleting the account
  • GDPR export/api/admin/users/:id/export companion endpoint for data portability