Exchange client credentials for an access token
const url = 'https://api2.recruso.co.uk/apiauth';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"clientId":"42.0f7b9c2e-8a41-4d6b-9f30-1c5ea7b8d902","clientSecret":"cs_RVhBTVBMRS1PTkxZLW5vdC1hLXJlYWwtc2VjcmV0LTAwMDAwMDAwMDAwMDAwMDAw","grantType":"client_credentials"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api2.recruso.co.uk/apiauth \ --header 'Content-Type: application/json' \ --data '{ "clientId": "42.0f7b9c2e-8a41-4d6b-9f30-1c5ea7b8d902", "clientSecret": "cs_RVhBTVBMRS1PTkxZLW5vdC1hLXJlYWwtc2VjcmV0LTAwMDAwMDAwMDAwMDAwMDAw", "grantType": "client_credentials" }'Exchanges the client id and secret issued to your API app for an access token. Every business operation in this API requires the resulting token in an Authorization: Bearer {token} header.
No sign-in is required. The client id and secret go in the request body, not the header, and authenticate the call on their own. Both are issued from the Recruso Developer Console, not through this API.
grantType must be client_credentials. The token is bound to the agency that owns the API app, which is what scopes every subsequent request — you never pass an agency id yourself. Writes are attributed to the Recruso user the app belongs to.
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, or an app whose owning user has been disabled all return 401 without distinguishing between them.
This endpoint is rate limited. Read expiresIn and request a new token only once the current one elapses — exchanging credentials before every call returns 429.
Access. This endpoint does not require authentication.
Authorizations
Section titled “Authorizations”- None
Request Bodyrequired
Section titled “Request Bodyrequired”Client-credentials token request.
object
The client id of the credential issued to your API app. Treat it as opaque: copy the whole value from the Developer Console rather than assembling or editing it, because every character is significant and altering any part only causes the exchange to fail. It is issued as a pair with the client secret, so a new secret comes with a new client id. It is not a secret itself and grants nothing on its own.
Example
42.0f7b9c2e-8a41-4d6b-9f30-1c5ea7b8d902The secret paired with ClientId. Shown once, at issue, and never retrievable afterwards. Never embed this in a browser or mobile client — exchange it server-side and keep the resulting token there.
Example
cs_RVhBTVBMRS1PTkxZLW5vdC1hLXJlYWwtc2VjcmV0LTAwMDAwMDAwMDAwMDAwMDAwMust be client_credentials. No other grant type is supported, and any other value is rejected with 400 before the credential is looked up.
Example
client_credentialsResponses
Section titled “Responses”OK
A successfully issued access token.
object
The bearer token to send as Authorization: Bearer {token} on every other request. It is bound to the agency that owns the API app, which is what scopes each request — there is no agency parameter anywhere in this API.
Lifetime of the token in seconds. Read this rather than hardcoding a value — it is the authoritative figure and it can change. Request a new token once it elapses, not before every call: this endpoint is rate limited.
The token scheme. Always Bearer.
Example
{ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvd25lcl9pZCI6IjQyIn0.J1v3xQ8pN2mKb7Yc4Fd9aR", "expiresIn": 3600, "tokenType": "Bearer"}Bad Request
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}Unauthorized
Too Many Requests
object
Examplegenerated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example"}
