Payxy
API Docs
v1.0 payxy.africa ↗
Payment API

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.

Bearer Token Auth
REST / JSON
Webhook Support
Sandbox https://api.payxy.ng
Production https://api.payxy.africa
1

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.

Sandbox credentials Use merchant code PYXY000026

Use this shared merchant code with https://api.payxy.ng while developing and testing.

Production credentials Issued after onboarding

Your unique production merchant code is provided when your Payxy merchant onboarding is complete. Use it only with https://api.payxy.africa.

Token Format
HTTP Header
Authorization: Bearer UFlYWTAwMDAyNg==
Content-Type: application/json
How to Encode Your Merchant Code

Encode the merchant code using Base64. The sandbox merchant code PYXY000026 encodes to UFlYWTAwMDAyNg==.

JavaScript
// Browser / Node.js (built-in)
const encoded = btoa("PYXY000026");

// C# / .NET
var encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes("PYXY000026"));
Security notice: The shared sandbox code is for testing only. Never expose your unique production merchant code or encoded token in client-side code. Always perform production API calls from your server-side backend.
2

Standard Response Format

All API endpoints return a consistent JSON wrapper. Always inspect responseCode first — a value of "00" indicates success.

JSON Response
{
  "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.
Always check responseCode === "00" before processing data. Non-"00" codes indicate an error — inspect responseMessage for details.
3

Test Card Details

Development environment only. Use these cards only with the sandbox API at https://api.payxy.ng. They must never be used for production transactions.
VerveTest card
Card number
5060990580000217499
Expiry date
0350
CVV
111
PIN
1111
OTP
123456
VisaTest card
Card number
4000000000002503
Expiry date
0350
CVV
111
PIN
1111
OTP
Shown on 3DS page
MastercardTest card
Card number
5123450000000008
Expiry date
0139
CVV
100
PIN
1234
OTP
Shown on 3DS page
4

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.

POST
Sandboxhttps://api.payxy.ng/api/Payments/Initialize Productionhttps://api.payxy.africa/api/Payments/Initialize
Headers
Required Headers
Authorization: Bearer UFlYWTAwMDAyNg==
Content-Type: application/json
Request Body
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"
}
Request Fields
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.
Successful Response
JSON — 200 OK
{
  "responseCode": "00",
  "responseMessage": "Authorization URL created",
  "data": {
    "paymentUrl": "https://payxy.ng/pay/checkout/ACCESS_CODE",
    "accessCode": "ACCESS_CODE"
  }
}
FieldTypeDescription
paymentUrl string URL to redirect the customer to complete payment.
accessCode string Access code generated for the transaction.
After Initialization — What to Do Next
Save the transactionId and returned accessCode in your database.
Redirect the customer to data.paymentUrl to complete payment.
Payxy redirects the customer to your callbackUrl after the payment flow.
When your callback URL is hit, call the Verify Payment endpoint from your backend to confirm final status.
5

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.

POST
Sandboxhttps://api.payxy.ng/api/Payments/VerifyPayment?caller={caller} Productionhttps://api.payxy.africa/api/Payments/VerifyPayment?caller={caller}
Query Parameters
ParameterTypeRequiredDescription
caller string Optional An identifier for the source making the request. Useful for debugging and tracing.
Request Body
JSON
{
  "transactionId": "TXN-20260706-0001"
}
FieldTypeRequiredDescription
transactionId string Required The merchant transaction ID used when initializing the payment.
Successful Response
JSON — 200 OK
{
  "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
  }
}
Response Data Fields
FieldTypeDescription
amountstringTransaction amount.
currencystringTransaction currency.
gatewayResponsestringPayment gateway response message.
merchantIdnumberPayxy merchant ID.
paymentTypestringPayment method used: Card, Transfer, USSD, or account-based.
transactionIdstringYour merchant transaction ID.
paymentReferencestringPayxy payment processor reference.
recurringIDstring | nullRecurring mandate ID, if applicable.
statusstringFinal transaction status: Successful, Failed, or Pending.
cardPanstring | nullMasked card PAN (card payments only).
cardTypestring | nullCard scheme (e.g. Mastercard, Visa).
cardExpirystring | nullCard expiry date in MM/YY format.
originatorBankstring | nullCustomer's bank name (bank transfer/USSD).
originatorNamestring | nullCustomer's account name (bank transfer/USSD).
originatorAccountstring | nullCustomer's account number (bank transfer/USSD).
sessionIdstring | nullProvider reference/session ID.
isSuccessfulbooleanConvenience flag — true if the transaction was successful.
Always verify server-side. Never give value to a customer based only on the redirect URL parameters. Always call Verify Payment from your backend and check isSuccessful === true before fulfilling the order.
6

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.

Webhooks are notifications only. Your system must still call the Verify Payment endpoint before giving value. Do not rely on webhook data alone.
Webhook Delivery
POST {your configured webhook URL}
Webhook Payload
JSON
{
  "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"
}
Recommended Webhook Handling
Return HTTP 200 OK immediately upon receiving the notification to prevent retries.
Log the full webhook payload for audit and debugging purposes.
Use the transactionId from the payload to call /api/Payments/VerifyPayment from your backend.
Update your order/payment status only after verification confirms the final status.
Make webhook processing idempotent — check if the transaction was already processed before acting, to avoid duplicate order fulfillment.
7

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.

1
Merchant Backend → Initialize Payment

Your server calls POST /api/Payments/Initialize with the transaction details.

2
Payxy → Returns paymentUrl & accessCode

Payxy creates a secure checkout session and returns a hosted payment URL.

3
Merchant Frontend → Redirects Customer

Your frontend redirects the customer to data.paymentUrl.

4
Customer → Completes Payment

The customer enters their card details or selects bank transfer / USSD on Payxy's secure checkout page.

5
Payxy → Redirects to Your callbackUrl

After payment (success or failure), Payxy redirects the customer back to your callbackUrl.

6
Merchant Backend → Verify Payment

Your backend calls POST /api/Payments/VerifyPayment using the transactionId.

7
Merchant Backend → Gives Value

After confirming isSuccessful === true, fulfill the order and give value to the customer.

W
Payxy → Sends Webhook (optional)

If a webhook URL is configured in the portal, Payxy also sends a POST notification to your webhook endpoint.

8

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.

Initialize Payment
cURL
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
  }'
JavaScript (Node.js / fetch)
// 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);
  }
}
C# / .NET
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 (cURL)
<?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;
}
Python 3 (standard library)
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"]
Java 17+ (HttpClient)
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());
Go
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)
}
Verify Payment
cURL
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" }'
JavaScript (Node.js / fetch)
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;
}
C# / .NET
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 (cURL)
<?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.
}
Python 3 (standard library)
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"])
Java 11+ (HttpClient)
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());
Go
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)
}
9

Implementation Notes

Key rules to follow for a secure, reliable integration.

Integration Checklist
callbackUrl is required during initialization and must be a reachable endpoint on your server.
Redirect the customer to paymentUrl — never embed the checkout in an iframe.
Always verify payment server-side before fulfilling any order — never give value based on a URL redirect alone.
Use a unique transactionId for every payment attempt. Reusing IDs may cause verification conflicts.
Make both callback and webhook handling idempotent — your handlers may be called more than once for the same transaction.
Webhook setup is optional and must be configured separately in the Payxy merchant portal.
Webhook notifications are sent only when a webhook URL is configured on the portal.
Never expose your merchant code or Base64 token in browser-side or mobile client code.