API Keys — Reference
The API Keys surface is the platform's token-management plane. It owns the lifecycle of every credential that an external system uses to call into SGEN — creation, scope assignment, last-used tracking, rotation, and revocation. Any integration that authenticates against SGEN's programmatic surface traces back to a record managed here.
This page is a reference for platform engineers and integrators who need to understand the surface before extending it, scripting against it, or scoping a credential model. Customer-facing how-tos live in the customer docs set; this page describes the shape of the surface, not the steps to drive it.
Overview
API Keys live under the Settings → Developer module in SG-Admin. The module renders three primary views — the key list, the key create form, and the key detail view — and exposes a small set of write operations for create, scope edit, rotate, revoke, and permanent delete.
The module is paired by convention: one half renders the views and prepares the data, the other half handles writes and returns AJAX responses. Engineers reading the source will see this split across two controller files; the reference below describes the combined surface as it appears to a calling integration.
A second surface — scope catalog — lives adjacent to the API Keys module under Settings → Roles. Scopes are defined there; the API Keys module references them by slug. A new scope shows up automatically in the create form once it has been added to the catalog.
Where it lives in SG-Admin:
- Sidebar: SG-Admin → Settings → Developer → API Keys
- URL prefix:
/sg-admin/api-keys/ - View templates:
application/views/Admin/ApiKeys/
┌────────────────────────────────────────────────────────────────────────────┐│ SG-Admin → Settings → Developer → API Keys [+ New key] │├────────────────────────────────────────────────────────────────────────────┤│ Label Scope Last used Status ││ ────────────────── ─────────────── ─────────────── ────────────────────││ Zapier integration read:content 2 min ago active ││ CI publish bot write:posts 14 min ago active ││ Legacy mobile app read:content 32 days ago active ││ Old import script admin:full never revoked ││ Vendor sync read:orders yesterday rotating ││ ││ [⋯ Detail] [⋯ Rotate] [⋯ Revoke] │└────────────────────────────────────────────────────────────────────────────┘Actions
The API Keys surface exposes the following operations. Each is described by what it does to the data, not by its internal method name.
List and filter
Returns the keys visible to the current operator, paginated, with label / scope / last-used / status columns. Supports column sort, free-text filter across label, and scope-based filter. The list view never exposes the secret value of a key — only its label, prefix, and metadata.
Create key
Opens an empty create form. Required fields: label, scope set, expiry preference (never / 30 / 90 / 365 days). Optional fields cover description, IP allowlist, and per-environment tag (production / staging / sandbox). On submit, the surface generates a fresh secret, persists the hashed form of it, and returns the plaintext secret exactly once — in the success response. The plaintext is never re-shown.
Engineering note — the one-shot reveal is a hard property of the surface. A second GET on the same key returns metadata only, with the secret field omitted. Integrations that lose the plaintext must rotate, not re-fetch.
View key detail
Loads the metadata for a single key: label, scope set, expiry, IP allowlist, environment tag, created-by operator, last-used timestamp, last-used IP, and the action vocabulary the key has invoked (derived from Activity Log). The plaintext secret is not part of the response.
Edit scope
A focused write path. Accepts a new scope set for an existing key, validates that every requested scope exists in the catalog, and rewrites the binding. The secret value is unchanged; only the bound scope set updates. Takes effect on the next authenticated call — there is no cache to flush.
Rotate
Generates a fresh secret for an existing key while keeping the label, scope, and IP allowlist intact. The new plaintext is returned exactly once in the rotate response. The old secret transitions to a grace state where it continues to authenticate for a configurable overlap window (default 24 hours), then hard-revokes. Used when a secret leaks or when periodic rotation policy fires.
Revoke
Marks a key inactive. The secret stops authenticating immediately — no grace window. The record stays in the database for audit purposes; subsequent calls return a structured rejection naming the revoked state. Revoke is reversible up to permanent delete via the Restore entry on the key detail view.
Permanent delete
Hard-removes a revoked key. Available only after a revoke. This path is irreversible and is intentionally separated from revoke so that the audit trail survives operator panic.
Inspect last-used
A read-only diagnostic. Returns the last-used timestamp, the last-used IP, the last-used action slug, and a recent-activity tail (last 25 calls). Used during incident review when the question is "is this key in use?" before a planned revoke.
Data model
An API key record carries the following fields. Field names below are the conceptual shape — the on-disk column names match closely but are not contractually stable across releases.
| Field | Type | Notes |
|---|---|---|
id | integer | Primary key. Stable across rotations. |
label | string | Operator-set display name. Not unique. |
prefix | string | First 8 characters of the secret. Shown in lists for visual matching against logs. |
secret_hash | string | Salted hash of the full secret. Never exposed in any read response. |
scope | array | List of scope slugs. Validated against the Settings → Roles catalog. |
status | enum | active, rotating, revoked, expired. |
expires_at | timestamp | Null if "never". |
ip_allowlist | array | Optional. CIDR ranges. Empty = no IP restriction. |
environment | enum | production, staging, sandbox. Cosmetic — does not change auth behavior. |
created_by | integer | User id of the operator who issued the key. |
last_used_at | timestamp | Touched on every successful auth. Null until first use. |
last_used_ip | string | Source IP of the most recent successful auth. |
grace_until | timestamp | During rotation, the old secret remains valid until this time. |
created_at | timestamp | Set on create, immutable. |
updated_at | timestamp | Touched on any edit. |
create and rotate and nowhere else. The database stores only the salted hash.Rotation overlap. During a rotation, both the old and the new secrets authenticate. The old secret carries grace_until; the new secret is unmarked. After the overlap window, the old secret hard-revokes.
Scope expansion. A scope set is additive. A key with read:content and write:posts can do both. Adding a new scope requires Edit scope; removing requires the same.
API KEY RECORD├── id integer primary key├── label string operator-set├── prefix string first 8 chars of secret (lookup aid)├── secret_hash string salted hash, never returned├── scope array e.g. ['read:content', 'write:posts']├── status enum active | rotating | revoked | expired├── expires_at timestamp null = never├── ip_allowlist array CIDR ranges, empty = unrestricted├── environment enum production | staging | sandbox├── created_by integer issuing operator user.id├── last_used_at timestamp touched on auth success├── last_used_ip string source IP of last auth├── grace_until timestamp during rotation only└── timestamps created_at, updated_at↓ on rotateNEW SECRET ISSUED (returned once)OLD SECRET → status=rotating, grace_until=now+overlap↓ after overlap windowOLD SECRET → status=revokedPermissions
Access to the API Keys surface is gated at two layers.
Layer 1 — admin gate. Every action under SG-Admin passes through the platform's standard admin access check at request entry. An unauthenticated request never reaches the API Keys surface.
Layer 2 — per-action capability. Within SG-Admin, each API Keys action checks a capability associated with the calling operator's role. The default role configuration ships with three roles — Administrator, Editor, Viewer — and the capability map is:
| Capability | Administrator | Editor | Viewer |
|---|---|---|---|
| List keys | ✔ | — | — |
| View key detail | ✔ | — | — |
| Create key | ✔ | — | — |
| Edit scope | ✔ | — | — |
| Rotate | ✔ | — | — |
| Revoke | ✔ | — | — |
| Permanent delete | ✔ | — | — |
| Inspect last-used | ✔ | — | — |
| View own keys (self-issued) | ✔ | ✔ | — |
Self-protection rules. An operator cannot create a key with a scope they themselves do not hold. The surface returns a structured rejection naming the missing capability. An operator cannot revoke a key in a different environment from the one they are signed into when environment isolation is enabled under Settings → Security.
Audit. Every write — create, edit scope, rotate, revoke, permanent delete — emits an Activity Log entry. The log records the acting operator, the key identifier (label + prefix, never the secret), and the change shape. Reads of the key list and detail are not logged; calls authenticated by the key itself are logged with source = api.
REQUEST│▼┌───────────────────────────┐│ Admin gate │ unauth → reject│ (every /sg-admin/* call) │└─────────────┬─────────────┘│ authed▼┌───────────────────────────┐│ Capability check │ role lacks cap → reject│ (per-action) │ (custom roles override defaults)└─────────────┬─────────────┘│ allowed▼┌───────────────────────────┐│ Scope-floor rule │ requested scope exceeds│ (create / edit scope) │ operator's own → reject└─────────────┬─────────────┘│ passes▼action executes│▼Activity Log entry(label + prefix only, never secret)Related references
- Settings — Reference. Owns the scope catalog, the rotation overlap window, the environment isolation flag, and the IP allowlist defaults. Changes there reshape what API Keys can request.
- Roles — Reference. Defines the scope slugs that this surface binds against. New scopes added under Roles flow automatically into the API Keys create form.
- Permissions — Reference. Per-endpoint capability mapping. API Keys carry scopes; scopes resolve to capabilities at request time.
- Integrations — Reference. Pre-built integrations (Zapier, webhooks, OAuth clients) provision their own API keys through this surface but may layer additional metadata.
- Activity Log — Reference. Source of last-used data, source of the rotation / revoke audit trail. Every key write emits an entry; every authenticated call emits an entry with source =
api. - Users — Reference. A key's
created_byreferences a user record. Soft-deleting the issuing user does not revoke their keys — a separate cleanup workflow handles that under Settings → Security.
/docs/api-keys.