API Keys
Issue, scope, rotate, and revoke Organization machine credentials, and understand what a key can never do.
An API key is an Organization-owned machine credential. It is not a personal access token: once issued, its authority is independent of the person who created it, so a Role change or a departure neither widens nor narrows the integration.
Prefix
ulsav_sk_
Scope
Exactly one
It covers that subtree's descendants
Secret
Shown once
Later reads return the prefix only
Authority
Frozen at issue
Independent of the creator
Managed by
A session, never a key
Expiry
Optional
High-risk keys should carry one
Create a key
Create keys in the organizer webapp under Settings → API Keys, or call the operation below with a signed-in session.
| Action | Capability |
|---|---|
| Create, edit, or roll | api_keys.create |
| Read metadata | api_keys.read |
| Revoke | api_keys.revoke |
Every action requires a session-authenticated human, and an API key can never manage another.
A creation request carries:
| Field | Meaning |
|---|---|
name | A label for the integration, up to 80 characters |
capabilities | The exact actions the key may perform |
scopeType / scopeId | The one resource subtree the key applies to; defaults to the Organization |
expiresAt | Optional expiry; high-risk keys should carry one |
allowedOrigins | Optional browser-origin allowlist for non-credentialed CORS |
/api/v1/organizations/{organization_id}/api-keysIssue an Organization API key and return its secret once.
api_keys.createPOST /api/v1/organizations/{organization_id}/api-keys
Content-Type: application/json
{
"name": "Order sync",
"capabilities": ["orders.read", "registrations.read"],
"scopeType": "Organization",
"expiresAt": "2027-11-06T00:00:00Z",
"allowedOrigins": ["https://app.example.com"]
}The response contains the key metadata and the secret, shown exactly once:
{
"apiKey": {
"id": "019ae4b0-...",
"name": "Order sync",
"prefix": "ulsav_sk_...",
"capabilities": ["orders.read", "registrations.read"],
"scopeType": "Organization",
"status": "active"
},
"secret": "ulsav_sk_..."
}The apiKey object also carries organizationId, scopeId, allowedOrigins, createdAt, and updatedAt. Store the secret in your secret manager before leaving the page. Later reads return metadata and the prefix only; there is no "show secret again" operation.
What the key can do
Authority is fixed at issuance and is deliberately narrow:
- It is a subset of the issuer. Selected capabilities and Scope must fit inside the creating member's effective authority at that Scope.
- It does not follow the issuer. If the creator later loses a Role or leaves the Organization, the key keeps its frozen authority until a member with
api_keys.createorapi_keys.revokein the Organization acts on it. - It has exactly one Scope. That Scope covers its descendants through the resource hierarchy, so a key scoped to an EventGroup can act on that group's Events, but not on a sibling Event.
- It is allowed per operation. Key access is a default-deny decision made operation by operation. An endpoint used by the browser session is not automatically available to keys.
An operation that does not declare API-key policy rejects a key with 403 api_key_forbidden, even if the key names a similarly named capability. An operation that does declare policy checks three things in order:
- The Organization in the path must equal the key's Organization.
- The capability must match exactly.
- The key's Scope must be the target or one of its ancestors.
Failures are 403 api_key_forbidden or 403 api_key_scope_denied.
What a key can never do
The api_keys.* capability family is human-only and is never valid on a key. A key cannot create, list, read, edit, roll, or revoke any key, including itself. This is enforced at the HTTP layer as well as at issuance, so an operation mistakenly configured to accept keys for key management still rejects them.
Organization suspension or platform suspension overrides every key: requests fail with organization_suspended or platform_suspended until the suspension is lifted.
Rotate and revoke
/api/v1/organizations/{organization_id}/api-keys/{api_key_id}/rollReplace the secret while keeping the key's id, capabilities, and Scope.
api_keys.createPOST /api/v1/organizations/{organization_id}/api-keys/{api_key_id}/rollRolling and revoking answer different questions:
Roll
- Keeps the key's id, capabilities, and Scope
- Returns the new secret once
- Stops the previous secret immediately
Revoke
- Permanent; the key's status becomes
revoked - Keeps the metadata, creator, and audit trail useful
Unlike webhook signing secrets, a roll has no grace window, so schedule the cutover and restart workers that cache the old value. Revoke rather than delete.
/api/v1/organizations/{organization_id}/api-keys/{api_key_id}/revokePermanently disable a key and keep its audit trail.
api_keys.revokePOST /api/v1/organizations/{organization_id}/api-keys/{api_key_id}/revokeA revoked key and an expired key both fail authentication with 401; their statuses read revoked and expired.
One key per integration and environment
Separate keys make rotation boring, keep last-used metadata meaningful, and bound the blast radius of a leak. Do not share one key between staging and production, or between two services that only happen to be written by the same team.
Questions
Can an API key manage other API keys?
No. The api_keys.* family is human-only, so a key cannot create, list, read, edit, roll, or revoke any key, including itself.
Does rolling a key change its id, capabilities, or Scope?
No. Rolling keeps the key's id, capabilities, and Scope, and replaces only the secret.
Is there a grace window after I roll a secret?
No. The previous secret stops working immediately, unlike webhook signing secrets, so schedule the cutover and restart any worker that caches the old value.
What happens to a key when its creator leaves the Organization?
Nothing. Authority is frozen at issue, so the key keeps working until a member with api_keys.create or api_keys.revoke in the Organization edits or revokes it.
Should I revoke a key or delete it?
Revoke it. The metadata, creator, and audit trail stay useful, and the key's status becomes revoked.