- Card number
5060990580000217499- Expiry date
0350- CVV
111- PIN
1111- OTP
123456
Payxy Developer API
Initialize payments, redirect customers to a secure checkout, verify transaction status, and receive real-time webhook notifications — all through a single, unified API.
Authentication
Every API request must include an Authorization header containing your Base64-encoded merchant code. This token authenticates your requests and identifies your merchant account.
PYXY000026
Use this shared merchant code with https://api.payxy.ng while developing and testing.
Your unique production merchant code is provided when your Payxy merchant onboarding is complete. Use it only with https://api.payxy.africa.
Authorization: Bearer UFlYWTAwMDAyNg==
Content-Type: application/json
Encode the merchant code using Base64. The sandbox merchant code PYXY000026 encodes to UFlYWTAwMDAyNg==.
// Browser / Node.js (built-in)
const encoded = btoa("PYXY000026");
// C# / .NET
var encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes("PYXY000026"));
Standard Response Format
All API endpoints return a consistent JSON wrapper. Always inspect responseCode first — a value of "00" indicates success.
{
"responseCode": "00",
"responseMessage": "Request processed successfully",
"data": {}
}
| Field | Type | Description |
|---|---|---|
responseCode |
string | API response code. "00" means successful. |
responseMessage |
string | Human-readable description of the response result. |
data |
object | Response payload. Structure varies per endpoint. |
responseCode === "00" before processing data. Non-"00" codes indicate an error — inspect responseMessage for details.
Test Card Details
https://api.payxy.ng. They must never be used for production transactions.- Card number
4000000000002503- Expiry date
0350- CVV
111- PIN
1111- OTP
- Shown on 3DS page
- Card number
5123450000000008- Expiry date
0139- CVV
100- PIN
1234- OTP
- Shown on 3DS page
Initialize Payment
Creates a new payment session and returns a paymentUrl. Redirect your customer to this URL to complete payment on Payxy's secure hosted checkout page.
Authorization: Bearer UFlYWTAwMDAyNg==
Content-Type: application/json
{
// Required fields
"email": "[email protected]",
"amount": "5000",
"transactionId": "TXN-20260706-0001",
"currency": "NGN",
"callbackUrl": "https://merchant-site.com/payment/callback",
// Optional fields
"metadata": [
{
"name": "orderId",
"value": "ORD-10001"
}
],
"productId": "PROD-001",
"productDescription": "Premium subscription",
"applyConviniencyCharge": true,
"mode": 0,
"bodyColor": "#ffffff",
"buttonColor": "#17c96e",
"footerText": "Powered by Merchant Name",
"footerLink": "https://merchant-site.com",
"footerLogo": "https://merchant-site.com/logo.png"
}
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Required | Customer email address. |
amount |
string | Required | Payment amount. Send as a string (e.g. "5000"). |
transactionId |
string | Required | Unique transaction ID generated by the merchant. Used to track the payment on your system. |
currency |
string | Required | Transaction currency code, e.g. NGN. |
callbackUrl |
string | Required | URL to redirect the customer after payment. Your backend should call Verify Payment upon receiving this redirect. |
metadata |
array | Optional | Additional merchant-defined key-value data to attach to the transaction. |
metadata[].name |
string | Optional | Metadata key name. |
metadata[].value |
string | Optional | Metadata value. |
productId |
string | Optional | Merchant product ID. |
productDescription |
string | Optional | Product or payment description shown on the checkout page. |
applyConviniencyCharge |
boolean | Optional | Whether to apply a convenience charge to the transaction. |
mode |
number | Optional | Payment mode / configuration value. |
bodyColor |
string | Optional | Hex color for the payment page body background. |
buttonColor |
string | Optional | Hex color for buttons on the payment page. |
footerText |
string | Optional | Custom text displayed in the payment page footer. |
footerLink |
string | Optional | URL for the footer link on the payment page. |
footerLogo |
string | Optional | URL of a logo image displayed in the payment page footer. |
{
"responseCode": "00",
"responseMessage": "Authorization URL created",
"data": {
"paymentUrl": "https://payxy.ng/pay/checkout/ACCESS_CODE",
"accessCode": "ACCESS_CODE"
}
}
| Field | Type | Description |
|---|---|---|
paymentUrl |
string | URL to redirect the customer to complete payment. |
accessCode |
string | Access code generated for the transaction. |
transactionId and returned accessCode in your database.data.paymentUrl to complete payment.callbackUrl after the payment flow.Verify Payment
Confirms the final status of a transaction. This must be called from your backend after Payxy redirects the customer to your callbackUrl. Never rely solely on the redirect — always verify server-side.
| Parameter | Type | Required | Description |
|---|---|---|---|
caller |
string | Optional | An identifier for the source making the request. Useful for debugging and tracing. |
{
"transactionId": "TXN-20260706-0001"
}
| Field | Type | Required | Description |
|---|---|---|---|
transactionId |
string | Required | The merchant transaction ID used when initializing the payment. |
{
"responseCode": "00",
"responseMessage": "Transaction retrieved successfully",
"data": {
"amount": "5000",
"currency": "NGN",
"gatewayResponse": "Approved",
"merchantId": 10001,
"paymentType": "Card",
"transactionId": "TXN-20260706-0001",
"paymentReference": "PAYXY-REF-123456789",
"recurringID": null,
"status": "Successful",
"cardPan": "5399********1234",
"cardType": "Mastercard",
"cardExpiry": "12/29",
"originatorBank": "Customer Bank",
"originatorName": "John Doe",
"originatorAccount": "0123456789",
"sessionId": "PROVIDER-SESSION-ID",
"isSuccessful": true
}
}
| Field | Type | Description |
|---|---|---|
amount | string | Transaction amount. |
currency | string | Transaction currency. |
gatewayResponse | string | Payment gateway response message. |
merchantId | number | Payxy merchant ID. |
paymentType | string | Payment method used: Card, Transfer, USSD, or account-based. |
transactionId | string | Your merchant transaction ID. |
paymentReference | string | Payxy payment processor reference. |
recurringID | string | null | Recurring mandate ID, if applicable. |
status | string | Final transaction status: Successful, Failed, or Pending. |
cardPan | string | null | Masked card PAN (card payments only). |
cardType | string | null | Card scheme (e.g. Mastercard, Visa). |
cardExpiry | string | null | Card expiry date in MM/YY format. |
originatorBank | string | null | Customer's bank name (bank transfer/USSD). |
originatorName | string | null | Customer's account name (bank transfer/USSD). |
originatorAccount | string | null | Customer's account number (bank transfer/USSD). |
sessionId | string | null | Provider reference/session ID. |
isSuccessful | boolean | Convenience flag — true if the transaction was successful. |
isSuccessful === true before fulfilling the order.
Webhook Notifications
Webhooks are an optional, additional notification mechanism. When configured on the Payxy merchant portal, Payxy sends an HTTP POST to your webhook URL after a payment completes. Configure your webhook URL in the Payxy merchant dashboard.
{
"amount": "5000",
"currency": "NGN",
"gatewayResponse": "Approved",
"merchantId": 10001,
"paymentType": "Card",
"transactionId": "TXN-20260706-0001",
"paymentReference": "PAYXY-REF-123456789",
"recurringID": null,
"status": "Successful",
"cardPan": "5399********1234",
"cardType": "Mastercard",
"cardExpiry": "12/29",
"originatorBank": "Customer Bank",
"originatorName": "John Doe",
"originatorAccount": "0123456789",
"sessionId": "PROVIDER-SESSION-ID"
}
200 OK immediately upon receiving the notification to prevent retries.transactionId from the payload to call /api/Payments/VerifyPayment from your backend.Complete Payment Flow
The end-to-end payment integration involves four parties: your backend, your frontend, the customer, and Payxy. Follow this sequence for every transaction.
Your server calls POST /api/Payments/Initialize with the transaction details.
Payxy creates a secure checkout session and returns a hosted payment URL.
Your frontend redirects the customer to data.paymentUrl.
The customer enters their card details or selects bank transfer / USSD on Payxy's secure checkout page.
After payment (success or failure), Payxy redirects the customer back to your callbackUrl.
Your backend calls POST /api/Payments/VerifyPayment using the transactionId.
After confirming isSuccessful === true, fulfill the order and give value to the customer.
If a webhook URL is configured in the portal, Payxy also sends a POST notification to your webhook endpoint.
Code Examples
Ready-to-use sandbox samples across multiple languages. They use https://api.payxy.ng and merchant code PYXY000026. For production, use https://api.payxy.africa and the merchant code issued during onboarding. Always run Initialize and Verify from your backend.
curl -X POST "https://api.payxy.ng/api/Payments/Initialize" \
-H "Authorization: Bearer UFlYWTAwMDAyNg==" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"amount": "5000",
"transactionId": "TXN-20260706-0001",
"currency": "NGN",
"callbackUrl": "https://merchant-site.com/payment/callback",
"metadata": [{ "name": "orderId", "value": "ORD-10001" }],
"productId": "PROD-001",
"productDescription": "Premium subscription",
"applyConviniencyCharge": true,
"mode": 0
}'
// Run this from your backend (Node.js) — never expose credentials in browser code
async function initializePayment() {
const merchantCode = "PYXY000026";
const token = Buffer.from(merchantCode).toString("base64");
const response = await fetch("https://api.payxy.ng/api/Payments/Initialize", {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
email: "[email protected]",
amount: "5000",
transactionId: "TXN-20260706-0001",
currency: "NGN",
callbackUrl: "https://merchant-site.com/payment/callback"
})
});
const result = await response.json();
if (result.responseCode === "00") {
// Redirect the customer
res.redirect(result.data.paymentUrl);
}
}
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var merchantCode = "PYXY000026";
var encodedCode = Convert.ToBase64String(Encoding.UTF8.GetBytes(merchantCode));
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", encodedCode);
var payload = new
{
email = "[email protected]",
amount = "5000",
transactionId = "TXN-20260706-0001",
currency = "NGN",
callbackUrl = "https://merchant-site.com/payment/callback"
};
var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.payxy.ng/api/Payments/Initialize", content);
var body = await response.Content.ReadAsStringAsync();
<?php
$merchantCode = "PYXY000026";
$payload = [
"email" => "[email protected]",
"amount" => "5000",
"transactionId" => "TXN-20260706-0001",
"currency" => "NGN",
"callbackUrl" => "https://merchant-site.com/payment/callback"
];
$ch = curl_init("https://api.payxy.ng/api/Payments/Initialize");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . base64_encode($merchantCode),
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
if ($response === false) throw new RuntimeException(curl_error($ch));
$result = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
curl_close($ch);
if (($result["responseCode"] ?? null) === "00") {
header("Location: " . $result["data"]["paymentUrl"]);
exit;
}
import base64
import json
from urllib.request import Request, urlopen
merchant_code = "PYXY000026"
token = base64.b64encode(merchant_code.encode()).decode()
payload = {
"email": "[email protected]",
"amount": "5000",
"transactionId": "TXN-20260706-0001",
"currency": "NGN",
"callbackUrl": "https://merchant-site.com/payment/callback",
}
request = Request(
"https://api.payxy.ng/api/Payments/Initialize",
data=json.dumps(payload).encode(),
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
method="POST",
)
with urlopen(request, timeout=30) as response:
result = json.load(response)
if result["responseCode"] == "00":
payment_url = result["data"]["paymentUrl"]
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
var merchantCode = "PYXY000026";
var token = Base64.getEncoder().encodeToString(
merchantCode.getBytes(StandardCharsets.UTF_8));
var payload = """
{"email":"[email protected]","amount":"5000",
"transactionId":"TXN-20260706-0001","currency":"NGN",
"callbackUrl":"https://merchant-site.com/payment/callback"}
""";
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.payxy.ng/api/Payments/Initialize"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
var response = HttpClient.newHttpClient().send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
)
func main() {
payload := map[string]string{
"email": "[email protected]", "amount": "5000",
"transactionId": "TXN-20260706-0001", "currency": "NGN",
"callbackUrl": "https://merchant-site.com/payment/callback",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(http.MethodPost,
"https://api.payxy.ng/api/Payments/Initialize", bytes.NewReader(body))
token := base64.StdEncoding.EncodeToString([]byte("PYXY000026"))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer response.Body.Close()
fmt.Println(response.Status)
}
curl -X POST "https://api.payxy.ng/api/Payments/VerifyPayment?caller=merchant-site" \
-H "Authorization: Bearer UFlYWTAwMDAyNg==" \
-H "Content-Type: application/json" \
-d '{ "transactionId": "TXN-20260706-0001" }'
async function verifyPayment(transactionId) {
const token = Buffer.from("PYXY000026").toString("base64");
const response = await fetch(
"https://api.payxy.ng/api/Payments/VerifyPayment?caller=my-store",
{
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ transactionId })
}
);
const result = await response.json();
if (result.responseCode === "00" && result.data.isSuccessful) {
// Safe to give value to the customer
console.log("Payment confirmed:", result.data.paymentReference);
}
return result;
}
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var encodedCode = Convert.ToBase64String(Encoding.UTF8.GetBytes("PYXY000026"));
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", encodedCode);
var payload = new { transactionId = "TXN-20260706-0001" };
var json = JsonSerializer.Serialize(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.payxy.ng/api/Payments/VerifyPayment?caller=my-store", content);
var body = await response.Content.ReadAsStringAsync();
<?php
$merchantCode = "PYXY000026";
$payload = ["transactionId" => "TXN-20260706-0001"];
$ch = curl_init(
"https://api.payxy.ng/api/Payments/VerifyPayment?caller=my-store"
);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . base64_encode($merchantCode),
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
if ($response === false) throw new RuntimeException(curl_error($ch));
$result = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
curl_close($ch);
if (($result["responseCode"] ?? null) === "00"
&& ($result["data"]["isSuccessful"] ?? false)) {
// Payment confirmed — fulfillment can proceed idempotently.
}
import base64
import json
from urllib.request import Request, urlopen
token = base64.b64encode(b"PYXY000026").decode()
request = Request(
"https://api.payxy.ng/api/Payments/VerifyPayment?caller=my-store",
data=json.dumps({"transactionId": "TXN-20260706-0001"}).encode(),
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
method="POST",
)
with urlopen(request, timeout=30) as response:
result = json.load(response)
if result["responseCode"] == "00" and result["data"]["isSuccessful"]:
print("Payment confirmed", result["data"]["paymentReference"])
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
var token = Base64.getEncoder().encodeToString(
"PYXY000026".getBytes(StandardCharsets.UTF_8));
var request = HttpRequest.newBuilder()
.uri(URI.create(
"https://api.payxy.ng/api/Payments/VerifyPayment?caller=my-store"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"transactionId\":\"TXN-20260706-0001\"}"))
.build();
var response = HttpClient.newHttpClient().send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
)
func main() {
payload := map[string]string{"transactionId": "TXN-20260706-0001"}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(http.MethodPost,
"https://api.payxy.ng/api/Payments/VerifyPayment?caller=my-store",
bytes.NewReader(body))
token := base64.StdEncoding.EncodeToString([]byte("PYXY000026"))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer response.Body.Close()
fmt.Println(response.Status)
}
Implementation Notes
Key rules to follow for a secure, reliable integration.
callbackUrl is required during initialization and must be a reachable endpoint on your server.paymentUrl — never embed the checkout in an iframe.transactionId for every payment attempt. Reusing IDs may cause verification conflicts.