Managing multiple Norbelys orgs from one terminal with the CLI
How the norbelys CLI's one-profile-per-org config file works, and the safe patterns for switching between client workspaces without hitting the wrong org.
By Gabriel Lara, Developer Relations, Norbelys
Founder-reviewed ·How we research and correct articles
An agency running Norbelys for a dozen clients isn’t managing one workspace — it’s managing a dozen, each its own Clerk organization with its own senders, its own audience, its own suppression list. Clicking into the dashboard and switching orgs from a menu works fine for a person doing one thing at a time. It works less well the moment you want to run the same check, the same import, or the same health audit across every client workspace without doing it by hand twelve times.
The CLI’s config file is built around exactly this: one profile per org, in a single file, on one machine. This post covers how that actually works and — more importantly — how to avoid the one mistake it makes possible: running a command against the wrong org.
What’s actually in the config file
Every norbelys login writes its result to
~/.config/norbelys/config.json, and the file holds one profile per
organization you’ve authenticated against. A separate post covers why that
file is locked down to mode 0600
— worth reading first if you haven’t, since everything below assumes that
baseline: the file is only readable by you, and it’s the thing standing
between “a script mistargets a client” and “a script mistargets a client
and the credential that made it possible was sitting around loosely
permissioned too.”
It’s a plain JSON file, which is worth remembering in its own right — if you’re ever unsure what’s configured, you can open it and read it directly instead of trusting what you think you remember setting up three months ago.
Adding a second org safely
Bringing a new client workspace under the CLI
Generate a dedicated API key for that org
From that client's own dashboard, not a key copied from a different workspace. A key is org-scoped by design — using the right org's key from the start removes an entire category of mistake before it can happen.
Log in with that key
norbelys login --api-key ak_... against the new key. This adds or updates that org's profile in config.json without touching any other org's saved credential.
Confirm which org you're actually pointed at
Run norbelys whoami immediately after. Don't assume the login succeeded against the org you meant — verify it, especially the first time you're setting up a new client.
Name things so future-you doesn't have to guess
If you're scripting around multiple orgs, keep a clear mapping somewhere outside the CLI itself — a README, a secrets manager entry — between client name and which key belongs to which. The config file identifies orgs; it doesn't remind you which client that org is.
The real risk: running against the wrong org by habit
The failure mode here isn’t exotic — it’s the same one that bites anyone
juggling multiple AWS accounts or multiple kubectl contexts. You run a
command you’ve run a hundred times, on muscle memory, and it executes
against whichever org happened to be active last, not the one you meant
this time. For a read like people list, that’s an annoyance. For a write
— deleting a suppressed contact, launching a program — it’s a real
incident, and it’s one client’s data affected by a mistake meant for
another.
The pattern that actually removes the risk: be explicit in scripts
Interactive habit-checking helps, but it’s still a human remembering to do
something. For anything scripted, there’s a more reliable pattern already
built into the CLI: the bearer token resolves from an environment variable
before it falls back to a saved profile.
That means a script touching multiple orgs doesn’t need to rely on “whichever
profile is currently active” at all — it can set NORBELYS_API_KEY
explicitly for each org, for each run, so there’s no ambient state to get
wrong in the first place.
A loop across client orgs looks roughly like this — each iteration overrides the environment variable for that one command, rather than depending on a persisted “current” profile:
That NORBELYS_API_KEY="$key" norbelys ... prefix — setting the variable
for a single command rather than exporting it for the whole shell session —
is the important part. It scopes the credential to exactly one invocation,
so there’s no window where a leftover exported variable from checking
Acme’s senders accidentally applies to a command you meant to run against
Northwind two lines later.
Separating interactive use from scripted use
A practical split that holds up in practice: use norbelys login and the
saved profile for whichever org you’re interactively poking around in right
now — one active context at a time, checked with whoami before anything
destructive. Reserve the environment-variable override for anything
scripted or repeated across orgs, where you want the credential explicit at
the point of use instead of implicit in whatever you logged into last. Mixing
the two — writing a multi-org script that quietly depends on the profile
you happen to have active — is exactly the setup that produces the wrong-org
mistake eventually, even if it works fine the first several times you run
it.
Naming senders and resources so cross-org output stays readable
One thing that trips people up the first time they run a check across
several orgs: the output of most commands only tells you about the resource
inside its own org, not which org it came from — a senders list result
doesn’t stamp “this is Acme’s data” on every row, because from the API’s
point of view there’s no such thing as a cross-org list to begin with. When
you’re piping several orgs’ output into one place, as in the loop above,
label it yourself — the echo "== ${client} ==" line before each call
isn’t decoration, it’s the only thing that keeps twelve orgs’ worth of JSON
from reading as one undifferentiated blob once it’s scrolled past.
If the config file gets lost or a key gets rotated
Losing config.json isn’t a data-loss event — it holds credentials, not
anything Norbelys itself considers a source of truth. Re-run norbelys login per org and you’re back where you started. The direction that
actually matters is the other one: if a key is compromised or a client
relationship ends, revoke that org’s key from its dashboard and run
norbelys logout (or just delete the stale entry) so an old credential
isn’t sitting in a config file for a workspace you no longer manage.
Next steps
- API key vs. browser OAuth — the full picture on credentials, the config file, and why its permissions matter.
- Automating ops checks in CI for the single-org version of the scripted-loop pattern above.
- CLI vs. dashboard: when to script if you’re deciding whether an agency-wide check is worth automating at all yet.
- Install the CLI if you’re setting this up on a fresh machine.
- The developer portal for the API surface every profile ultimately talks to, org by org.