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:
| laceholder | Description |
|---|---|
$CLIENT_CERTIFICATE | Path to your mTLS client certificate |
$CLIENT_PRIVATE_KEY | Path to the matching private key |
$ACCESS_TOKEN | A valid OAuth access token |
$API_BASE_URL | The base URL supplied for your environment |
$ENDPOINT_PATH | The path defined by the relevant API reference |
request.json | A 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
| Symptom | Check |
|---|---|
| TLS connection fails | Confirm that the certificate is valid, belongs to the target environment, and is paired with the correct private key. |
| Token request fails | Check the OAuth client_id, client_secret, token URL, audience, and required scope. |
401 Unauthorized | Confirm that the access token has not expired; obtain a new token and retry once only if safe. |
| API validation error | Check the endpoint-specific request method, headers, body fields, and value formats. |
| PaySecure request fails | Check the relevant PaySecure endpoint documentation for required headers, encryption inputs, and request fields. |
Updated 8 days ago

