Environments and Authentication

Choose the sandbox or production base URL, exchange your client credentials for a bearer token, and learn which permissions your credentials carry.

Every request to Payment Labs goes to one environment and carries a bearer token. One login serves the whole platform: the token you get from POST /login works for every API, whether you send payouts, review payment requests, run wallets or accept payins. This page shows how to pick the environment, get a token, and read the authentication errors.

Before you start

You need a client ID and a secret. Payment Labs issues them; you cannot create or rotate them through the API. Ask your Payment Labs contact for sandbox credentials first, and for production credentials when you are ready to go live.

🔒

Keep the secret on your server. Never ship it in a browser, a mobile app or a repository. When Payment Labs issues a new secret for your account, the old one stops working immediately.

Environments

Sandbox and production are separate: separate credentials, separate data, separate balances. A token from one does not work in the other.

SandboxProduction
API base URLhttps://api-sandbox.paymentlabs.iohttps://api.paymentlabs.io
Dashboard and hosted checkout page (links.checkout)https://app-sandbox.paymentlabs.iohttps://app.paymentlabs.io
Embeddable checkout (links.embeddable)https://checkout-sandbox.paymentlabs.iohttps://checkout.paymentlabs.io
Payin SDK scripthttps://sdk.paymentlabs.io/payin/latest/paymentlabs.jssame

Every path in this documentation is relative to the API base URL. All request and response bodies are JSON; send Content-Type: application/json on every request with a body.

What differs in sandbox:

  • No real money moves. Payouts and card charges run against test processors.
  • Payee identity verification is simulated and passes, so you can onboard test payees with any data.
  • You control payout outcomes with keywords in payeeMemo. See Bank Transfer Payout Test Values.
  • You pay checkouts with test cards. See Credit Card Payin Test Values.
  • Webhook deliveries carry the header x-environment: sandbox. In production it is production.

Get a token

Send your credentials to Create Access Token (POST /login) with method set to client-secret. key is your client ID. There is one login for all of Payment Labs: merchants and payors use the same operation, the same credentials and the same token.

curl -X POST https://api-sandbox.paymentlabs.io/login \
  -H "Content-Type: application/json" \
  -d '{
    "method": "client-secret",
    "key": "3f6c2a9e-8b41-4d7a-9f0e-5c2b7a1d4e88",
    "secret": "<your-secret>"
  }'
const BASE_URL = "https://api-sandbox.paymentlabs.io";

async function getToken(clientId: string, secret: string): Promise<string> {
  const response = await fetch(`${BASE_URL}/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ method: "client-secret", key: clientId, secret }),
  });
  if (!response.ok) {
    throw new Error(`Login failed with ${response.status}: ${await response.text()}`);
  }
  const { token } = (await response.json()) as { token: string };
  return token;
}

A successful login returns 200:

{
  "token": "eyJhbGciOiJSUzUxMiIsImtpZCI6IjIwMjYtMTAifQ.eyJzdWIiOiJDLTAxSkJYMlE4In0.c2lnbmF0dXJl"
}

A failed login always returns 400, never 401:

codeMeaningWhat to do
MISSING_KEYkey is missing.Send your client ID as key.
MISSING_SECRETsecret is missing.Send your secret.
INVALID_KEY_OR_SECRETThe client ID and secret do not match.Check that you use the credentials for this environment, and that the secret has not been replaced.
INVALID_KEYThe credential is no longer linked to an active account.Contact Payment Labs.
INVALID_METHODmethod is not a supported value.Send "method": "client-secret".

If the body is missing or is not valid JSON, the response is 400 with a plain-text body (Missing request body or Invalid body), not JSON.

Use the token

Send the token in the Authorization header of every other request:

curl https://api-sandbox.paymentlabs.io/payors/me \
  -H "Authorization: Bearer $TOKEN"
const response = await fetch(`${BASE_URL}/payors/me`, {
  headers: { Authorization: `Bearer ${token}` },
});

If your credential only has a payin role, call GET /merchants/me (Get Merchant) instead: GET /payors/me needs a payout role.

  • A token is valid for 3 hours from the moment it is issued. There is no refresh token: call POST /login again.
  • Cache the token and reuse it for all requests until it is close to expiry, rather than logging in for every request.
  • If a request returns 401, get a new token and retry that request once.
  • A token from API credentials belongs to exactly one account, so you never need the x-payor-id header. That header exists only for dashboard users who belong to several accounts.

A small token cache:

let cached: { token: string; expiresAt: number } | undefined;

async function authToken(): Promise<string> {
  const now = Date.now();
  if (cached && cached.expiresAt - now > 5 * 60 * 1000) {
    return cached.token;
  }
  const token = await getToken(process.env.PL_CLIENT_ID!, process.env.PL_SECRET!);
  cached = { token, expiresAt: now + 3 * 60 * 60 * 1000 };
  return token;
}

Permissions

Each credential is issued with a role for payouts, a role for payins, or both. The role decides which operations the token can call. Each operation's reference page states the role it needs when it is more than read access. Role and permission names are the ones shown on the Roles screen of your dashboard; the tables below map the permissions to roles.

Payout roles

RoleRead: view batches, payments, payees and settingsWrite: create and edit batches, payments, payees and imports; cancel paymentsPayment Approval: submit payments and batches, turn auto-submit on or offUser Config: manage webhooks, set the payment availability period
AdministratorYesYesYesYes
Expert UserYesYesYesNo
UserYesYesNoNo
ApproverYesNoYesNo
ViewerYesNoNoNo

Payin roles

RoleMerchant Read: view checkouts, settlements and terminalsMerchant Write: create and charge checkouts, register and edit terminalsMerchant Approver: refund, edit subscription plans, enable and disable terminalsMerchant User Config: create and cancel plans, create, edit and delete plan offers, cancel subscriptions
Merchant AdministratorYesYesYesYes
Merchant ApproverYesYesYesNo
Merchant UserYesYesNoNo
Merchant ViewerYesNoNoNo

Webhooks are managed with the payout Administrator role, even if you only use payins. Ask for a credential with that role if you need to register webhooks through the API.

Wallets, wallet disputes and payment requests

Wallets, Wallet Disputes and Payment Requests need the Wallet Management or Payment Requests permission: Wallets and Wallet Disputes need Wallet Management, and Payment Requests need Payment Requests. In the dashboard the Administrator role includes both. To use them with an API credential, contact Payment Labs to enable access. Without the permission, these operations return 403 FORBIDDEN_INSUFFICIENT_TAGS.

You cannot change a credential's role or permissions through the API; ask Payment Labs.

Authentication errors

StatuscodeMeaningWhat to do
401UNAUTHORIZED_NO_TOKENNo Authorization header.Send Authorization: Bearer <token>.
401UNAUTHORIZED_INVALID_TOKENThe token is expired, malformed, or from another environment.Get a new token and retry once.
401UNAUTHORIZED_NO_CONTEXT, UNAUTHORIZED_NO_PAYORThe token carries no account, or your credential has no payout or payin role.Get a new token and retry once. If it persists, contact Payment Labs.
401none, body {"message": "Unauthorized"}Some routes reject a bad token at the gateway, without a code.Same as UNAUTHORIZED_INVALID_TOKEN.
403FORBIDDEN_INSUFFICIENT_TAGSYour credential's role does not allow this operation.Use a credential with the role the operation needs. Retrying does not help.
503AUTH_UNAVAILABLEPayment Labs could not verify the token in time.Retry after a short wait.

For every other error, see Errors.

Next steps


What’s Next

Did this page help you?