API Keys
API keys allow your systems and third-party tools to authenticate with the PurpletGo API without a user session. They are ideal for server-to-server integrations, HRIS webhook bridges, and automation pipelines.
For a general overview of authentication, see Authentication.
Key format
All PurpletGo API keys follow the same format: fnl_, an environment segment, then 32 hex characters.
| Prefix | Environment |
|---|---|
fnl_live_ | Production |
fnl_test_ | Sandbox / staging |
Only the raw key's prefix (the first 12 characters, e.g. fnl_live_a1b) is stored for display - PurpletGo never stores or shows the full value again after creation.
An organisation can have at most 20 active keys at a time; creating a 21st fails until you revoke an unused one.
Scopes
Every API key is created with one or more scopes. Requests are rejected with 403 Forbidden if the key does not carry the required scope for the endpoint being called.
| Scope | Description |
|---|---|
offboardings:read | List and view offboarding records |
offboardings:write | Create offboardings and update their status |
employees:read | List employees |
webhooks:read | List registered webhooks |
webhooks:write | Create and delete webhooks |
Grant only the scopes your integration actually needs. A key with offboardings:write can trigger live offboarding workflows. Never embed production keys in client-side code or public repositories.
Endpoints
These management endpoints are for the PurpletGo dashboard itself - you authenticate with your regular session (cookie or Bearer JWT), not an API key, and they live under /api/keys rather than /api/v1.
List API keys
GET /api/keys
Returns all API keys for your organisation, most recently created first. Key values are never returned - only the stored prefix.
Required role: superadmin, admin, or hr.
Response 200 OK - a plain array, not wrapped in data/total:
[
{
"id": "3f9c8b1a-...",
"name": "BambooHR Webhook Bridge",
"key_prefix": "fnl_live_a3f",
"scopes": ["offboardings:write", "employees:read"],
"last_used_at": "2025-06-24T14:05:33Z",
"expires_at": null,
"revoked_at": null,
"created_at": "2025-03-12T08:22:00Z",
"created_by_name": "Jane Smith"
}
]Create an API key
POST /api/keys
Creates a new API key. The full key value is returned only in this response, in the raw_key field - store it immediately in a secrets manager.
Required role: superadmin, admin, or hr.
Request body
{
"name": "Workday Offboarding Trigger",
"scopes": ["offboardings:write", "employees:read"],
"expires_at": "2026-12-31T00:00:00Z"
}| Field | Required | Type | Description |
|---|---|---|---|
name | ✅ | string | Label shown in the dashboard (max 80 characters) |
scopes | - | string[] | Defaults to all scopes if omitted |
expires_at | - | date-time | Must be in the future; omit for a key that never expires |
Response 201 Created
{
"id": "6a1e2d90-...",
"name": "Workday Offboarding Trigger",
"key_prefix": "fnl_live_kx9",
"scopes": ["offboardings:write", "employees:read"],
"expires_at": "2026-12-31T00:00:00Z",
"created_at": "2025-06-26T10:00:00Z",
"raw_key": "fnl_live_kx9mrpwqlzdvntyja2cbs7hueog3"
}The raw_key field is returned exactly once. PurpletGo does not store the plaintext value. If you lose it, revoke the key and generate a new one.
An organisation is capped at 20 active keys - creating another returns 400 until you revoke one.
Revoke an API key
DELETE /api/keys/{keyId}
Immediately invalidates the API key. Any in-flight requests using this key will receive 401 Unauthorized. This action is irreversible.
Required role: superadmin, admin, or hr.
Response 200 OK
{ "message": "API key revoked" }Returns 404 if the key doesn't exist in your organisation or was already revoked.
Using a key in requests
Pass the API key in the Authorization header as a Bearer token on every request:
curl https://app.purpletgo.com/api/v1/offboardings \
-H "Authorization: Bearer fnl_live_kx9mrpwqlzdvntyja2cbs7hueog3" \
-H "Content-Type: application/json"Error responses
| Status | Meaning |
|---|---|
401 | Missing, malformed, revoked, or expired API key |
403 | Key doesn't carry the scope required for the endpoint |
429 | Key has exceeded 120 requests per 60 seconds |
Every error follows the standard { "error": "..." } shape - see Errors & Rate Limiting.
Related
- Authentication - key format and session auth concepts
- Errors & Rate Limiting - error shape and per-key rate limits
- Webhooks - deliver events to your own endpoints