Making API Calls

Use mutual TLS (mTLS) and an OAuth 2.0 Bearer access token when calling Lume APIs.

  • mTLS authenticates your integration using its client certificate and private key.
  • OAuth 2.0 authorises each API request using an access token.

For Secure Card (PaySecure) APIs, follow the additional requirements in PaySecure API.

Before you begin

Make sure you have:

  • A valid client certificate and its matching private key for the target environment. See Access Setup.
  • A valid OAuth access token. See Getting an Access Token.
  • The correct API base URL and endpoint path for your environment.
  • The request method, headers, body fields, and response contract for the endpoint you are calling.

Calling a standard API endpoint

The following example shows the common security controls for a JSON API request. Replace the placeholders with the values and endpoint-specific payload defined in the relevant API reference.

curl --fail-with-body --silent --show-error \
  --request POST \
  --cert "$CLIENT_CERTIFICATE" \
  --key "$CLIENT_PRIVATE_KEY" \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @request.json \
  "$API_BASE_URL$ENDPOINT_PATH"
openssl pkcs12 -export \
  -in pty-mtls-client-cert.cer \
  -inkey pty-mtls-client-cert.key.pem \
  -out client.p12 \
  -name paymentology

import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import java.time.Duration;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

public class PaymentologyApiClient {
    private static SSLContext createMtlsContext(Path keyStorePath, char[] password)
            throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        try (InputStream input = Files.newInputStream(keyStorePath)) {
            keyStore.load(input, password);
        }

        KeyManagerFactory keyManagers =
                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagers.init(keyStore, password);

        TrustManagerFactory trustManagers =
                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagers.init((KeyStore) null); // Use the default trusted certificate authorities.

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(
                keyManagers.getKeyManagers(),
                trustManagers.getTrustManagers(),
                null
        );

        return context;
    }

    public static void main(String[] args) throws Exception {
        String apiBaseUrl = System.getenv("API_BASE_URL");
        String endpointPath = System.getenv("ENDPOINT_PATH");
        String accessToken = System.getenv("ACCESS_TOKEN");
        String keyStorePassword = System.getenv("CLIENT_KEYSTORE_PASSWORD");

        SSLContext sslContext = createMtlsContext(
                Path.of("client.p12"),
                keyStorePassword.toCharArray()
        );

        HttpClient client = HttpClient.newBuilder()
                .sslContext(sslContext)
                .connectTimeout(Duration.ofSeconds(10))
                .build();

        String requestBody = Files.readString(Path.of("request.json"));

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(
                        apiBaseUrl.replaceAll("/$", "") + "/" +
                        endpointPath.replaceFirst("^/", "")
                ))
                .header("Authorization", "Bearer " + accessToken)
                .header("Accept", "application/json")
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        HttpResponse<String> response =
                client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.statusCode());
        System.out.println(response.body());
    }
}
npm install axios

const fs = require("node:fs");
const https = require("node:https");
const axios = require("axios");

const apiBaseUrl = process.env.API_BASE_URL.replace(/\/$/, "");
const endpointPath = process.env.ENDPOINT_PATH.replace(/^\//, "");
const accessToken = process.env.ACCESS_TOKEN;

const mtlsAgent = new https.Agent({
  cert: fs.readFileSync(process.env.CLIENT_CERTIFICATE),
  key: fs.readFileSync(process.env.CLIENT_PRIVATE_KEY),
});

async function callApi() {
  const response = await axios.post(
    `${apiBaseUrl}/${endpointPath}`,
    JSON.parse(fs.readFileSync("request.json", "utf8")),
    {
      httpsAgent: mtlsAgent,
      timeout: 10_000,
      headers: {
        Authorization: `Bearer ${accessToken}`,
        Accept: "application/json",
        "Content-Type": "application/json",
      },
    }
  );

  console.log(response.status);
  console.log(response.data);
}

callApi().catch((error) => {
  const status = error.response?.status;
  const body = error.response?.data;

  console.error(status ?? error.message);
  if (body) console.error(body);

  process.exitCode = 1;
});
openssl pkcs12 -export \
  -in pty-mtls-client-cert.cer \
  -inkey pty-mtls-client-cert.key.pem \
  -out client.pfx \
  -name paymentology

using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Text;

var apiBaseUrl = Environment.GetEnvironmentVariable("API_BASE_URL")!
    .TrimEnd('/');
var endpointPath = Environment.GetEnvironmentVariable("ENDPOINT_PATH")!
    .TrimStart('/');
var accessToken = Environment.GetEnvironmentVariable("ACCESS_TOKEN")!;
var certificatePath = Environment.GetEnvironmentVariable("CLIENT_CERTIFICATE_PFX")!;
var certificatePassword =
    Environment.GetEnvironmentVariable("CLIENT_CERTIFICATE_PASSWORD")!;

var certificate = new X509Certificate2(
    certificatePath,
    certificatePassword,
    X509KeyStorageFlags.EphemeralKeySet
);

using var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);

