> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nullpass.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Delete Account

> Permanently delete user account

## Endpoint

```
POST /api/auth/delete-account
```

## Overview

Permanently deletes the authenticated user's account. This action is irreversible and will:

* Delete all user data
* Cancel all Polar subscriptions
* Delete all sessions
* Delete all service entitlements
* Delete all audit logs (cascade delete)

## Request

<ParamField body="password" type="string" required>
  User password for verification
</ParamField>

<ParamField body="verificationCode" type="string">
  Required if 2FA is enabled. TOTP code from authenticator app.
</ParamField>

## Response

<ResponseField name="success" type="boolean">
  Always `true` on success
</ResponseField>

<ResponseField name="message" type="string">
  "Account deleted successfully"
</ResponseField>

## Implementation Details

### Code Reference

```17:110:nullpass_clean/src/app/api/auth/delete-account/route.ts theme={null}
export async function POST(request: NextRequest) {
  const corsResponse = handleCors(request)
  if (corsResponse) return corsResponse

  const blocked = await protectRoute(request, { requested: 2 })
  if (blocked) return blocked

  const auth = await requireAuth(request)
  if ('error' in auth) return auth.error

  try {
    const body = await request.json()
    const validated = deleteAccountSchema.parse(body)

    const user = await prisma.user.findUnique({
      where: { id: auth.userId },
      include: {
        serviceAccess: true,
      },
    })

    if (!user || !user.passwordHash) {
      return errorResponse('User not found', 404, request.headers.get('origin'))
    }

    const isValid = await bcrypt.compare(validated.password, user.passwordHash)
    if (!isValid) {
      logger.warn('Account deletion failed: Invalid password', auth.userId)
      return errorResponse('Invalid password', 401, request.headers.get('origin'))
    }

    if (user.twoFactorEnabled) {
      if (!validated.verificationCode) {
        return errorResponse('2FA verification code is required', 401, request.headers.get('origin'))
      }

      if (!user.twoFactorSecret) {
        return errorResponse('2FA is enabled but secret is missing', 500, request.headers.get('origin'))
      }

      const isValid2FA = speakeasy.totp.verify({
        secret: user.twoFactorSecret,
        encoding: 'base32',
        token: validated.verificationCode,
        window: 2,
      })

      if (!isValid2FA) {
        logger.warn('Account deletion failed: Invalid 2FA code', auth.userId)
        return errorResponse('Invalid 2FA verification code', 401, request.headers.get('origin'))
      }
    }

    for (const service of user.serviceAccess) {
      if (service.polarSubscriptionId && process.env.POLAR_ACCESS_TOKEN) {
        try {
          await fetch(`https://api.polar.sh/v1/subscriptions/${service.polarSubscriptionId}`, {
            method: 'DELETE',
            headers: {
              'Authorization': `Bearer ${process.env.POLAR_ACCESS_TOKEN}`,
              'Content-Type': 'application/json',
            },
          })
          logger.info(`Canceled Polar subscription: ${service.polarSubscriptionId}`, auth.userId)
        } catch (error) {
          logger.error('Failed to cancel Polar subscription:', error)
        }
      }
    }

    await createAuditLog(auth.userId, 'USER_DELETE', {
      email: user.email,
    })

    await prisma.user.delete({
      where: { id: auth.userId },
    })

    logger.info(`User account deleted: ${user.email}`, auth.userId)

    return jsonResponse(
      { success: true, message: 'Account deleted successfully' },
      200,
      request.headers.get('origin')
    )
  } catch (error: any) {
    if (error.name === 'ZodError') {
      logger.warn('Delete account validation error:', error.errors)
      return errorResponse(error.errors[0].message, 400, request.headers.get('origin'))
    }
    logger.error('Delete account error:', error)
    return errorResponse('Internal server error', 500, request.headers.get('origin'))
  }
}
```

## Status Codes

<ResponseField name="200" type="OK">
  Account deleted successfully
</ResponseField>

<ResponseField name="400" type="Bad Request">
  Validation error
</ResponseField>

<ResponseField name="401" type="Unauthorized">
  Invalid password or 2FA code
</ResponseField>

<ResponseField name="404" type="Not Found">
  User not found
</ResponseField>

## Example Request

```bash theme={null}
curl -X POST https://auth.nullpass.xyz/api/auth/delete-account \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "password": "yourpassword123",
    "verificationCode": "123456"
  }'
```

## Example Response

```json theme={null}
{
  "success": true,
  "message": "Account deleted successfully"
}
```

<Warning>
  **Irreversible Action:** Account deletion is permanent and cannot be undone. All user data, sessions, entitlements, and audit logs will be permanently deleted.
</Warning>

## Security Notes

* Requires password verification
* Requires 2FA code if 2FA is enabled
* All Polar subscriptions are canceled before deletion
* Cascade deletes remove all related data
* Final audit log entry is created before deletion

## Audit Events

* **USER\_DELETE**: Account deleted (created before deletion)
