Guide
Keys & credentials
Pharen has three credentials, and they are deliberately not interchangeable. Each one can do exactly one job, which is what makes it safe to ship one of them inside your app. This page is what each can do, how you get one, and what to do when one has to be pulled.
| Credential | Can | Cannot | Lives |
|---|---|---|---|
Ingest keyphi_live_… / phi_test_… | Send events for one app in one environment. | Read anything. Mint anything. | In your binary. Public by design — commit it. |
Query keyphq_live_… / phq_test_… | Read whitelisted aggregates, your issues and store context for the apps it names — and, only under a grant named at mint, the words people wrote in their reports (with addresses and phone numbers replaced), a user or an install, what your app said about a user, or the address a reporter left to be reached at. | Write anything. Read a raw event. Read another app. Read an original. Read a user or an install without the grant that covers it. Read anything under the health purpose, whatever its grants. | With the bot or agent that uses it. |
| Control credential | Everything above, plus mint and revoke keys. | — | With you, or with one CI job. Never in source. |
Ingest keys — the one that ships
An ingest key is write-only. It can create data and read none: the server derives your tenant, app and environment from the key itself, so a key cannot be pointed at someone else's app, and a stolen one cannot read a single row of yours. That is what makes it safe to ship inside a binary, the same way a crash-reporter DSN is.
You never handle the value. pharen setup ios mints one per environment and writes them into your build configuration — see the quickstart. Commit that file: a teammate who clones without it has no working build.
Seeing which keys exist
pharen ingest-keys list
pharen ingest-keys list --app your-app --environment productionOne row per key, each with its state — live, rotating out inside a grace window, or revoked, with the reason it was revoked and, while it can still be restored, until when. This is where the key_id for the commands below comes from. Note what is not here: the secret. A key's value is shown once, at mint, and never stored, so it can never be recovered — only replaced.
Rotating a key
Rotation is the ordinary move, and the one to reach for first. It mints a same-scope replacement and expires the old key a grace window later, so your installed base ages out instead of breaking at the instant of cutover — the builds already on people's phones keep reporting while you ship a new one.
pharen ingest-keys rotate ik_9pKq2mVx… # 24h grace by default
pharen ingest-keys rotate ik_9pKq2mVx… --grace 72h # a longer runway, typed with its unit
pharen ingest-keys rotate ik_9pKq2mVx… --grace 0 # immediate cutoverEach of these first shows what is at stake — the installs seen on the key in the last seven days, and what they will be told — and acts only when you add --yes.
Revoking a key
pharen ingest-keys revoke ik_9pKq2mVx… # routine, the default
pharen ingest-keys revoke ik_9pKq2mVx… --reason compromise # the key has leakedWorth saying plainly, because it changes the calculus: an ingest key appearing in a public binary is not a breach. It is the designed state. Someone who extracts one can write junk events into one app in one environment, and can read nothing. Rotate it if that is happening; you do not need to treat it as a credential leak.
Query keys — the one you hand to an agent
A query key is read-only, scoped, revocable and rate-limited. It reads a whitelisted registry of aggregates — never raw records, and never a metric grouped by a user or an install, because such metrics are structurally absent from the registry rather than filtered out at request time. Groups below a small-cell threshold are suppressed. A user or an install crosses only under the grant that covers it, below.
This is the credential for a bot, a scheduled report, or your own AI agent. It is the same registry the console's own dashboards read, so the two can never disagree about what a number means. To connect an agent over MCP rather than call the API directly, see Connect your agent.
pharen query-keys create --environment production --app your-app
pharen query-keys list # metadata only — ids, scope, grants and purpose, labels. Never a secret.--app is repeatable, and it is the only source of scope — it never defaults from your project config, because standing in one app's directory must not silently narrow a key you asked to be broad. Omitting it mints a tenant-wide key that reads every app you own, including apps you onboard later. Tenant and environment still bound it absolutely.
Grants: what a key reads beyond counts
A key without a grant reads counts, your issues and what the store shows. Each grant is named at mint by an owner or a developer, carried to the replacement on rotation, and listed by pharen query-keys list:
report_text— the words people wrote in their reports, masked (below).small_cells— every grouped cell exactly, including the small ones the threshold otherwise withholds.users— one user or install at a time, and a metric narrowed to one user, install or session;identity_contact,identity_nameandidentity_traitsbeside it add what your app said about them; andreport_contact— the address a reporter left to be reached at, on the issue read. These read users, so a key carrying one is minted with a statedpurposeby an owner, or by a developer whose identity read has not been withdrawn, and every read of a user it makes is recorded — in your identity reads log, or on the issue's history for a reporter's address. Such a key is minted with--purpose(at most 200 characters), why it reads users, by that person signed in withpharen auth login; a CI or workload token is refused.pharen query-keys listshows the purpose beside the grants, and rotation carries both to the replacement. What the agent is served is on Connect your agent.
pharen query-keys create --environment production --app your-app \
--grant users --grant identity_contact \
--purpose "support: find the account a customer writes in about"The words people wrote
A key reads counts, your issues and what the store shows. It does not read what a person typed into a report unless you mint it with --grant report_text — a choice made per key, at mint, by an owner or a developer, and carried to the replacement on rotation. The command prints a warning before the key is shown: the key reads the words people wrote in their reports for the apps it names, with addresses and phone numbers replaced; whatever holds it can read them, and if that is an AI service, your own terms with that service apply. Scope such a key to one app, label it with the agent it serves, and revoke it when that agent is retired. pharen query-keys list prints no grants for a key without one — an empty list here means none, the opposite of an empty app list. What the agent is served, and how an owner or a developer reads an original on the record, is on Connect your agent.
pharen query-keys create --environment production --app your-app \
--grant report_textUsing one
A request names a metric, an app_id, an environment, and optionally group_by and filters. There is no free-form query language — anything not in the registry is rejected rather than interpreted.
curl https://api.pharen.ai/v1/query \
-H "Authorization: Bearer phq_live_…" \
-H "Content-Type: application/json" \
-d '{"metric":"crashes.count","app_id":"your-app",
"environment":"production","group_by":["app_version"]}'GET /v1/query/metrics with the same key returns the registry itself — every metric, what it means, and which dimensions it can be grouped and filtered by. That is the right first call for an agent, and the right place to look before trusting a zero.
Rotating and revoking
pharen query-keys rotate qk_4nRt7bZw… # no grace by default
pharen query-keys rotate qk_4nRt7bZw… --grace 4h # gapless rollover
pharen query-keys revoke qk_4nRt7bZw…The default is the opposite of an ingest key's, on purpose: a bot swaps a credential in a second, so there is nothing to age out. Revocation is immediate and idempotent — have the replacement in place first, because anything still holding the old key stops reading at once.
Your control credential — the secret one
This is the one that matters. It can read your data and mint every key above, so it stays with the person or the single CI job that holds it.
pharen auth login # browser sign-in; stores a session at ~/.config/pharen/credentials.json
pharen auth status # exits 0 if the active credential authenticates
pharen auth logout # deletes the stored sessionFor CI, export PHAREN_AUTH_TOKEN. It wins over a stored session when set, and the CLI says so on stderr rather than silently preferring one identity over another.