Authentication
The Recruso API uses bearer tokens. Every business operation requires an
Authorization: Bearer {token} header, and the token is bound to the agency that owns your API app —
which is what scopes every request you make.
Getting one takes a single call, using a client id and secret issued from the Developer Console.
Before you start
Section titled “Before you start”You need an API app’s client id and client secret. You don’t need a Recruso account yourself — someone at the agency creates the app in the Developer Console and gives you the credentials. Access to the console comes with a Recruso CRM licence and the right role, so it’s whoever administers the agency’s Recruso account.
The secret is shown once, at issue. If it is lost, issue a new one — it cannot be retrieved.
1. Exchange your client credentials
Section titled “1. Exchange your client credentials”The client id and secret go in the body — not in the header, and not as basic auth.
POST /apiauthContent-Type: application/json
{ "clientId": "42.0f7b9c2e-…", "clientSecret": "…", "grantType": "client_credentials"}{ "accessToken": "eyJhbGciOi…", "expiresIn": 3600, "tokenType": "Bearer"}grantType must be client_credentials; no other grant type is supported. expiresIn is the token
lifetime in seconds — read it rather than hardcoding a value, and request a new token once it
elapses rather than on every call. It is one hour today; treat that as a fact about this response,
not a guarantee.
The client id looks like 42.0f7b9c2e-…. Treat it as opaque. Copy it whole from the console:
every character is significant, and editing any part of it only makes the exchange fail. It grants
nothing on its own — your secret is what authenticates you.
A client id and secret are issued as a pair, so a new secret arrives with a new client id. Change
both together; see Rotate API credentials. A credential can
also carry an expiry date, which is visible in the console — an untouched integration can start
returning 401 because its credential lapsed rather than because anything changed on your side.
When the exchange fails
Section titled “When the exchange fails”Two different statuses, and the difference tells you where to look.
400 means the request was the wrong shape, and no credential was looked up at all: a malformed
client id, a missing or empty clientSecret, or a grantType other than client_credentials. The
body is a Problem Details document naming the offending field. Fix the payload — retrying it
produces the same failure.
401 means the request was well formed but the credential was refused. An unknown client id, a
wrong secret, a revoked or expired credential, an inactive app, a caller outside the app’s
configured IP allow-list, and an app whose owning Recruso user has been disabled all return the
same 401 with an empty body, deliberately not distinguished — telling them apart would let anyone
test which client ids exist. There is nothing to parse, so branch on the status code. Unlike a 401
from a business operation, this one carries no WWW-Authenticate header.
2. Call the API
Section titled “2. Call the API”GET /v1/branchesAuthorization: Bearer {accessToken from /apiauth}There is no agency parameter anywhere in this API. The token decides which agency’s data you see; see Agencies.
Handling credentials
Section titled “Handling credentials”- Always use HTTPS. Tokens are bearer credentials: anyone holding one can act as your integration.
- Never embed a client secret in a browser or mobile client. Exchange credentials server-side and keep the resulting token there.
- Store the secret somewhere you can change without a redeploy — a secret store, an environment variable, a configuration record. A secret baked into a build artefact is what turns a routine rotation into an outage.
- Treat the access token as a credential too. It is valid until it expires and cannot be revoked individually; do not paste one into a ticket, a chat message or a log.
- Rotate through the Developer Console. Rotation does not require downtime — see Rotate API credentials.
Environments and base URLs — where these calls actually go.

