API keys allow automated systems to interact with Forgecroft. Every key has three dimensions of control: where it can act, what it can do, and which capabilities it holds.
Creating an API Key
For interactive use, forgecroft login handles key creation automatically (see CLI Reference).
To create a key programmatically, use POST /api-keys:
{
"name": "CI/CD Pipeline",
"scope_type": "project",
"scope_id": "project-uuid",
"action_scope": "write"
}
Important: The raw key value (fc_live_...) is returned only once at creation time. After that, only a masked version (****xxxx) is available. Store it securely.
Scope Type
Controls which resources the key can access:
| Scope Type | Access |
|---|---|
org | All resources in the organization |
project | Only the specified project and its workspaces |
workspace | Only the specified workspace |
When creating a project- or workspace-scoped key, you must provide the scope_id (UUID of the resource).
Action Scope
Controls the level of access:
| Action Scope | Capabilities |
|---|---|
read | Read-only access to resources within scope |
write | Read + write (create, update, trigger runs) |
admin | Full access including member and key management |
Capability Scopes
Fine-grained permissions that control access to specific API capabilities:
| Capability | Description |
|---|---|
api_keys:read | List and view API keys |
api_keys:write | Create and manage API keys |
members:read | View org members |
members:write | Manage org members |
vcs:write | Manage VCS integrations |
credentials:write | Manage credential configs |
billing:read | View billing status |
If no capability scopes are specified, the key is a legacy key with full access to all capabilities. Scoped keys must explicitly list each capability.
Verb Scopes
API keys can also have verb-based scopes that control which run operations they can perform:
| Verb Scope | Allows |
|---|---|
trigger | Trigger plan runs |
apply | Apply completed plans |
approve | Approve or reject runs |
read | Read workspace and run data |
admin | Manage workspace settings |
Verb scopes are specified in the scopes array alongside capability scopes:
{
"name": "CI Pipeline",
"scope_type": "project",
"scope_id": "project-uuid",
"action_scope": "write",
"scopes": ["trigger", "read"]
}
This key can trigger plans and read results, but cannot approve runs, apply changes, or manage workspace settings.
Recommended scopes by use case
| Use Case | Scopes |
|---|---|
| CI/CD pipeline (trigger only) | ["trigger", "read"] |
| Deploy pipeline (plan + apply) | ["trigger", "apply", "read"] |
| Approval bot | ["approve", "read"] |
| Read-only dashboard | ["read"] |
| Full automation | ["trigger", "apply", "approve", "read"] |
How Scopes Interact
When an API key has both an action scope and capability/verb scopes, both must be satisfied for a request to succeed. For example:
- A key with
action_scope: "admin"andscopes: ["api_keys:read"]can only read API keys — the capability scopes restrict it despite the admin action scope. - A key with
action_scope: "read"andscopes: ["trigger"]cannot trigger runs because the action scope blocks write operations.
If scopes is empty (legacy key), only the action scope is checked.
Anti-Escalation
API keys cannot create child keys with more permissions than they hold:
- A scoped key can only create child keys whose capability scopes are a subset of its own
- A legacy key (empty scopes) can create any type of child key
- A scoped key can never create a legacy (empty-scope) key — even if it holds broad scopes, it cannot escalate to unrestricted access
Key Lifecycle
- Create —
POST /api-keys, store the raw key value - Use — Pass as
Authorization: Bearer fc_live_... - Suspend —
PATCH /api-keys/{id}with{"suspended": true}to temporarily disable - Resume —
PATCH /api-keys/{id}with{"suspended": false} - Delete —
DELETE /api-keys/{id}to permanently revoke
Suspended keys are immediately rejected with a clear error. Suspension is reversible — use it for temporary disabling without losing the key.
Expired keys are silently rejected (same error as an invalid key). Expiration is checked at request time, not proactively.
Auditing Key Usage
Every API key tracks last_used_at — the timestamp of the last successful request. Use this to identify stale keys:
GET /api-keys
Review keys where last_used_at is null or older than 90 days. Consider suspending keys that are no longer in active use.
Only admins or the key creator can view a specific key’s full metadata via GET /api-keys/{id}.
Incident Response: Leaked Key
If a key is compromised:
- Suspend immediately —
PATCH /api-keys/{id}with{"suspended": true}. This blocks the key within seconds without permanent deletion. - Audit usage — Check
last_used_atand review recent run activity filtered to the affected workspaces. - Create a replacement — Issue a new key with the same scopes.
- Delete the leaked key — Once you’ve confirmed the replacement is deployed, permanently delete the old key.
Suspend first, investigate second. Suspension is instant and reversible; deletion is permanent.
Key Rotation
To rotate a key without downtime:
- Create a new key with the same scopes
- Deploy the new key to your clients
- Monitor
last_used_aton the old key until it stops being used - Delete the old key
Principal Types
API keys can be attributed to different principals for audit trail purposes:
| Principal Type | Use Case |
|---|---|
org | Service accounts owned by the organization (CI/CD, bots) |
user | Keys attributed to a specific person (personal automation) |
team | Keys shared by a team (team-level automation) |
Non-admin callers can only create user-principal keys for themselves. Admins can create keys for any principal type and any user.
Choose org for shared automation (the key outlives any individual). Choose user when audit trail attribution matters. Choose team for team-scoped tooling.
Expiration
Keys can be set to expire with expires_in_days. If not specified, the key never expires.
Expired keys fail silently with an “invalid api key” error (identical to a revoked key). Track expires_at in your key inventory and rotate before expiry.
Related API Endpoints
POST /api-keys— Create an API keyGET /api-keys— List all API keys for the org (requiresapi_keys:readcapability)GET /api-keys/{id}— Get a single key’s metadata (admin or key creator only)PATCH /api-keys/{id}— Suspend or unsuspend a key (requiresapi_keys:writecapability)DELETE /api-keys/{id}— Revoke a key (requiresapi_keys:writecapability)GET /whoami— Verify which key is currently authenticated