Quickstart
Get your API credentials, authenticate, and send your first request.
Step 1: Get your API credentials
In order to use the PXP API, you'll need to get your client ID, create a token, and get the token's ID and value.
To get your credentials:
- In the Unity Portal, go to Merchant setup > Merchant groups.
- Select a merchant group.
- Click the Inbound calls tab.
- Copy the Client ID in the top-right corner.
- Click New token.
- Choose a number of days before token expiry. For example,
30
. - Click Save to confirm. Your token is now created.
- Copy the token ID and token value. Make sure to keep these confidential to protect the integrity of your authentication process.
As best practice, we recommend regularly generating and implementing new tokens.
Step 2: Set up webhooks
The PXP platform can automatically inform your application about events in real time using webhook notifications. This is the easiest way to keep track of transaction events, such as authorisations, captures, and cancellations.
To set up webhooks for your merchant group:
- In the Unity Portal, go to Merchant setup > Merchant groups.
- Select a merchant group.
- Click the Webhooks tab.
- Enter the URL you want PXP to send notifications to and generate a hash key.
- Click Save to confirm. Your webhooks are now set up.
Step 3: Prepare your API request
Now that you have your credentials and have set up your webhooks, you'll need to prepare your API request. In this example, we'll be authorising a card for an e-commerce transaction.
To do this, you'll need to supply:
- Your
merchant
andsite
identifier. These are automatically generated by PXP and supplied during onboarding. - A
merchantTransactionId
of your choice that represents this specific transaction. For example,ECOM_TEST001
. - A
merchantTransactionDate
that corresponds to the date and time when the transaction is being initiated, in ISO 8601 format. For example,2025-03-18 08:51:02.826445+00:00
.
You can replace the placeholders in the following sample:
{
"merchant": "{merchantValue}",
"site": "{siteValue}",
"merchantTransactionId": "{merchantTransactionId}",
"merchantTransactionDate": "{merchantTransactionDate}",
"transactionMethod": {
"intent": "Authorisation",
"entryType": "Ecom",
"fundingType": "Card"
},
"fundingData": {
"card": {
"primaryAccountNumber": "4111111111111111",
"expiryMonth": "11",
"expiryYear": "2028"
}
},
"amounts": {
"transaction": 20,
"currencyCode": "GBP"
}
}
Step 4: Generate a unique request ID and HMAC signature
Our platform uses HMAC (Hash-based Message Authentication Code) with SHA256 for authentication to ensure secure communication and data integrity. This method involves creating a signature by hashing your request data with a secret key, which must then be included in the HTTP headers of your API request.
To authenticate, you'll need to:
- Create a unique request ID (UUID or GUID) for each API request.
- Use your token value and request details to create an HMAC signature with cryptographic functions.
Step 5: Add HTTP headers to your request
Once you've created the HMAC signature, you'll need to include it in the HTTP headers of your API request alongside other identifying information.
The following table describes how to format these headers:
Header name | Description | Format |
---|---|---|
Authorization Header | The HMAC signature. This is made up of the authentication scheme, (e.g., PXP-UST1 ), your tokenId , the timestamp, and the HMAC value. | "Authorization: PXP-UST1 {tokenId}:{timestamp}:{hmac}" |
X-Request-Id Header | The unique request ID that you generated. | "X-Request-Id: {requestId}" |
X-Client-Id Header | Your clientId , which identifies your specific client application. | "X-Client-Id: {clientId}" |
Examples
using System;
using System.Security.Cryptography;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
public class ApiAuthentication
{
private static readonly HttpClient client = new HttpClient();
public static async void SendAuthenticatedRequest(string requestUri, string requestBody, string tokenValue, string tokenId, string clientId)
{
// Generating unique request ID and timestamp
var requestId = Guid.NewGuid().ToString();
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
// Preparing the data for HMAC signature
// Concatenating timestamp, requestId, requestPath, and requestBody for HMAC
var requestPath = new Uri(requestUri).AbsolutePath.Trim('/');
var hmacRequestData = $"{timestamp}{requestId}{requestPath}{requestBody}";
// Creating HMAC signature using the concatenated data and tokenValue
var hmac = CreateHmacSignature(hmacRequestData, tokenValue).ToUpper();
// Constructing the authentication header with HMAC signature
var authHeader = $"PXP-UST1 {tokenId}:{timestamp}:{hmac}";
// Setting up the request with necessary headers
// Authorization header includes the HMAC signature
// X-Request-Id and X-Client-Id headers include requestId and clientId respectively
var request = new HttpRequestMessage(HttpMethod.Post, requestUri)
{
Content = new StringContent(requestBody, Encoding.UTF8, "application/json")
};
request.Headers.Authorization = new AuthenticationHeaderValue("Authorization", authHeader);
request.Headers.Add("X-Request-Id", requestId);
request.Headers.Add("X-Client-Id", clientId);
// Sending the request and receiving the response
var response = await client.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
// Handle response as needed (not part of authentication steps)
}
// Helper method to create HMAC signature
private static string CreateHmacSignature(string data, string key)
{
var encoding = new UTF8Encoding();
byte[] keyBytes = encoding.GetBytes(key);
byte[] messageBytes = encoding.GetBytes(data);
using (var hmacsha256 = new HMACSHA256(keyBytes))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return BitConverter.ToString(hashmessage).Replace("-", "");
}
}
}
import uuid
import time
import hmac
import hashlib
import requests
from urllib.parse import urlparse
class ApiAuthentication:
@staticmethod
def send_authenticated_request(request_uri, request_body, token_value, token_id, client_id):
# Generating unique request ID and timestamp
request_id = str(uuid.uuid4())
timestamp = str(int(time.time()))
# Preparing the data for HMAC signature
# Concatenating timestamp, requestId, requestPath, and requestBody for HMAC
request_path = urlparse(request_uri).path.strip('/')
hmac_request_data = f"{timestamp}{request_id}{request_path}{request_body}"
# Creating HMAC signature using the concatenated data and token_value
hmac_signature = ApiAuthentication.create_hmac_signature(
hmac_request_data,
token_value
).upper()
# Constructing the authentication header with HMAC signature
auth_header = f"PXP-UST1 {token_id}:{timestamp}:{hmac_signature}"
# Setting up the request headers
headers = {
'Authorization': auth_header,
'X-Request-Id': request_id,
'X-Client-Id': client_id,
'Content-Type': 'application/json'
}
# Sending the request and receiving the response
response = requests.post(
request_uri,
headers=headers,
data=request_body
)
return response.text
@staticmethod
def create_hmac_signature(data, key):
# Create HMAC SHA256 signature
key_bytes = key.encode('utf-8')
message_bytes = data.encode('utf-8')
hmac_obj = hmac.new(
key_bytes,
message_bytes,
hashlib.sha256
)
# Convert to hexadecimal
return hmac_obj.hexdigest()
<?php
class ApiAuthentication
{
public static function sendAuthenticatedRequest($requestUri, $requestBody, $tokenValue, $tokenId, $clientId)
{
// Generating unique request ID and timestamp
$requestId = self::generateUuid();
$timestamp = time();
// Preparing the data for HMAC signature
// Concatenating timestamp, requestId, requestPath, and requestBody for HMAC
$requestPath = trim(parse_url($requestUri, PHP_URL_PATH), '/');
$hmacRequestData = $timestamp . $requestId . $requestPath . $requestBody;
// Creating HMAC signature using the concatenated data and tokenValue
$hmac = strtoupper(self::createHmacSignature($hmacRequestData, $tokenValue));
// Constructing the authentication header with HMAC signature
$authHeader = "PXP-UST1 {$tokenId}:{$timestamp}:{$hmac}";
// Setting up the request headers
$headers = [
'Authorization: ' . $authHeader,
'X-Request-Id: ' . $requestId,
'X-Client-Id: ' . $clientId,
'Content-Type: application/json'
];
// Initialize cURL session
$ch = curl_init($requestUri);
// Set cURL options
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $requestBody,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true
]);
// Send the request and get response
$response = curl_exec($ch);
// Check for errors
if (curl_errno($ch)) {
throw new Exception(curl_error($ch));
}
// Close cURL session
curl_close($ch);
return $response;
}
private static function createHmacSignature($data, $key)
{
return hash_hmac('sha256', $data, $key);
}
private static function generateUuid()
{
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpRequest.Builder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.UUID;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class ApiAuthentication {
private static final HttpClient client = HttpClient.newHttpClient();
public static void sendAuthenticatedRequest(String requestUri, String requestBody, String tokenValue, String tokenId, String clientId) throws Exception {
// Generating unique request ID and timestamp
String requestId = UUID.randomUUID().toString();
String timestamp = String.valueOf(Instant.now().getEpochSecond());
// Preparing the data for HMAC signature
String requestPath = URI.create(requestUri).getPath().replaceAll("^/|/$", "");
String hmacRequestData = timestamp + requestId + requestPath + requestBody;
// Creating HMAC signature
String hmac = createHmacSignature(hmacRequestData, tokenValue);
// Constructing the authentication header
String authHeader = "PXP-UST1 " + tokenId + ":" + timestamp + ":" + hmac;
// Setting up the request with necessary headers
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(requestUri))
.header("Authorization", authHeader)
.header("X-Request-Id", requestId)
.header("X-Client-Id", clientId)
.POST(BodyPublishers.ofString(requestBody))
.build();
// Sending the request and receiving the response
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// Handle response as needed
System.out.println(response.body());
}
private static String createHmacSignature(String data, String key) throws NoSuchAlgorithmException {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hash = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
} catch (Exception e) {
throw new RuntimeException("Error while creating HMAC signature", e);
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
public static void main(String[] args) {
try {
sendAuthenticatedRequest("Your API URL", "Your Request Body", "Your Token Value", "Your Token ID", "Your Client ID");
} catch (Exception e) {
e.printStackTrace();
}
}
}
require 'uri'
require 'net/http'
require 'json'
require 'securerandom'
require 'openssl'
class ApiAuthentication
class << self
def send_authenticated_request(request_uri, request_body, token_value, token_id, client_id)
# Generating unique request ID and timestamp
request_id = SecureRandom.uuid
timestamp = Time.now.to_i.to_s
# Preparing the data for HMAC signature
# Concatenating timestamp, requestId, requestPath, and requestBody for HMAC
request_path = URI(request_uri).path.sub(/^\/+/, '')
hmac_request_data = "#{timestamp}#{request_id}#{request_path}#{request_body}"
# Creating HMAC signature using the concatenated data and token_value
hmac = create_hmac_signature(hmac_request_data, token_value).upcase
# Constructing the authentication header with HMAC signature
auth_header = "PXP-UST1 #{token_id}:#{timestamp}:#{hmac}"
# Create URI object
uri = URI(request_uri)
# Create HTTP object
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
# Create Request object
request = Net::HTTP::Post.new(uri.path)
# Add headers
request['Authorization'] = auth_header
request['X-Request-Id'] = request_id
request['X-Client-Id'] = client_id
request['Content-Type'] = 'application/json'
request.body = request_body
# Send request and get response
response = http.request(request)
# Return response body
response.body
rescue StandardError => e
raise "Request failed: #{e.message}"
end
private
def create_hmac_signature(data, key)
# Create HMAC SHA256 signature
OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new('sha256'),
key,
data
)
end
end
end
require 'uri'
require 'net/http'
require 'json'
require 'securerandom'
require 'openssl'
class ApiAuthentication
class << self
def send_authenticated_request(request_uri, request_body, token_value, token_id, client_id)
# Generating unique request ID and timestamp
request_id = SecureRandom.uuid
timestamp = Time.now.to_i.to_s
# Preparing the data for HMAC signature
request_path = URI(request_uri).path.sub(/^\/+/, '')
hmac_request_data = "#{timestamp}#{request_id}#{request_path}#{request_body}"
# Creating HMAC signature using the concatenated data and token_value
hmac = create_hmac_signature(hmac_request_data, token_value).upcase
# Constructing the authentication header with HMAC signature
auth_header = "PXP-UST1 #{token_id}:#{timestamp}:#{hmac}"
# Create URI object
uri = URI(request_uri)
# Create HTTP object
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
# Create Request object
request = Net::HTTP::Post.new(uri.path)
# Add headers
request['Authorization'] = auth_header
request['X-Request-Id'] = request_id
request['X-Client-Id'] = client_id
request['Content-Type'] = 'application/json'
request.body = request_body
# Send request and get response
response = http.request(request)
response.body
rescue StandardError => e
raise "Request failed: #{e.message}"
end
private
def create_hmac_signature(data, key)
OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new('sha256'),
key,
data
)
end
end
end
import Foundation
import CommonCrypto
class ApiAuthentication {
static func sendAuthenticatedRequest(
requestUri: String,
requestBody: String,
tokenValue: String,
tokenId: String,
clientId: String,
completion: @escaping (Result<String, Error>) -> Void
) {
// Generating unique request ID and timestamp
let requestId = UUID().uuidString
let timestamp = String(Int(Date().timeIntervalSince1970))
// Preparing the data for HMAC signature
guard let url = URL(string: requestUri),
let requestPath = url.path.removingPrefix("/") else {
completion(.failure(AuthError.invalidUrl))
return
}
// Concatenating timestamp, requestId, requestPath, and requestBody for HMAC
let hmacRequestData = "\(timestamp)\(requestId)\(requestPath)\(requestBody)"
// Creating HMAC signature using the concatenated data and tokenValue
let hmac = createHmacSignature(data: hmacRequestData, key: tokenValue).uppercased()
// Constructing the authentication header with HMAC signature
let authHeader = "PXP-UST1 \(tokenId):\(timestamp):\(hmac)"
// Create URL request
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue(authHeader, forHTTPHeaderField: "Authorization")
request.setValue(requestId, forHTTPHeaderField: "X-Request-Id")
request.setValue(clientId, forHTTPHeaderField: "X-Client-Id")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = requestBody.data(using: .utf8)
// Create URL session task
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
completion(.failure(error))
return
}
guard let data = data,
let responseString = String(data: data, encoding: .utf8) else {
completion(.failure(AuthError.invalidResponse))
return
}
completion(.success(responseString))
}
// Start the task
task.resume()
}
private static func createHmacSignature(data: String, key: String) -> String {
guard let keyData = key.data(using: .utf8),
let messageData = data.data(using: .utf8) else {
return ""
}
let keyBytes = keyData.map { $0 }
let messageBytes = messageData.map { $0 }
var macData = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
messageBytes.withUnsafeBufferPointer { messageBytesPtr in
keyBytes.withUnsafeBufferPointer { keyBytesPtr in
CCHmac(
CCHmacAlgorithm(kCCHmacAlgSHA256),
keyBytesPtr.baseAddress,
keyBytes.count,
messageBytesPtr.baseAddress,
messageBytes.count,
&macData
)
}
}
return macData.map { String(format: "%02hhx", $0) }.joined()
}
}
// Helper extension
extension String {
func removingPrefix(_ prefix: String) -> String? {
guard self.hasPrefix(prefix) else { return self }
return String(self.dropFirst(prefix.count))
}
}
// Error enum
enum AuthError: Error {
case invalidUrl
case invalidResponse
}
// Example usage of completion handler:
/*
ApiAuthentication.sendAuthenticatedRequest(
requestUri: "https://api.example.com/endpoint",
requestBody: "{}",
tokenValue: "your_token",
tokenId: "your_token_id",
clientId: "your_client_id"
) { result in
switch result {
case .success(let response):
print("Success: \(response)")
case .failure(let error):
print("Error: \(error)")
}
}
*/
Always ensure that the time on your client is synchronised with the server to avoid issues with timestamp validation.
Step 6: Send your first API request
You can now go ahead and send your API request.
In return, you should receive:
- A
200
response containing asystemTransactionId
that identifies this specific transaction. You can use this to modify your transaction later. - A webhook that matches the transaction's state. For example, an
Authorisation
webhook.
{
"state": "Authorised",
"approvalCode": "123456",
"merchantTransactionId": "{merchantTransactionId}",
"systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b",
"providerTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b",
"fundingData": {
"cardScheme": "Visa",
"gatewayTokenId": "1ed768bb-e88a-4636-91ae-67927ccbb02b",
"schemeTokenNumber": "4837261112345678",
"avsResult": "noInformationAvailable",
"cvcResult": "noInformationAvailable",
"providerResponse": {
"provider": "PXPFinancial",
"code": "00",
"message": "Approved",
"merchantId": "77772182",
"avsResult": "D",
"cvcResult": "A",
"schemeTransactionId": "TX1234567890123456",
"paymentAccountReference": "PAR12345678901234567890",
"electronicCommerceIndicatorAdjustment": "01",
"settlementDate": "2025-03-25T00:00:00.000Z"
}
}
}
Updated about 1 month ago