HelloJohn / docs
Multi-tenancy

Managing Tenants

Create, configure, and manage tenants in HelloJohn — REST API, hjctl CLI, and dashboard. Tenant lifecycle, slugs, custom domains, and metadata.

Creating a tenant

POST /v2/admin/tenants
Authorization: Bearer $ADMIN_TOKEN
Content-Type: application/json

{
  "name": "Acme Corp",
  "slug": "acme-corp",
  "owner_email": "admin@acme.com",
  "metadata": {
    "plan": "pro",
    "salesforce_id": "0015000001AbCdE"
  }
}

Response 201 Created:

{
  "id": "ten_01HX...",
  "name": "Acme Corp",
  "slug": "acme-corp",
  "created_at": "2026-01-15T10:00:00Z",
  "owner_id": "usr_01HX...",
  "metadata": { "plan": "pro", "salesforce_id": "0015000001AbCdE" }
}
hjctl tenants create \
  --name "Acme Corp" \
  --slug "acme-corp" \
  --owner-email "admin@acme.com"
tenant, err := hjClient.Tenants.Create(ctx, &hellojohn.CreateTenantParams{
    Name:       "Acme Corp",
    Slug:       "acme-corp",
    OwnerEmail: "admin@acme.com",
    Metadata: map[string]any{
        "plan": "pro",
    },
})
const tenant = await hj.tenants.create({
  name: 'Acme Corp',
  slug: 'acme-corp',
  ownerEmail: 'admin@acme.com',
  metadata: { plan: 'pro' }
})

Listing tenants

GET /v2/admin/tenants?page=1&limit=20&search=acme
{
  "tenants": [
    {
      "id": "ten_01HX...",
      "name": "Acme Corp",
      "slug": "acme-corp",
      "user_count": 42,
      "created_at": "2026-01-15T10:00:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 20
}

Getting a tenant

GET /v2/admin/tenants/{tenantId}
# or by slug:
GET /v2/admin/tenants/slug/{slug}

Updating a tenant

PATCH /v2/admin/tenants/{tenantId}
Content-Type: application/json

{
  "name": "Acme Corporation",
  "metadata": { "plan": "enterprise" }
}

Deleting a tenant

DELETE /v2/admin/tenants/{tenantId}

Deleting a tenant permanently deletes all users, sessions, and data within it. This cannot be undone. HelloJohn requires confirmation via the X-Confirm-Delete: true header.

DELETE /v2/admin/tenants/{tenantId}
X-Confirm-Delete: true

Tenant slugs

Slugs are URL-friendly identifiers. They must be:

  • Lowercase alphanumeric + hyphens
  • 3-63 characters
  • Unique across the instance

Slugs are useful for tenant-specific login pages:

https://yourapp.com/login/{slug}

Tenant metadata

Use metadata to store arbitrary data alongside a tenant — Stripe customer IDs, Salesforce IDs, plan names, etc.:

{
  "metadata": {
    "stripe_customer_id": "cus_Nxxx",
    "salesforce_account_id": "0015000001AbCdE",
    "plan": "enterprise",
    "seats": 100
  }
}

Metadata is returned in all tenant API responses and can be queried:

GET /v2/admin/tenants?metadata.plan=enterprise

Tenant stats

GET /v2/admin/tenants/{tenantId}/stats
{
  "user_count": 42,
  "active_sessions": 18,
  "mau": 35,
  "created_at": "2026-01-15T10:00:00Z",
  "last_activity_at": "2026-03-07T14:00:00Z"
}

On this page