Authentication
The TreasurySpring Public API uses OAuth 2.0. Every request is authenticated with a bearer access token obtained from the /oauth/token endpoint. Two integration flows cover the different ways partners connect, and they use three OAuth grant types between them:
| Grant type | Used by | Purpose |
|---|---|---|
client_credentials | Client Credentials flow | Exchange a client_id / client_secret for an access token. |
authorization_code | Code Authorisation flow | Exchange a per-user consent code for an access token. |
refresh_token | Code Authorisation flow | Extend a user's session without re-prompting for consent. |
Client Credentials has no refresh token — you re-request with the same credentials — so the refresh_token grant applies only to Code Authorisation.
Pick a grant type
| Grant type | Use case |
|---|---|
| Client Credentials | A TreasurySpring user accessing their own data. The credentials are issued by the entity owner and represent that user. Each call is logged as that user. |
| Code Authorisation (Auth Code + PKCE) | A partner system integrating shared users with TreasurySpring — typically when end-users of the partner platform should each act with their own TreasurySpring identity. |
Client Credentials — when
- A treasurer at one organisation wires their own TMS into TreasurySpring.
- A back-office team builds an internal dashboard.
- A scheduled reporting job runs against the API.
The credential is generated in the portal: Account Information → Developer Settings → Generate client_id / client_secret. One credential pair can be granted access to multiple entities the user is permissioned on — in that case, each request specifies entityCode to scope the action.
Exchange the credentials for an access token, authenticating the client with HTTP Basic auth (client_id:client_secret, base64-encoded):
- cURL
- Python
curl --location 'https://api.treasuryspring.com/oauth/token' \
-H 'Authorization: Basic <base64_client_id_and_secret>' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=<client_id>' \
--data-urlencode 'client_secret=<client_secret>'
import base64
import requests
basic = base64.b64encode(b"<client_id>:<client_secret>").decode()
resp = requests.post(
"https://api.treasuryspring.com/oauth/token",
headers={
"Authorization": f"Basic {basic}",
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"grant_type": "client_credentials",
"client_id": "<client_id>",
"client_secret": "<client_secret>",
},
)
access_token = resp.json()["access_token"]
Send the returned access_token as Authorization: Bearer <access_token> on API calls. See the Quickstart for an end-to-end worked example.
Code Authorisation — when
- A multi-tenant treasury platform offers TreasurySpring as one of several investment venues, and wants each end-user's TreasurySpring actions to be attributed to that user.
- A partner application needs per-user audit trails in TreasurySpring rather than rolling everything up under a single service identity.
Code Authorisation clients are provisioned by TreasurySpring — contact your account manager to set up client credentials and register your redirect URIs (a client may have more than one). After the end-user consents, your application receives a short-lived code at your redirect_uri, which you exchange for an access token:
- cURL
- Python
curl --location 'https://api.treasuryspring.com/oauth/token' \
-H 'Authorization: Basic <base64_client_id_and_secret>' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=<client_id>' \
--data-urlencode 'code=<authorization_code>' \
--data-urlencode 'redirect_uri=<redirect_uri>'
resp = requests.post(
"https://api.treasuryspring.com/oauth/token",
headers={
"Authorization": f"Basic {basic}",
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"grant_type": "authorization_code",
"client_id": "<client_id>",
"code": "<authorization_code>",
"redirect_uri": "<redirect_uri>",
},
)
tokens = resp.json()
Include redirect_uri matching the one used to obtain the code — it is required when your client has more than one registered redirect URI. The full browser consent flow, redirect URI rules, and this requirement are covered in the Code Authorisation flow guide.
Trusted-system vs impersonation patterns
When a partner platform integrates on behalf of multiple end-users, there are two architectural patterns to choose between. They differ in whose name appears in the TreasurySpring audit trail.
Trusted-system pattern — the partner authenticates with a single Client Credentials token and calls the API on behalf of all its users. Every TreasurySpring audit log entry is attributed to the partner system, not the individual end-user. The partner system is responsible for maintaining its own internal mapping between end-users and the actions they triggered.
- Simpler to operate (one credential).
- TreasurySpring side sees one actor; the partner is the system of record for who did what.
Impersonation pattern — the partner uses Code Authorisation to obtain a token per end-user. Each TreasurySpring action is attributed in TreasurySpring's audit log to the individual user.
- TreasurySpring is the system of record for who did what.
- More setup; each user goes through an OAuth consent flow.
For regulated environments where end-user attribution is a compliance requirement, the impersonation pattern is usually the right fit.
Base URLs
| Environment | API base | OAuth token endpoint |
|---|---|---|
| Production | https://api.treasuryspring.com/api/v1 | https://api.treasuryspring.com/oauth/token |
| Sandbox | https://api.sandbox.treasuryspring.com/api/v1 | https://api.sandbox.treasuryspring.com/oauth/token |
Please note that the OAuth token endpoints sit at the root of each environment, not under /api/v1 — they are routed differently from the API endpoints. Constructing the token URL by concatenating the API base with /oauth/token will return a 404, so it's worth taking the URLs above as-is.
Token lifetime and refresh
Access tokens are returned by the /oauth/token endpoint with an expires_in value (in seconds). The typical lifetime is several hours, but we recommend reading expires_in and refreshing before it expires rather than hard-coding the lifetime in your client.
For Client Credentials, refresh means "request a new token using the same credentials". There is no separate refresh token; the same client_id / client_secret can be re-exchanged on demand. Tokens are reusable until they expire, so caching and reusing the token across calls is more efficient than requesting a new one per API call.
For Code Authorisation, a refresh token is issued alongside the access token and should be used to extend a session without re-prompting the end-user. Exchange it with the refresh_token grant (no redirect_uri is needed):
- cURL
- Python
curl --location 'https://api.treasuryspring.com/oauth/token' \
-H 'Authorization: Basic <base64_client_id_and_secret>' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'client_id=<client_id>' \
--data-urlencode 'refresh_token=<refresh_token>'
resp = requests.post(
"https://api.treasuryspring.com/oauth/token",
headers={
"Authorization": f"Basic {basic}",
"Content-Type": "application/x-www-form-urlencoded",
},
data={
"grant_type": "refresh_token",
"client_id": "<client_id>",
"refresh_token": "<refresh_token>",
},
)
tokens = resp.json()
A new access token and refresh token are returned; store the rotated refresh token for the next cycle.
Sandbox API keys (testing convenience)
Alongside OAuth, the sandbox environment supports an API key mode for ease of testing — you can generate one from the portal's Developer Settings under the sandbox environment. The API key is sent as Authorization: Bearer <key> and bypasses the token exchange. For production data, OAuth is required.
Worked example
- Quickstart — end-to-end token exchange and authenticated call.
- Sandbox guide — getting credentials.
- Errors & responses — what auth failures look like and how to recover.