Create Users
How to create users in HelloJohn — via sign-up, admin API, and bulk import.
Create Users
Users can be created through self-service sign-up or programmatically via the Admin API. This page covers both patterns.
Self-Service Sign-Up
The most common way: the user creates their own account through your sign-up form.
Via SDK
import { useHelloJohn } from "@hellojohn/react";
function SignUpForm() {
const { auth } = useHelloJohn();
const handleSignUp = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const data = new FormData(e.currentTarget);
await auth.signUp({
email: data.get("email") as string,
password: data.get("password") as string,
name: data.get("name") as string,
});
};
return (
<form onSubmit={handleSignUp}>
<input name="name" placeholder="Full name" required />
<input name="email" type="email" placeholder="Email" required />
<input name="password" type="password" placeholder="Password" required />
<button type="submit">Create account</button>
</form>
);
}Via API
curl -X POST https://api.hellojohn.dev/v1/auth/sign-up \
-H "Authorization: Bearer pk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321" \
-H "Content-Type: application/json" \
-d '{
"email": "alice@example.com",
"password": "SecurePassword123!",
"name": "Alice Smith"
}'Response: 201 Created
{
"user": {
"id": "usr_01HABCDEF123456",
"email": "alice@example.com",
"name": "Alice Smith",
"email_verified": false,
"created_at": "2024-01-15T10:00:00Z"
},
"access_token": "eyJhbGciOiJFZERTQSJ9...",
"refresh_token": "rt_01HABCDEF..."
}Admin-Created Users
Create users server-side without them going through sign-up. Useful for:
- Inviting users directly (no self-registration)
- Migrating users from another system
- Creating test accounts
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",
"name": "Alice Smith",
"password": "TemporaryPass123!",
"email_verified": true,
"send_welcome_email": true,
"public_metadata": {"plan": "starter"},
"role": "member"
}'Body:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✅ | User email (must be unique) |
name | string | — | Display name |
password | string | — | If omitted, user must reset via magic link |
phone_number | string | — | E.164 format |
email_verified | boolean | — | Skip email verification (default: false) |
send_welcome_email | boolean | — | Send welcome email (default: true) |
role | string | — | System role (default: member) |
public_metadata | object | — | Public key/value data |
private_metadata | object | — | Private key/value data |
Response: 201 Created — Returns user object (without password).
Passwordless User Creation
Create a user without a password. They sign in via magic link or SSO:
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",
"name": "Alice Smith",
"email_verified": true
}'Send a magic link so they can sign in:
curl -X POST https://api.hellojohn.dev/v1/auth/magic-link \
-H "Authorization: Bearer pk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321" \
-H "Content-Type: application/json" \
-d '{"email": "alice@example.com"}'Preventing Duplicate Accounts
POST /v1/users returns 409 Conflict if the email is already taken:
{
"error": "email_already_exists",
"message": "A user with this email already exists."
}To handle this gracefully:
try {
const user = await hj.users.create({ email, name });
} catch (error) {
if (error.code === "email_already_exists") {
// Either update the existing user or use them as-is
const existing = await hj.users.getByEmail(email);
return existing;
}
throw error;
}Disabling Sign-Up
To prevent users from self-registering (admin-only creation):
curl -X PATCH "https://api.hellojohn.dev/v1/admin/config" \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321" \
-H "Content-Type: application/json" \
-d '{"sign_up_enabled": false}'POST /v1/auth/sign-up will return 403 for all requests.