Authentication
Authenticate with an x-api-key (merchant-scoped) or Auth0 M2M tokens.
Benji Pays uses two authentication methods, and each route accepts exactly one of them:
- Merchant endpoints (Gateways, Invoices, Customers, Payment Methods, Settings, Transactions, Users) authenticate with an
x-api-keyheader issued from the merchant app. The key is scoped to one organization and inherits the permissions of the login that created it. - Partner endpoints (Whoami, Plans, Partners, Organizations, Usage, Billing) 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.
GET https://api.benjipays.com/v2/gateways
x-api-key: YOUR_API_KEY
Content-Type: application/jsonAPI 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 additionally require the target organization to be enabled and not blocked by an expired free trial without billing. 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:payment-methods:read | Read saved payment methods | companyAdmin or manageProfiles |
organizations:settings:read | Read organization settings | companyAdmin |
organizations:transactions:read | Read payment transactions | companyAdmin |
organizations:users:read | Read organization users | 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
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:
{
"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
GET https://api.benjipays.com/v2/whoami
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/jsonSuccessful responses return JSON. See Errors for failure responses.
Examples
curl
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
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 application/problem+json. See the Errors 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:
{
"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".
