User Identifiers
How HelloJohn identifies users — IDs, emails, phone numbers, and external IDs.
User Identifiers
HelloJohn provides multiple ways to look up and reference users. Understanding the different identifier types helps you build robust integrations.
Identifier Types
| Identifier | Format | Unique | Mutable |
|---|---|---|---|
id | usr_01HABCDEF123456 | ✅ | Never |
email | alice@example.com | Per tenant | ✅ |
phone_number | +14155552671 | Per tenant | ✅ |
external_id | Any string | Per tenant | ✅ |
HelloJohn User ID
The primary identifier is the HelloJohn user ID (id), prefixed with usr_. It is:
- Globally unique across all tenants
- Immutable — never changes, even if the user changes their email
- Safe to store in your database as a foreign key
// Store in your DB when the user first signs in
const user = await hj.auth.getUser(token);
await db.users.upsert({ hellojohn_id: user.id, ...user });Email is unique per tenant. Users can change their email, which triggers re-verification.
Look up by email
curl "https://api.hellojohn.dev/v1/users?email=alice@example.com" \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321"Email change flow
- Admin or user sets new email via
PATCH /v1/users/:id - Verification email sent to new address
- New email is active after verification
- JWT contains the new email
Phone Number
Phone numbers use E.164 format: +14155552671. Unique per tenant.
Set phone number
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 '{"phone_number": "+14155552671"}'Phone verification
After setting a phone number, verify it with an SMS OTP:
// Trigger SMS verification
await hj.users.sendPhoneVerification(userId);
// Verify with the code received
await hj.users.verifyPhone(userId, "123456");External ID
The external_id is a custom string you assign to link a HelloJohn user to a record in your own system. It must be unique within a tenant.
When to use external IDs
- Migrating from another auth provider (set to old provider's user ID)
- Linking to your internal database ID
- Syncing with an external CRM or ERP
Setting an external ID
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 '{"external_id": "user_42"}'Looking up by external ID
curl "https://api.hellojohn.dev/v1/users?external_id=user_42" \
-H "Authorization: Bearer sk_live_abc123" \
-H "X-Tenant-ID: tnt_01HABCDEF654321"const user = await hj.users.getByExternalId("user_42");Referencing Users in Your Database
Best practice: Store the HelloJohn id as the primary foreign key in your database.
CREATE TABLE profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
hj_user_id TEXT UNIQUE NOT NULL, -- HelloJohn user ID
plan TEXT NOT NULL DEFAULT 'free',
created_at TIMESTAMPTZ DEFAULT now()
);On first sign-in, create the profile if it doesn't exist:
app.post("/auth/callback", async (req, res) => {
const user = await verifyToken(req.body.token);
const profile = await db.profiles.upsert({
hj_user_id: user.sub,
plan: user.public_metadata?.plan ?? "free",
});
res.json({ profile });
});Identifier Uniqueness
Identifiers are unique within a tenant. Two different tenants can have users with the same email — they are separate accounts with separate HelloJohn IDs.