HelloJohn / docs
Users

Delete Users

Permanently delete users and handle data retention considerations in HelloJohn.

Delete Users

Deleting a user permanently removes their account, sessions, MFA factors, and organization memberships. This action is irreversible.

Delete a User

curl -X DELETE "https://api.hellojohn.dev/v1/users/usr_01HABCDEF123456" \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321"

Response: 204 No Content

What Is Deleted

DataBehavior
User accountPermanently deleted
Active sessionsImmediately revoked
MFA factorsPermanently deleted
OAuth connectionsPermanently deleted
Organization membershipsRemoved from all orgs
Audit log entriesRetained (for compliance)
Webhook events referencing this userRetained

What Is NOT Automatically Deleted

Data in your own database that references the user ID is not touched by HelloJohn. You should clean up your own data before or after deleting the user.


Soft Delete vs Hard Delete

By default, DELETE /v1/users/:id is a hard delete — data is gone permanently.

Pattern: Soft Delete via Metadata

If you need to retain the record but prevent sign-in, disable the user instead:

curl -X POST "https://api.hellojohn.dev/v1/users/usr_01HABCDEF123456/disable" \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "X-Tenant-ID: tnt_01HABCDEF654321" \
  -H "Content-Type: application/json" \
  -d '{"revoke_sessions": true}'

Then mark them as deleted in your own database. Hard-delete later after a retention period.


GDPR / Right to Erasure

When a user exercises their right to erasure, delete their account and any data you store:

async function eraseUser(userId: string) {
  // 1. Delete from your own database
  await db.deleteUserData(userId);

  // 2. Delete from HelloJohn
  await hj.users.delete(userId);

  // 3. Log the erasure for compliance
  await auditLog.record({ action: "user.erased", userId });
}

The audit log retains entries referencing the deleted user ID. These entries are anonymized — the user record is gone but the action history remains for compliance.


Confirming Deletion

After deletion, the user ID no longer exists. Requests to GET /v1/users/:id return 404:

{
  "error": "resource_not_found",
  "message": "User not found."
}

Deleting Your Own Account (Self-Service)

To allow users to delete their own accounts:

import { useUser } from "@hellojohn/react";

function DeleteAccount() {
  const { user, deleteAccount } = useUser();
  const [confirmed, setConfirmed] = useState(false);

  const handleDelete = async () => {
    if (!confirmed) return;

    await deleteAccount();
    window.location.href = "/goodbye";
  };

  return (
    <div>
      <p>This will permanently delete your account and all data.</p>
      <label>
        <input
          type="checkbox"
          onChange={(e) => setConfirmed(e.target.checked)}
        />
        I understand this cannot be undone
      </label>
      <button onClick={handleDelete} disabled={!confirmed}>
        Delete my account
      </button>
    </div>
  );
}

Bulk Delete

Delete multiple users in one operation (admin only):

const userIds = ["usr_01HABCDEF123456", "usr_01HABCDEF789012"];

await Promise.all(userIds.map((id) => hj.users.delete(id)));

For large-scale deletions, process in batches to avoid rate limits:

async function bulkDelete(userIds: string[], batchSize = 20) {
  for (let i = 0; i < userIds.length; i += batchSize) {
    const batch = userIds.slice(i, i + batchSize);
    await Promise.all(batch.map((id) => hj.users.delete(id)));

    // Respect rate limits between batches
    await new Promise((r) => setTimeout(r, 1000));
  }
}

On this page