using var client = new HttpClient(handler)
{
    Timeout = TimeSpan.FromSeconds(10)
};

var requestBody = await File.ReadAllTextAsync("request.json");

using var request = new HttpRequestMessage(
    HttpMethod.Post,
    $"{apiBaseUrl}/{endpointPath}"
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", accessToken);
request.Headers.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json")
);
request.Content = new StringContent(
    requestBody,
    Encoding.UTF8,
    "application/json"
);

using var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();

Console.WriteLine((int)response.StatusCode);
Console.WriteLine(responseBody);

Where:

laceholderDescription
$CLIENT_CERTIFICATEPath to your mTLS client certificate
$CLIENT_PRIVATE_KEYPath to the matching private key
$ACCESS_TOKENA valid OAuth access token
$API_BASE_URLThe base URL supplied for your environment
$ENDPOINT_PATHThe path defined by the relevant API reference
request.jsonA file containing the endpoint-specific JSON request body

Do not disable certificate validation in your HTTP client. Protect the client certificate and private key using an approved keystore or secret-management solution.

Endpoint-specific requirements

mTLS and the Authorization header do not replace the endpoint contract. Each API reference defines its own:

  • HTTP method and endpoint path.
  • Required request headers.
  • Request body fields and validation rules.
  • Response format and error handling.
  • Idempotency or request-identifier requirements, where applicable.

Do not assume that every API uses the same request body or that all API paths follow the same pattern.

Call Secure Card APIs

Secure Card (PaySecure) APIs require the same mTLS and OAuth controls described above.

Some PaySecure endpoints have additional security and traceability requirements, including headers such as:

  • Session-Id
  • X-Request-Id

Use these headers only where the relevant PaySecure endpoint documentation requires them. The required encryption format, key material, and request fields are endpoint-specific. Do not implement PaySecure encryption from a generic example or assume that it applies to every /sc endpoint. For more information see PaySecure API.

Implement in your preferred language

Your HTTP client must be configured to:

  • Present the client certificate and matching private key during the TLS handshake.
  • Send the OAuth Bearer token in the Authorization header.
  • Use the method, headers, and JSON payload defined for the selected endpoint.
  • Validate the Paymentology server certificate.

Provide language-specific examples separately for the supported client libraries - for example, Java, JavaScript, .NET, and Python. Keep this page as the canonical integration pattern so that the security requirements are not duplicated and allowed to drift.

Handle errors and retries

  • If an API request returns 401 Unauthorized, obtain a new access token and retry once only when the operation is safe to retry.
  • Do not retry authentication or validation errors without correcting the underlying configuration or request.
  • For network failures, timeouts, rate limiting, or server errors, use bounded retries with backoff and jitter where the API operation is safe to retry.
  • Use any endpoint-specific idempotency or request-identifier mechanism when it is available.
  • Never log access tokens, private keys, client secrets, or sensitive request and response data.

Troubleshooting

SymptomCheck
TLS connection failsConfirm that the certificate is valid, belongs to the target environment, and is paired with the correct private key.
Token request failsCheck the OAuth client_id, client_secret, token URL, audience, and required scope.
401 UnauthorizedConfirm that the access token has not expired; obtain a new token and retry once only if safe.
API validation errorCheck the endpoint-specific request method, headers, body fields, and value formats.
PaySecure request failsCheck the relevant PaySecure endpoint documentation for required headers, encryption inputs, and request fields.

Did this page help you?