Private betaRequest early access →

Sign in

API keys

An API key lets a service call the Perihelium API on your organization's behalf, without a human signing in. Use one for a backend job, a data sync, a CI pipeline — anything that runs unattended.

Manage keys in the app under Settings → API Keys (you need the tenant:manage permission).

If creating a key is refused with 403 and a message about finishing setup, the organization is quarantined — it was opened by an AI agent and its owner has not approved the setup. See Agent-driven onboarding.

The shape of a key

Text
zyn_live_<secret>_<checksum>
  • live or test — a key is bound to the environment that issued it. A test key can never authenticate against production, and a live key never against a test deployment. That is enforced on every request, so a mixed-up environment variable fails immediately and visibly rather than doing something surprising in the wrong place.
  • The trailing checksum lets malformed or truncated keys be rejected instantly, and lets automated secret scanners recognise a leaked Zynth key on sight.

Use it exactly like an access token:

Shell
curl https://auth.zynthmedia.com/api/v1/consent/admin \
  -H "Authorization: Bearer zyn_live_…"

The key is shown once

When you create or rotate a key, the full value appears exactly once, in that one response. We store only a hash of it — we cannot show it to you again, and we cannot recover it for you. Copy it into your secret store immediately. If you lose it, rotate the key and update the caller; there is no "reveal" button, by design.

Afterwards you will only ever see a display handle like zyn_live_abcd…wxyz, which is safe to put in a ticket, a log line, or a screenshot.

Scopes: what a key may do

Scopes are the same permissions your roles use — compliance:read, command:read, and so on. A key can do exactly what its scopes allow and nothing else.

  • A key with no scopes authenticates but can call nothing. That is a deliberate default: you grant capability on purpose, never by omission.
  • Scopes are validated when the key is created, so a typo like compliance:reed is refused at that moment rather than becoming a permission that silently never works.
  • Give each integration its own key with the narrowest scopes it needs. Two integrations sharing one key means revoking either one takes down both.

You can only put your own permissions on a key

A key may not carry a permission you do not hold yourself. Asking for one is refused with 403, and the response names every scope you are missing — the key is not created, not even partially. Holding tenant:manage lets you manage keys; it does not let you hand an integration compliance:admin that you could not use yourself. Tenant owners hold everything, so this never limits them.

The same rule applies to rotation, because a rotation hands you a working copy of the key: you can rotate a key whose scopes you hold, and not one whose scopes you do not.

This is the rule your roles already follow when you delegate authority to someone else. A key is authority handed to a piece of software, so it follows it too.

Platform permissions can never ride a key

A few permissions are platform-scoped — they belong to Zynth's own operator plane (operator:read, operator:manage) and to the assurance programme that exercises it (assurance:read, assurance:operate, assurance:report). They are not tenant permissions, and no API key may carry one, on creation or on rotation. Asking for one is refused and nothing is minted: 403 if the permission was never yours to give (the rule just above), and 400 naming the codes if you do hold them — nobody may put them on a key.

If you never see those names in your console, this rule will never touch you: it exists so that the surfaces which provision organizations and run platform drills cannot be reached by a standing bearer token that has no kill switch, no oversight mode, and no expiry.

A key carries reads and a short list of writes

An API key is a bearer credential: it has no kill switch, no risk ceiling and no approval step, and it works until it expires or you revoke it. So a key may carry:

  • any read-only permission (compliance:read, members:read, and the rest of the *:read family), and
  • five writes, each for an integration the product documents:
