Authentication
OAuth 2.0 client-credentials (machine-to-machine) with per-scope access.
Authentication
The Integrated API uses OAuth 2.0 client credentials (RFC 6749 §4.4). Your client is a machine identity bound to one CPO partner — there is no end user behind the token.
Get your credentials
Joulo provisions an OAuth client for your partner and gives you a client_id
and client_secret, plus the scopes your integration needs. The secret is
shown once.
Store the client_secret in a secrets manager. If it leaks, ask Joulo to
rotate it • the old secret stops working immediately.
Request a token
POST https://api.joulo.nl/functions/v1/oauth-token
curl -X POST https://api.joulo.nl/functions/v1/oauth-token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "your-client-id",
"client_secret": "your-client-secret"
}'{
"access_token": "9f456b04e72e749c...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "cpo:accounts:write cpo:mandates:write cpo:sessions:write cpo:chargers:write"
}The token is valid for one hour. There is no refresh token — for machine-to-machine access you simply request a new token when the old one expires (re-presenting your credentials).
You may narrow a token to a subset of your scopes by passing a
space-separated scope parameter; omit it to receive all scopes granted to
your client.
Call the API
Send the token as a bearer token on every request:
curl https://api.joulo.nl/functions/v1/api/v1/accounts \
-H "Authorization: Bearer 9f456b04e72e749c..."Scopes
Access is fail-closed: an endpoint you lack the scope for returns
403 Insufficient scope, and unknown routes return 404.
| Scope | Grants |
|---|---|
cpo:accounts:read | GET /v1/accounts |
cpo:accounts:write | POST /v1/accounts |
cpo:mandates:write | POST /v1/mandate-links |
cpo:chargers:write | POST /v1/chargers |
cpo:sessions:write | POST /v1/sessions:batch |
Errors
| HTTP | error | Meaning |
|---|---|---|
| 400 | unsupported_grant_type | grant_type must be client_credentials |
| 400 | unauthorized_client | Your client isn't provisioned for client credentials |
| 400 | invalid_scope | Requested scope exceeds what your client was granted |
| 401 | invalid_client | Unknown client or wrong secret |
| 403 | cpo_token_required | The /v1 API needs a client-credentials token |
| 403 | client_not_linked | Your client isn't linked to a partner yet — contact Joulo |