API keys — generation, scopes, rotation
API access is an Enterprise and Government feature. Keys are workspace-scoped, scope-restricted, and rate-limited per key. Generation, rotation, and revocation are self-serve at /settings/api-keys.
Generation
- Open
/settings/api-keysand fill in the new-key form. - Name the key (free-text label; recorded in the audit log).
- Select scopes — see below. The form requires at least one scope.
- Optionally set an expiry. If you leave it empty, the key expires 365 days after issuance — set an explicit expiry (or rotate before it lapses) if you need a different lifetime.
- Click Create key. The full key is shown once. Copy it; we do not store the plaintext. If you lose it, rotate.
Keys have the wire format fg_live_<14-char prefix>_<32-char secret>. The fg_live_ namespace is the only one issued — there is no separate sandbox/test prefix. Characters are drawn from an unambiguous lowercase-alphanumeric alphabet (no 0, 1, l, i, o).
Scopes
Scopes are additive — a key gets exactly what you grant.
| Scope | What it unlocks |
|---|---|
briefs:read | Brief read endpoints |
search:read | Search endpoints |
notices:read | Notice read endpoints |
entities:read | Entity / relationship-graph read endpoints |
agencies:read | Agency read endpoints |
forecasts:read | Forecast read endpoints |
opportunities:read | Opportunity read endpoints |
pwin:assess | pWin assessment |
exports:read | Export read endpoints |
v1 is read-plus-assess. There are no write scopes — the list above is the complete, enforced set (V1_SCOPES in lib/auth/api-keys.ts). No v1 endpoint mutates workspace state through an API key.
Keys issued before the v1 taxonomy carry legacy scope strings (read:brief, read:search, read:forecast, read:network) which alias forward to their v1 equivalents, so old keys keep working.
Two wildcard scopes exist and satisfy every scope check: * and api:full. Grant them only when a narrower set genuinely will not work.
Rate limits
Rate limiting is per key, per minute, per route budget — the budget name depends on which endpoint you call. There is no per-day workspace ceiling and no tier-differentiated per-minute number today.
GET /api/v1/search, /notices, /opportunities, /forecasts, /entities/{id} and /agencies/{slug} all share ONE budget, named "search" (60 admissions/minute, per key). Calling five of those routes in the same minute draws down the same 60-request allowance, not five independent ones. Two routes have their own, smaller budgets: GET /api/v1/briefs uses the synthesize budget (10/minute per key) and POST /api/v1/pwin uses the query budget (30/minute per key).
Every v1 response — success or error — carries the current state of your budget:
X-RateLimit-Limit— the budget ceiling for the route you called (60 for the sharedsearchbucket, 10 for briefs, 30 for pWin).X-RateLimit-Remaining— admissions left in the current window, after this request.X-RateLimit-Reset— Unix epoch seconds when the window rolls over.
A 429 additionally carries Retry-After in seconds; honor it and back off exponentially.
Rotation
Click Rotate on the key's row at /settings/api-keys, which calls the rotate_api_key database function so the issue-new/revoke-old pair commits atomically — a mid-rotation crash cannot leave two live keys or zero. A new key is issued carrying the old key's scopes and expiry, and the old key is revoked immediately — there is no grace window. Stage the new secret in your secrets manager before you rotate.
Revocation
Click Revoke on the key's row at /settings/api-keys. Revocation is immediate — the next request from the revoked key returns 401 with error code unauthenticated, the same response as any unknown key. Revocation is recorded in the workspace audit log.
Best practices
- One key per integration. Never share keys across services.
- Store in your secrets manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault). Never commit to source control.
- Set the narrowest scopes the integration needs. A Brief mirror needs
briefs:read, not a wildcard. - Rotate on a regular schedule, for example quarterly.
/settings/api-keysshows each key's expiry and its last-24-hour usage per endpoint.
See Webhooks for the event-driven counterpart and The REST API v1 for the endpoints.
Last updated 2026-09-21.