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.

CredentialCanCannotLives
Ingest key
phi_live_… / phi_test_…
Send events for one app in one environment.Read anything. Mint anything.In your binary. Public by design — commit it.
Query key
phq_live_… / phq_test_…
Read whitelisted aggregates for the apps it names.Write anything. Read raw records. Read another app.With the bot or agent that uses it.
Control credentialEverything 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

bash
pharen ingest-keys list
pharen ingest-keys list --app your-app --environment production

One row per key, each with its state — live, rotating out inside a grace window, or revoked. This is where the key_id for the two 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.

bash
pharen ingest-keys rotate ik_9pKq2mVx…                  # 24-hour grace by default
pharen ingest-keys rotate ik_9pKq2mVx… --grace-hours 0  # immediate cutover

Revoking a key

bash
pharen ingest-keys revoke ik_9pKq2mVx…

Worth 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, never a field carrying personal or sensitive data, because such metrics are structurally absent from the registry rather than filtered out at request time. Groups below a small-cell threshold are suppressed.

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.

bash
pharen query-keys new --environment production --app your-app
pharen query-keys list      # metadata only — ids, scope, 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.

Using 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.

bash
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

bash
pharen query-keys rotate qk_4nRt7bZw…                  # no grace by default
pharen query-keys rotate qk_4nRt7bZw… --grace-hours 4  # 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.

bash
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 session

For 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.