---
updatedAt: 2026-10-01T08:19:54.000Z
agentTools:
  projectIndex: https://developer.spendesk.com/llms.txt
---

# How to Authenticate

Get an access token with an API key (customers) or OAuth2 (partners), how long it stays valid, and how to renew it.

Before making any other calls to our API, you first need to authenticate. This can be done in one of two ways:

* **API Key** - for Spendesk customers having API access, use this [endpoint](https://developer.spendesk.com/reference/v1-create-auth-token)
* **OAuth2** - for Spendesk partners developing an integration, use this [endpoint](https://developer.spendesk.com/reference/v1-request-authorization)

<br />

# Access Tokens

Your primary form of authenticating requests will be via an **access token**. These are temporary tokens you can retrieve via either of the above methods in order to validate subsequent requests to our other endpoints.

> 📘
>
> **Access tokens** are valid for **60 minutes, i.e. 3600 seconds**, at which point any requests using them will return a **401** error and a new token will need to be requested.
>
> :warning: As with all things related to security, tokens should be handled securely. Don't store access tokens in persistent storage and before every call check if the token is still valid. If it's not, request a new one.

You can see how the access tokens are used in [this quickstart example](https://developer.spendesk.com/reference/quickstart).

To find out more detail on how to first get your access token, read on.

# API Keys

Using the **API Key** flow is the simpler of the two options and requires a single request for the access token: `POST https://public-api.spendesk.com/v1/auth/token` ([Create an access token](https://developer.spendesk.com/reference/v1-create-auth-token)).

You can manage your API keys directly by logging into Spendesk and navigating to *Settings>Integrations>Manage API access*.

> 📘
>
> API keys can be valid for up to a maximum of **1 year.**

This request uses your API Key configuration, you must provide your client id and secret in the format *"id:secret"* then **base64 encode it**. You'll end up with something like:

* plain text: `my_id:my_secret`
* encoded: `bXlfaWQ6bXlfc2VjcmV0`

Then you're ready to make a call to authenticate at `POST /v1/auth/token` using that **encoded** value in the *Authorization* header. Don't forget the word *Basic* in front of the encoded value, so that your HTTP header looks like this:

> `Authorization: Basic bXlfaWQ6bXlfc2VjcmV0`

To get a new token, for example when one has expired, simply make another call to the `POST /v1/auth/token` endpoint using the same authorization header.

Our [quickstart guide](https://developer.spendesk.com/reference/quickstart) covers this flow end-to-end, so we recommend following that to get a feel for this.

# OAuth2

We use the standard [OAuth2](https://oauth.net/2/) authorization code flow with PKCE to authenticate on behalf of a customer. This follows these general steps:

* Your system first makes a call to our */oauth2/authorize* [endpoint](https://developer.spendesk.com/reference/v1-request-authorization) using your client id
  * *redirect\_uri* should start with *https* (with an 's' at the end!) and should be hosted on the domain provided to Spendesk when creating your new partner record (often on *localhost* for development purposes)
  * use [this tool](https://www.oauth.com/playground/authorization-code-with-pkce.html) to easily generate *code\_challenge* to get you started
* We respond with HTTP code 302 Redirect with a URL to the Spendesk frontend which your system should redirect to
* On Spendesk, the customer can login and approve the OAuth2 connection between our systems
* Once successful, Spendesk redirects back to *your* frontend with a connection *code* in the URL
* Your system makes a final call to our */oauth2/token/create* [endpoint](https://developer.spendesk.com/reference/v1-create-oauth2-token) with `grant_type=authorization_code`, using the connection *code* and the *code\_verifier* generated in the first step above
* If this is successful, we send back both an **access token** as well as a  **refresh token**
* Use the **access token** in any subsequent API calls for this customer, for example to */settlements*
* Use the **refresh token** to request new access tokens by calling the same */oauth2/token/create* [endpoint](https://developer.spendesk.com/reference/v1-create-oauth2-token) with `grant_type=refresh_token`

> 📘
>
> Access tokens via OAuth2 are scoped to the specific organisation that approved the connection.

When the access token is expired, instead of starting the flow again, call the */oauth2/token/create* [endpoint](https://developer.spendesk.com/reference/v1-create-oauth2-token) with `grant_type=refresh_token` to renew the connection and generate a new access and refresh tokens:

```shell
curl --request POST \
     --url https://public-api.spendesk.com/v1/oauth2/token/create \
     --header 'accept: application/json' \
     --header 'content-type: application/x-www-form-urlencoded' \
     --data grant_type=refresh_token \
     --data client_id=<your_client_id> \
     --data refresh_token=<your_refresh_token>
```

Send token requests as `application/x-www-form-urlencoded`, as specified by OAuth 2.0 (JSON bodies are still accepted for backwards compatibility). If your app was issued a client secret, add it as `client_secret`.

> 🚧 The refresh endpoint is deprecated
>
> The former */oauth2/token/refresh* endpoint is deprecated and only remains available temporarily for backwards compatibility. Use */oauth2/token/create* with `grant_type=refresh_token` instead.

You can either:

* Wait until you see a **401** to request a new token with your refresh token
* Proactively request new tokens before the 1 hour expiry time. Store the new refresh token in your database.

Refresh tokens expire in about 30 days - but we don't provide the exact expiration timestamp (on purpose). We recommend you store them in your database along with your internal customer/connection ID. If there is a possibility that no API calls are made for 30 days for a given customer, then request a new refresh token before the current one expires in order to keep the connection alive. But if your integration always runs on a weekly or daily basis, simply update the refresh token in your database every time you get a new one. When a new refresh token is issued it invalidates the previous one - hence the importance of updating the database every time you refresh your tokens.

If you are unable to get a new refresh token (with a **401** or **403** error codes), remove the token from your database and "disconnect" the customer.

## OAuth2 for customers with several entities

Many customers have more than one wallet (company) in Spendesk, grouped under one organisation. There are two ways to connect them.

**One connection per company.** Each OAuth2 connection is independent. When such customer arrives on Spendesk to authorize an OAuth2 connection, they pick the company they are connecting in the dropdown (in the screenshot there is just one, but for multi-entity customers there will be several). They repeat this process for every company/wallet they have with us, each time selecting a different company in the dropdown. The connection process starts from the same partner account, that's how you know they belong to the same customer.

<Image align="center" src="https://files.readme.io/c6fc075-oauth2_dialog.png" />

Once you get an access token for each new connection, you can either call [Get wallet summary](https://developer.spendesk.com/reference/v1-get-wallet-summary) endpoint (with no parameters) to get the name of the wallet (company), or you can decode the *access\_token* (it's a JWT) to get the ID of the wallet (company).

**One organisation-level connection.** Where the organisation-level option is available, the customer can approve the connection for the whole organisation instead of a single company. Your app then receives a single token that reaches every company of the organisation: list them with [Get Companies](https://developer.spendesk.com/reference/v2-get-companies), and name the company on each call with the `X-Company-Id` header. See [Organisation-level access](https://developer.spendesk.com/reference/organisation-level-access).

*Last checked against the Spendesk demo environment on 29 September 2026.*