Authentication

Create an API key, send it with each request, choose its scopes, and rotate or revoke it.

Every request to the GPS REST API carries an API key. A key belongs to one GPS organization, and every request made with it reads and writes that organization's data only.

Who can create keys#

Members with the Owner, Super Admin or Admin role. The Developer tab in Settings, where keys are managed, is for those roles.

Create a key#

  1. In GPS, open Settings → Developer → Keys & Webhooks.
  2. Under API Keys, select New API Key.
  3. Fill in the form:
    • Name (required, up to 100 characters), for example "Production integration"
    • Description (optional, up to 500 characters)
    • Expires At (optional). After this date the key stops working.
    • Scopes (at least one). See Scopes.
  4. Select Create Key.

GPS then shows two values. Copy both straight away: the secret is shown only once and GPS stores only a one-way hash of it.

Value Looks like Sent as
API key (key ID) emp_ followed by 28 characters X-API-Key header
Secret A 43-character random string X-API-Secret header

The Keys & Webhooks tab also shows your Organization ID. You don't need it to call the API, because the key already identifies your organization.

Send the key#

Use either form. If a request has an X-API-Key header, GPS reads the key from the two X-API-… headers and ignores Authorization.

Two headers (preferred)

HTTP
X-API-Key: emp_AbCdEfGhIjKlMnOpQrStUvWxYz12
X-API-Secret: <your secret>

Bearer token: the key ID and secret joined by a colon.

HTTP
Authorization: Bearer emp_AbCdEfGhIjKlMnOpQrStUvWxYz12:<your secret>
curl https://plan.empiraa.app/api/v1/goals \
  -H "Authorization: Bearer $GPS_API_KEY_ID:$GPS_API_SECRET"

Keep the secret on your server. The API accepts requests from browsers (it allows cross-origin requests from any origin), but anyone who can read your page's code can then use the key.

Scopes#

A key can call an endpoint only if it has that endpoint's scope. Choose the fewest scopes your integration needs.

A key's access comes from its scopes alone. It isn't narrowed by the GPS role of the person who created it, and it sees every record in the organization, including Goals, Objectives and Actions marked private in GPS.

Scope Lets the key
organization:read GET /organization
organization:write PATCH /organization
users:read GET /users, GET /users/{id}
users:write POST /users, PATCH /users/{id}, DELETE /users/{id}
goals:read GET /goals, GET /goals/{id}
goals:write POST /goals, PATCH /goals/{id}, DELETE /goals/{id}
objectives:read GET /objectives, GET /objectives/{id}, GET /goals/{goalId}/objectives
objectives:write POST /objectives, PATCH /objectives/{id}, DELETE /objectives/{id}
progress:read GET /objectives/{objectiveId}/progress
progress:write POST /objectives/{objectiveId}/progress
actions:read GET /actions, GET /actions/{id}, GET /objectives/{objectiveId}/actions, GET /goals/{goalId}/actions
actions:write POST /actions, PATCH /actions/{id}, DELETE /actions/{id}
meetings:read GET /meetings, GET /meetings/{id}
meetings:write POST /meetings, PATCH /meetings/{id}, DELETE /meetings/{id}
ideas:read GET /ideas, GET /ideas/{id}
ideas:write POST /ideas, PATCH /ideas/{id}, DELETE /ideas/{id}
comments:read GET on the /comments list of a Goal, Objective, Meeting, Action or Idea
comments:write POST on those /comments lists, and every comment DELETE

GET /api/v1 needs no scope: any valid key can call it to see its own scopes. See API info.

Rotate a key#

GPS has no in-place rotation. To rotate:

  1. Create a new key with the same scopes.
  2. Deploy the new key ID and secret to your integration.
  3. Confirm requests succeed with the new key.
  4. Revoke the old key.

Use the same approach to change a key's scopes: the settings screen doesn't edit scopes on an existing key.

Revoke a key#

In Settings → Developer → Keys & Webhooks, select the Revoke icon next to the key, then Revoke Key. The key stops working on its next request. Revoked keys stay listed under the active ones for your records; the settings screen can't reactivate them, so create a new key instead.

A key that reaches its Expires At date stops working the same way.

401 and 403 responses#

Authentication failures return the standard error body.

Status code Meaning
401 MISSING_CREDENTIALS No X-API-Key header and no Authorization: Bearer <keyId>:<secret> header.
401 MISSING_SECRET X-API-Key was sent without X-API-Secret.
401 INVALID_CREDENTIALS The key ID doesn't exist, or the secret doesn't match it.
401 KEY_INACTIVE The key has been revoked.
401 KEY_EXPIRED The key is past its expiry date.
403 INSUFFICIENT_SCOPE The key is valid but lacks the endpoint's scope.
403 ORG_MISMATCH The request named a different organization (see Organization isolation).
JSON
{
  "error": "This API key does not have the 'goals:write' scope.",
  "code": "INSUFFICIENT_SCOPE",
  "docs": "https://empiraa.com/docs/api"
}

Who a key acts as#

Records a key creates are attributed to the member who created the key, unless the request names another member with onBehalfOf. See Attribution.