Authentication

The Staff & Go API is an OAuth 2.0 resource server. Your application authenticates as itself with the client credentials grant — there is no end-user login, no redirect, no refresh token.

Getting a token

Credentials are issued per environment by Staff & Go. Exchange them at the authorization server:

curl -X POST "https://<authorization-server-host>/realms/staffngo-partners/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET"

Send the token on every call:

Authorization: Bearer <access_token>

Mint a new token shortly before the current one expires. Tokens are cheap; a wave of retries triggered by simultaneous expiry is not, and it counts against your rate limit.

Scopes

Each endpoint declares the scopes it requires; the API reference lists them per operation.

Scope Grants
external-api Base access to the API.
partner:read Read your own partner profile.
leaves:read Read leave data.
leaves:write Create or modify leave data.
payroll:read Read payroll data.
payroll:trigger Trigger payroll distribution.
referentials:read Read the referentials, platform-wide ones as well as the company's — see Discovery.
audit-entries:read Read your own audit trail — see Audit trail.
beta:access Call endpoints marked Beta — none today, see Lifecycle.

Do not add a scope parameter to the token request. The scopes granted to your application are attached to your credentials and enter the token without being asked for.

Naming them is in fact risky: the authorization server refuses the whole request as soon as one named scope is no longer granted — invalid_scope, no token at all, and a message listing every scope you asked for rather than the one that went away.

⚠️ This bites hardest in the API reference on this site. Its "Authorize" panel builds its scope list from the published contract, which names every scope this API knows — including the field sub-scopes (employments:read:compensation, leaves:read:reason, payroll:read:amounts). They are listed so you can discover what releases a field, not because you hold them: a sub-scope is granted only on a stated need, and leaves:read:reason covers health data under Article 9. Ticking everything there gets you no token at all. Leave the selection empty, or tick only what you know was granted to you.

A token that lacks a required scope gets 403 with type = scopes/insufficient, and the detail names the missing scope.

After any change to your scopes, request a new token. When the client company's administrator withdraws one, the tokens already issued are disowned: they get a 401, not a 403, because they were signed under a grant that is no longer yours. Waiting does not bring them back, and granting the scope again does not revive them either — only a token minted after the change carries your current rights. If your calls start returning 401 with no explanation, that is the first thing to try.

Confirming what your token carries

GET /api/v1/client/partner/profile returns the identity the API resolved: your partner id, the customer tenant your calls act on, and the scopes actually present on the token. It is the fastest way to diagnose a 403. Version 2 of that endpoint adds the plan, the requester and the module states — see Discovery.

Legacy tokens — deprecated

Integrations predating OAuth issue a BearerClient token from /api/v1/token. It still works, and it is deprecated: new integrations must not use it.

It is not merely older — it behaves differently in ways that will not be carried forward:

To migrate, request partner credentials from Staff & Go, swap the token acquisition for the client credentials call above, and keep the rest of your integration unchanged — the endpoints and their contracts are identical.

Keeping the secret safe

The client secret authenticates your application on its own. Keep it server-side, out of browsers, mobile apps, repositories and logs. If it leaks, ask Staff & Go to rotate it — a rotated secret invalidates the old one immediately.