Users API
REST API endpoints for creating, reading, updating, and deleting users. Requires a secret key.
Users API
Manage users within a tenant. All endpoints require a secret key (sk_live_...) and X-Tenant-ID.
User Object
{
"id": "usr_01HABCDEF123456",
"email": "alice@example.com",
"username": "alice",
"name": "Alice Smith",
"phone": "+14155552671",
"avatar_url": "https://example.com/avatar.png",
"email_verified": true,
"phone_verified": false,
"role": "member",
"status": "active",
"mfa_enabled": true,
"public_metadata": { "plan": "pro" },
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"last_sign_in_at": "2024-01-20T08:15:00Z"
}GET /v1/users
List all users in the tenant.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
limit | integer | Results per page (default: 20, max: 100) |
cursor | string | Pagination cursor |
email | string | Filter by exact email |
q | string | Search by name, email, or username |
status | string | active, disabled, banned |
role | string | Filter by role |
sort | string | created_at, last_sign_in_at, email |
order | string | asc or desc |
curl "https://api.hellojohn.dev/v1/users?limit=50&status=active" \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321"Response:
{
"data": [
{ "id": "usr_01HABCDEF123456", "email": "alice@example.com", ... }
],
"pagination": {
"total": 1482,
"limit": 50,
"has_more": true,
"next_cursor": "cur_01HABCDEF123456"
}
}POST /v1/users
Create a new user. Unlike sign-up, this endpoint bypasses password validation and can set a hashed password directly.
Body:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ | User's email address |
password | string | — | Plaintext password (HelloJohn hashes it) |
password_hash | string | — | Pre-hashed password (for migrations) |
name | string | — | Full name |
username | string | — | Unique username |
phone | string | — | E.164 phone number |
email_verified | boolean | — | Mark email as verified (default: false) |
role | string | — | member, admin (default: member) |
public_metadata | object | — | Custom public data |
private_metadata | object | — | Custom private data (not in JWT) |
send_welcome_email | boolean | — | Trigger welcome email (default: false) |
curl -X POST https://api.hellojohn.dev/v1/users \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321" \
-H "Content-Type: application/json" \
-d '{
"email": "alice@example.com",
"password": "s3cur3P@ssw0rd",
"name": "Alice Smith",
"email_verified": true,
"public_metadata": { "plan": "pro" }
}'Response: 201 Created — Returns the created User object.
GET /v1/users/:id
Fetch a single user by ID.
curl https://api.hellojohn.dev/v1/users/usr_01HABCDEF123456 \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321"Also supported: GET /v1/users/email/:email
Response: 200 OK — Returns User object.
PATCH /v1/users/:id
Update a user. Only include the fields you want to change.
Body (all optional):
| Field | Type | Description |
|---|---|---|
name | string | Full name |
username | string | Unique username |
phone | string | E.164 phone number |
avatar_url | string | URL to avatar image |
role | string | member or admin |
email_verified | boolean | Override email verification status |
public_metadata | object | Replaces entire public_metadata object |
private_metadata | object | Replaces entire private_metadata object |
curl -X PATCH https://api.hellojohn.dev/v1/users/usr_01HABCDEF123456 \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321" \
-H "Content-Type: application/json" \
-d '{
"name": "Alice Johnson",
"public_metadata": { "plan": "enterprise" }
}'Response: 200 OK — Returns updated User object.
DELETE /v1/users/:id
Permanently delete a user and all associated data (sessions, MFA factors, org memberships).
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
GDPR compliance: Deleting a user removes all personal data. For soft-delete (preserve data for audit), use
PATCH /v1/users/:idwith"status": "disabled"instead.
POST /v1/users/:id/disable
Disable a user account. The user cannot sign in but their data is preserved.
curl -X POST https://api.hellojohn.dev/v1/users/usr_01HABCDEF123456/disable \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321"Response: 200 OK — Returns updated User object with "status": "disabled".
POST /v1/users/:id/enable
Re-enable a disabled user.
Response: 200 OK
POST /v1/users/:id/ban
Permanently ban a user. All active sessions are immediately revoked.
Body:
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | — | Internal reason for the ban (stored in audit log) |
Response: 200 OK
POST /v1/users/:id/sessions/revoke-all
Revoke all active sessions for a user (force sign-out on all devices).
curl -X POST https://api.hellojohn.dev/v1/users/usr_01HABCDEF123456/sessions/revoke-all \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321"Response: 200 OK
{ "revoked": 3 }POST /v1/users/:id/password
Set a new password for a user (admin override, no old password required).
Body:
| Field | Type | Required | Description |
|---|---|---|---|
password | string | ✅ | New password |
revoke_sessions | boolean | — | Revoke all sessions after change (default: true) |
Response: 200 OK
GET /v1/users/:id/sessions
List all active sessions for a user.
Response:
{
"data": [
{
"id": "ses_01HABCDEF999888",
"user_id": "usr_01HABCDEF123456",
"user_agent": "Mozilla/5.0...",
"ip_address": "192.168.1.1",
"created_at": "2024-01-15T10:30:00Z",
"last_active_at": "2024-01-20T08:15:00Z",
"expires_at": "2024-02-14T10:30:00Z"
}
]
}POST /v1/users/:id/impersonate
Generate an impersonation session for debugging. The CP Admin acts as the user.
Requires CP Admin secret key (
sk_cp_...). Generates an audit log entry.
Response: Returns a short-lived access token valid for 1 hour.
{
"access_token": "eyJhbGciOiJFZERTQSJ9...",
"expires_at": "2024-01-15T11:30:00Z",
"impersonated_by": "cpadmin_01HABCDEF111222"
}