Logging In
Iron uses a single shared identity per person across every app, backed by Supabase Auth at your-domain.example. This is the one sanctioned cross-app dependency: one login, everywhere. CRM access is still gated per-tenant by membership (see below).
For operators and clients (the UI)
Section titled “For operators and clients (the UI)”Log in to the dashboard at your-domain.example. Your Iron identity is your Supabase
user; once authenticated, the app resolves which subaccount(s) you can act in from your
crm.org_members rows. Clients see a curated portal into their own subaccount.
For API callers
Section titled “For API callers”Every authenticated /api/v1 request carries a Supabase JWT as a bearer token:
Authorization: Bearer <supabase-jwt>The token is validated as HS256 with audience authenticated. An invalid or expired token
returns 401 Unauthorized with a WWW-Authenticate: Bearer header.
Once the user is resolved, the request also resolves an acting org. Most endpoints expect
an X-Org-Id header to select the subaccount you are acting in:
Authorization: Bearer <supabase-jwt>X-Org-Id: <org-uuid>If X-Org-Id is omitted, the API falls back to your earliest-joined org. See
Subaccounts & X-Org-Id and Authentication
for the full rules.
Service-to-service auth
Section titled “Service-to-service auth”Some internal seams are called by trusted services (for example, the telephony engine booking
on the native scheduler, or inbound webhooks) rather than a logged-in user. Those endpoints
authenticate with a shared secret header (X-Iron-CRM-Secret) instead of a user JWT, and pass
the org explicitly in the request body. These are not part of the public user-facing API; see
Webhooks.
First login provisioning
Section titled “First login provisioning”On the first authenticated request for a brand-new user, the API auto-provisions a fresh org, an owner membership, a CRM tenant, and a default pipeline. This bootstrap runs under a system context (it cannot be org-scoped yet, because the org does not exist), then the rest of the request runs org-scoped. You do not need to do anything to trigger this — it happens on first authenticated access.