---
updatedAt: 2026-09-04T14:31:51.000Z
---

Fetch the complete documentation index at: https://developer.benjipays.com/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Authentication

Authenticate with an x-api-key (merchant-scoped) or Auth0 M2M tokens.

Benji Pays uses two authentication methods. Most routes accept exactly one of them:

* **Benji Pays Merchant API** routes authenticate with an **`x-api-key`** header issued from the merchant app. The key is scoped to one organization and inherits the permissions of the login that created it.
* **Benji Pays Partner API** routes authenticate with an **Auth0 M2M Bearer token**: exchange client credentials for a JWT and send `Authorization: Bearer <jwt>`.

The sections below cover both flows.

## API key (merchant-scoped)

Merchant-facing routes authenticate with an `x-api-key` header tied to a single organization. The API validates the key, loads the owning login, and resolves the request actor from it.

```http
GET https://api.benjipays.com/v2/gateways
x-api-key: YOUR_API_KEY
Content-Type: application/json
```

API keys are issued from the merchant app and inherit the live mapping permissions of their owning login. Revoke a key from the merchant app to immediately cut off access.

Organization-scoped routes require the target organization to be **enabled** and not blocked by an expired free trial. Disabled organizations receive `401` with detail `API access is not active for this organization`; expired trials receive `403` with detail `Free trial has ended and billing is not enabled`. Benji Pays internal support keys bypass these organization lifecycle checks.

### Available scopes

| Scope                                          | Description                                           | Required mapping                   |
| ---------------------------------------------- | ----------------------------------------------------- | ---------------------------------- |
| `organizations:gateways:read`                  | Read payment gateways                                 | `companyAdmin`                     |
| `organizations:invoices:read`                  | Read invoices                                         | `companyAdmin`                     |
| `organizations:customers:read`                 | Read customers                                        | `companyAdmin`                     |
| `organizations:customer-notes:create`          | Create customer notes and replies                     | `companyAdmin`                     |
| `organizations:customer-notes:update`          | Update notes, status, and customer alerts             | `companyAdmin`                     |
| `organizations:customer-notes:delete`          | Delete notes, replies, and customer alerts            | `companyAdmin`                     |
| `organizations:payment-methods:read`           | Read saved payment methods                            | `companyAdmin` or `manageProfiles` |
| `organizations:payment-links:create`           | Create unapplied and applied payment links            | `companyAdmin`                     |
| `organizations:payment-method-requests:create` | Create customer payment-method-on-file requests       | `companyAdmin`                     |
| `organizations:payment-method-requests:read`   | List and get customer payment-method-on-file requests | `companyAdmin`                     |
| `organizations:settings:read`                  | Read organization settings                            | `companyAdmin`                     |
| `organizations:transactions:read`              | Read payment transactions                             | `companyAdmin`                     |
| `organizations:users:read`                     | Read organization users                               | `companyAdmin`                     |
| `organizations:emails:read`                    | Read emails                                           | `companyAdmin`                     |
| `organizations:autoprocessing:read`            | Read autoprocessing forecast                          | `companyAdmin`                     |
| `organizations:profile:read`                   | Read organization profile                             | `companyAdmin`                     |

## Auth0 M2M (partners and distributors)

The partner/distributor surface uses the OAuth 2.0 client-credentials grant against Auth0. The token's `actor` claim (`distributor`, `partner`, or `organization`) and OAuth scopes determine which routes the caller can reach.

### Prerequisites

* **Client ID** — your Auth0 M2M application client ID.
* **Client Secret** — your Auth0 M2M application client secret.
* **Auth0 domain** — your tenant domain (e.g. `your-tenant.auth0.com`).
* **API audience** — the API identifier configured in Auth0 (typically `https://api.benjipays.com`).

### 1. Obtain an access token

```http
POST https://YOUR_TENANT.auth0.com/oauth/token
Content-Type: application/json

{
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET",
  "audience": "https://api.benjipays.com",
  "grant_type": "client_credentials"
}
```

Response:

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

The token is valid for one hour by default. Refresh it before expiry.

### 2. Call the API

```http
GET https://api.benjipays.com/v2/whoami
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
```

Successful responses return JSON. See [Errors](./errors.md) for failure responses.

### Examples

**curl**

```bash
curl -X POST https://YOUR_TENANT.auth0.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "audience": "https://api.benjipays.com",
    "grant_type": "client_credentials"
  }'
```

**Node.js**

```javascript
const axios = require('axios');

async function getAccessToken() {
  const response = await axios.post('https://YOUR_TENANT.auth0.com/oauth/token', {
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET',
    audience: 'https://api.benjipays.com',
    grant_type: 'client_credentials'
  });
  return response.data.access_token;
}
```

## Failure responses

Failures use [RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) `application/problem+json`. See the [Errors](./errors.md) guide for the full envelope.

| Status             | When                                                                                                                           |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| `401 Unauthorized` | Missing, invalid, or expired credentials; or organization API access is not active.                                            |
| `403 Forbidden`    | Wrong actor type, missing OAuth scope, insufficient mapping permission for the key owner, or free trial ended without billing. |

Example 401 body:

```json
{
  "type": "https://api.benjipays.com/problems/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or missing authentication token",
  "instance": "/v2/whoami"
}
```

## Best practices

* Treat client secrets and access tokens as secrets. Never commit them.
* Implement token refresh before the one-hour expiry rather than reactively.
* Use environment variables or a secret manager (never source).
* Always call over HTTPS.
* Handle 401 and 403 distinctly — 401 is "re-authenticate", 403 is "you can't do this with these credentials".