Authentication
Key types, scoping, rotation and revocation — and choosing the right credential.
Every request carries a credential in the x-api-key header.
curl https://api.uni-flow.ai/api/v1/workspaces \
-H "x-api-key: ck_live_..."Credential types
| Prefix | Reaches | Use for |
|---|---|---|
ck_live_ | Everything in the tenant | Server-side application code |
ck_test_ | Everything, non-production | Development |
ck_eph_ | Everything, for 24 hours | CI and short-lived automation |
mk_ | Exactly one memory | Agents, edge deployments, third parties |
| OAuth 2 token | What its scopes allow | Machine-to-machine integrations |
Pick the narrowest that works. A tenant-wide key inside a distributed agent is a blast radius nobody chose deliberately — it is what happens when the first key minted is the key that ships.
Per-memory keys
An mk_ key is bound to one memory and rejected everywhere else. Pair it with the
memory's own hostname:
curl https://acme-1045.api.uni-flow.ai/api/v1/memory/search \
-H "x-api-key: mk_..." \
-H "content-type: application/json" \
-d '{"query": "..."}'A leaked mk_ key exposes one memory. A leaked ck_live_ key exposes everything.
Restricting a key
At creation you can set:
app_permissionsobjectPer-app allow-list. Empty means unrestricted, which is the legacy default — set it explicitly for new keys.
ip_allowliststring[]CIDR ranges the key may be used from.
expires_atstring (date-time)Automatic expiry. Ephemeral keys get 24 hours by default.
Rotation
POST/api/v1/api-keys/{key_id}/rotate
The replacement is minted before the original is revoked, so a rotating client has an overlap window rather than an outage. Deploy the new key, confirm traffic has moved, then revoke.
The plaintext key is returned only in the rotation response. There is no way to read it afterwards.
Revocation
DELETE/api/v1/api-keys/{key_id}
Revocation hits the gateway first and the database second. There is no window in which a revoked key still authenticates.
What the gateway does
Resolve
The key is hashed and matched, resolving to a tenant.
Sanitise
Client-supplied trust headers are stripped, and verified identity is injected in their place.
Enforce
Per-key rate limits and quotas are applied before anything reaches a service.
You never send a tenant id, and there is no parameter that would let you claim one. Cross-tenant access is not blocked so much as unavailable.
Storage
Keys are stored as SHA-256 hashes and compared in constant time. The plaintext is shown exactly once, at creation.
If a key is lost, rotate it. There is no recovery path, and a system that offered one would be storing your key in a form an attacker could steal.