HelloJohn / docs
Users

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

IdentifierFormatUniqueMutable
idusr_01HABCDEF123456Never
emailalice@example.comPer tenant
phone_number+14155552671Per tenant
external_idAny stringPer 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

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

  1. Admin or user sets new email via PATCH /v1/users/:id
  2. Verification email sent to new address
  3. New email is active after verification
  4. 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.


On this page