> This page is for version v2 (default).
> For other versions, use one of these documentation indexes:
> - v2 (default): https://developers.clearpay.co.uk/v-2/llms.txt
> - v1: https://developers.clearpay.co.uk/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.clearpay.co.uk/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.clearpay.co.uk/_mcp/server.

# Authentication

The Clearpay Online API uses two different authentication options, which are discussed below. With the exception of [Ping](/api-reference/online-api/service-status/ping), all Online API endpoints require that one of these forms of authentication are used. Failure to correctly authenticate an API request will result in a `401 Unauthorized` response.

## Basic Auth

The first authentication method is [Basic HTTP Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication), a simple authentication scheme built into the HTTP protocol, as specified by [RFC 7617](https://tools.ietf.org/html/rfc7617).

## Example Request

**`Raw HTTP`**

```http Raw HTTP
GET /v2/configuration HTTP/1.1
Host: global-api-sandbox.afterpay.com
Authorization: Basic MzI6YWJjZGVmZ2g=
```

```curl
curl "https://global-api-sandbox.afterpay.com/v2/configuration" \
  -H 'Authorization: Basic MzI6YWJjZGVmZ2g='
```

**`Node`**

```javascript Node
var request = require("request");

var options = {
  url: 'https://global-api-sandbox.afterpay.com/v2/configuration',
  headers: {
    Authorization: 'Basic MzI6YWJjZGVmZ2g='
  }
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://global-api-sandbox.afterpay.com/v2/configuration")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic MzI6YWJjZGVmZ2g='

response = http.request(request)
puts response.read_body
```

```python
import requests

url = "https://global-api-sandbox.afterpay.com/v2/configuration"

headers = {
    'Authorization': "Basic MzI6YWJjZGVmZ2g="
}

response = requests.request("GET", url, headers=headers)

print(response.text)
```

Consider the following example:

| Merchant ID | Secret Key |
| :---------- | :--------- |
| 32          | abcdefgh   |

> **Note**
>
> In conventional HTTP terms, "Merchant ID" is the **username** and "Secret Key" is the **password**.
>
> Clearpay provides merchant accounts per region, and each merchant account has unique API credentials.

The credentials are joined by a colon character (without any spaces), then base64-encoded.

| Plain Text    | Base64 Encoded     |
| :------------ | :----------------- |
| `32:abcdefgh` | `MzI6YWJjZGVmZ2g=` |

The `Authorization` header can then be formed by including the word `Basic`, followed by a single space character, followed by the base64-encoded credential pair.

| Final Header                            |
| :-------------------------------------- |
| `Authorization: Basic MzI6YWJjZGVmZ2g=` |

> **Security Notice**
>
> Please note that the base64-encoding of the `Authorization` header is unrelated to security. All HTTP headers and bodies (for both requests and responses) between the Merchant and Clearpay are encrypted with [TLS](/https). The reason for base64-encoding is solely to comply with the [RFC 7617](http://www.rfc-editor.org/rfc/rfc7617.txt) standard, which allows non-HTTP characters and multibyte strings to be used for [Basic HTTP Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication).

## Bearer Tokens

The Client Credentials Authentication method is another authentication method available to merchants. It is a secure mechanism used to obtain access tokens which is defined in [RFC 6749](https://datatracker.ietf.org/doc/rfc6749/).

When using this method, a client application uses its unique credentials to fetch an access token, which enables it to access Clearpay's online APIs.

### Token URLs

Tokens are generated using separate URLs from those described in the API overview.

#### OAuth Endpoint Production

|             |                                                      |
| ----------- | ---------------------------------------------------- |
| Locations   | UK and EU                                            |
| Environment | `https://merchant-auth.afterpay.com/v2/oauth2/token` |

#### OAuth Endpoint Sandbox

|             |                                                              |
| ----------- | ------------------------------------------------------------ |
| Locations   | UK and EU                                                    |
| Environment | `https://merchant-auth-sandbox.afterpay.com/v2/oauth2/token` |

### Example Request

The following examples use the same credentials as the [Basic Auth](#basic-auth) section.

> **Note**
>
> The `scopes` field mentioned below is `merchant_api_v2`, but `merchant_api_v1` may be used to access the first version of the merchant APIs.

#### Access Token Request

**`Raw HTTP`**

```http Raw HTTP
POST /v2/oauth2/token HTTP/1.1
Host: https://merchant-auth-sandbox.afterpay.com
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=32
&client_secret=abcdefgh
&scope=merchant_api_v2
```

```curl
curl -X POST "https://merchant-auth-sandbox.afterpay.com/v2/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=32&client_secret=abcdefgh&scope=merchant_api_v2"
```

**`Node`**

```javascript Node
const request = require('request');

const options = {
  url: 'https://merchant-auth-sandbox.afterpay.com/v2/oauth2/token',
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  form: {
    grant_type: 'client_credentials',
    client_id: '32',
    client_secret: 'abcdefgh',
    scope: 'merchant_api_v2'
  }
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
```

```ruby
require 'uri'
require 'net/http'

uri = URI.parse('https://merchant-auth-sandbox.afterpay.com/v2/oauth2/token')

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/x-www-form-urlencoded' })

request.set_form_data({
  'grant_type' => 'client_credentials',
  'client_id' => '32',
  'client_secret' => 'abcdefgh',
  'scope' => 'merchant_api_v2'
})

response = http.request(request)

puts response.body
```

```python
import requests

data = {
    'grant_type': 'client_credentials',
    'client_id': '32',
    'client_secret': 'abcdefgh',
    'scope': 'merchant_api_v2'
}

response = requests.post('https://merchant-auth-sandbox.afterpay.com/v2/oauth2/token', data=data)
print(response.json())
```

### Access Token Response

The response to a successful authentication request includes the full JWT `access_token`. In the example below, the token is shortened for brevity.

```json
{
  "access_token": "eyJraWQiOiIwMzllNDBlMy0wYjM5LTQ3MTktOGFjNS05ZmE0OWRiMjQ3MWMiLCJhbGciOiJSUzI1NiJ9.eyJzd…",
  "scope": "merchant_api_v2/read merchant_api_v2/reverse merchant_api_v2/void merchant_api_v2/deferred_capture merchant_api_v2/capture merchant_api_v2/manage merchant_api_v2/initiate merchant_api_v2/cancel_subscription merchant_api_v2/direct_capture merchant_api_v2/refund merchant_api_v2/auth",
  "token_type": "Bearer",
  "expires_in": 86399
}
```

> **Token Expiration**
>
> The field `expires_in` is the time (in seconds) that the token is valid from when its generated. The token is not usable after this time elapses.

### API Requests with Token

See the following example where the `access_token` field is provided in the `Authorization` header of the request to access a secure API:

**`Raw HTTP`**

```http Raw HTTP
GET /v2/configuration HTTP/1.1
Host: global-api-sandbox.afterpay.com
Authorization: Bearer eyJraWQiOiIwMzllNDBlMy0wYjM5LTQ3MTktOGFjNS05ZmE0OWRiMjQ3MWMiLCJhbGciOiJSUzI1NiJ9.eyJzd…
```

```curl
curl "https://global-api-sandbox.afterpay.com/v2/configuration" \
  -H 'Authorization: Bearer eyJraWQiOiIwMzllNDBlMy0wYjM5LTQ3MTktOGFjNS05ZmE0OWRiMjQ3MWMiLCJhbGciOiJSUzI1NiJ9.eyJzd…'
```

**`Node`**

```javascript Node
var request = require("request");

var options = {
  url: 'https://global-api-sandbox.afterpay.com/v2/configuration',
  headers: {
    Authorization: 'Bearer eyJraWQiOiIwMzllNDBlMy0wYjM5LTQ3MTktOGFjNS05ZmE0OWRiMjQ3MWMiLCJhbGciOiJSUzI1NiJ9.eyJzd…'
  }
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://global-api-sandbox.afterpay.com/v2/configuration")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer eyJraWQiOiIwMzllNDBlMy0wYjM5LTQ3MTktOGFjNS05ZmE0OWRiMjQ3MWMiLCJhbGciOiJSUzI1NiJ9.eyJzd…'

response = http.request(request)
puts response.read_body
```

```python
import requests

url = "https://global-api-sandbox.afterpay.com/v2/configuration"

headers = {
    'Authorization': "Bearer eyJraWQiOiIwMzllNDBlMy0wYjM5LTQ3MTktOGFjNS05ZmE0OWRiMjQ3MWMiLCJhbGciOiJSUzI1NiJ9.eyJzd…"
}

response = requests.request("GET", url, headers=headers)

print(response.text)
```

> **Bearer Token Usage**
>
> Instead of the Authorization header using a prefix of `Basic`, the token authentication method uses `Bearer`. Omitting this value or setting it to something else will return an HTTP status code of `401 Unauthorized`.
>
> Other Clearpay APIs are accessible by using the same authentication scheme as the previous example.