PermissionWhat the key is for
agents:killa SIEM or pager that engages an agent's emergency stop; releasing a stopped agent needs a person (the key is refused with 403)
hipaa:phi:logan EHR integration recording each access to protected health information
identity:self:writean SDK reporting security signals (and nothing else: consent, data-subject requests and policy acknowledgement are a person's acts and refuse a key)
payments:verifyyour backend consuming a step-up grant (see payment security)
autonomy:disablea pager that stops autonomous response, never restores it

Authoring content drafts is an AI agent's work, not a key's: delegate content:draft:write to an agent (see agent-authored content).

Anything else (tenant:manage, members:manage, compliance:admin, command:operate, isms:write, manifest:apply, and every other permission that changes who has authority or what the platform does) is refused with 400, naming the permission, on creation and on rotation, and for the tenant owner too. If an integration needs to change things beyond this list, give it an AI agent (it has a kill switch, a risk ceiling and an approval step) or have a person do it.

Keys you already have. A key created before this rule keeps working. On the day it takes effect it keeps its reads and the five writes above and loses the other write scopes: a call that needed one now answers 403. The key is not rewritten and is not revoked. To keep an integration running, create a new key with the scopes it can carry. The key list shows each scope the key no longer confers as inactive (struck through), because the key's record still lists what it was given; the API returns them as inactive_scopes. Rotating a key that holds a scope it can no longer carry is refused with the same 400.

Only a person can create an API key

An AI agent principal — and an API key itself — is refused key creation and rotation outright, with 403, whatever permissions it holds or has been delegated.

An agent operates under governance you control: a kill switch, a risk ceiling, an oversight mode, and human approval where you require it. An API key has none of those — it is a separate principal, and stopping the agent that made it would not stop the key. Letting an agent mint one would let it step outside the very controls you put it inside; letting a key mint one would let a leaked key hand itself a successor that outlives its own revocation. If your agent's or integration's workload genuinely needs a key, a person creates it. Each refused attempt is recorded and surfaces in your Command Center as a detection.

A runaway key is revoked automatically

A key is bounded by the same blast-radius budget as an agent (see the API reference): a rolling hourly write budget from your plan, and a fixed allowance of refused requests. A key that exhausts either is revoked — not slowed — with the reason recorded on the key (blast-radius breaker: …), and its next request is refused. There is no un-revoke: read the reason, fix what tripped it, and mint a new key. Reads never count, and a normal integration never comes near the bound.

Rotating without downtime

Rotation issues a new key and leaves the old one working:

  1. Rotate — you get a new key with the same scopes. (You must hold those scopes yourself — see above.)
  2. Migrate — deploy the new key to whatever uses it.
  3. Revoke the old one once nothing is using it.

Both keys are valid in between, so there is no window where your integration is broken. The portal shows which key replaced which.

Revoking

Revocation takes effect on the key's very next request — not after a cache expires. Record a reason when you revoke; it stays visible in the portal afterwards, which is what makes an incident reconstructable months later.

If a key leaks, revoke it immediately. Repeated attempts to use a revoked key are detected and raised to your security operators.

What a key did can be read back and undone

Every write a key makes is journalled under the key's own id, the way an AI agent's writes are. After a leak or a misbehaving integration, read GET /api/v1/recovery/api-keys/{key_id}/journal (newest first, windowed with since / until, paged) to see exactly what the key did, and POST /api/v1/recovery/api-keys/{key_id}/rollback to undo what can be undone. Both need tenant:manage, which a key can never carry, and the rollback must be a person. The report is honest: a stop, an access record, a spend or an SDK report has no clean inverse and is listed as irreversible rather than pretended undone. See recovery.

Expiry

Keys expire after one year by default. You can choose a different lifetime, or explicitly create a non-expiring key — but that has to be a decision someone makes, not an accident. An expired key is refused exactly like a revoked one.

Your organization may carry a maximum key lifetime set by the platform operator (a common compliance requirement). When one applies, creating a key with a longer lifetime — or a non-expiring one — is refused with a message stating the cap, and rotated keys inherit it. If you need longer-lived keys than your cap allows, that is a conversation with your operator, not a workaround.

Rate limits and your monthly quota

Two different numbers apply, and they behave differently:

What it isWhat happens at the limit
Rate limitRequests per minute for a key429, with Retry-After telling you when to try again
Monthly quotaTotal API calls per month on your plan429 with RateLimit-Policy: monthly-quota

Both come from your plan, so if you need more throughput, that is a conversation with us — not an engineering change on your side or ours.

Your people are never locked out by either of these. Exceeding your plan's quota affects your integrations; the humans in your organization keep signing in normally. A commercial limit is a billing conversation, not an outage.

Every 429 carries headers so a well-behaved client can respond correctly:

Text
RateLimit-Limit: 120
RateLimit-Remaining: 0
RateLimit-Reset: 47
Retry-After: 12

Honour Retry-After before retrying, and watch RateLimit-Remaining if you want to slow down before hitting the wall.

Seeing usage

The portal shows calls this month, per key and in total, against your plan's limit — plus each key's last-used date. That is the fastest way to answer "which integration is doing all this?" and to spot a key that nothing uses any more (a good candidate for revocation).

Good practice

  • One key per integration, narrowly scoped.
  • Store keys in a secret manager, never in source control.
  • Rotate on a schedule, and immediately whenever someone who had access leaves.
  • Revoke keys you are not using — an unused live key is only a risk.