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
| Data | Behavior |
|---|---|
| User account | Permanently deleted |
| Active sessions | Immediately revoked |
| MFA factors | Permanently deleted |
| OAuth connections | Permanently deleted |
| Organization memberships | Removed from all orgs |
| Audit log entries | Retained (for compliance) |
| Webhook events referencing this user | Retained |
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));
}
}