Developer Documentation · v1

Ship a checkout in one API call.

Send your customer to a payment page hosted on AlliancePay's domain. No card data touches your servers. Sandbox and live share the same URL — the key prefix picks the environment.

Create a checkout session
curl -X POST https://hostedcheckoutapi.alliancepay.cloud/api/v1/session \
  -H "Authorization: Bearer $AP_PUBLIC_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email":       "customer@example.com",
    "amount":      500000,
    "currency":    "NGN",
    "reference":   "order_1717000000",
    "firstName":   "Ada",
    "lastName":    "Okonkwo",
    "mobile":      "+2348012345678",
    "country":     "NG",
    "callbackUrl": "https://yourstore.com/checkout/return"
  }'
One call to go live

Create a session, redirect the customer, verify server-side. A few dozen lines.

PCI SAQ-A scope

Card details entered on our page. Your servers never see a PAN or a CVV.

Any stack

.NET, Node, PHP, Python, Ruby, Go, curl — plain HTTPS with Bearer auth.

Get started

Overview

Hosted Checkout gives you a drop-in payment page for card and bank-transfer payments. You call one endpoint — POST /api/v1/session — with the cart amount and customer details, receive an accessCode, then send the customer to https://hostedcheckout.alliancepay.cloud/pay/{accessCode}. AlliancePay handles the card form, 3-D Secure, virtual accounts, and the receipt. When the customer is done, we redirect them back to your callbackUrl. Your server confirms the outcome with a single call to GET /api/v1/transaction/verify/{reference}.

Prefer full control?
The direct Server-to-Server API at checkout-api.alliancepay.cloud lets you build your own checkout UI with the same merchant keys.
Get started

Base URLs

REST APIhttps://hostedcheckoutapi.alliancepay.cloud
Customer-facing UIhttps://hostedcheckout.alliancepay.cloud/pay/{accessCode}
Browser SDKhttps://hostedcheckoutsdk.alliancepay.cloud/inline.js
The ingress accepts both the production hostnames above and the historical -dev hostnames (hostedcheckoutapi-dev.alliancepay.cloud, hostedcheckout-dev.alliancepay.cloud) — they route to the same service. If you already integrated against the -dev URLs nothing breaks; new integrations should use the production hostnames.
Get started

Authentication

Every request sends your Public Key as a bearer token:

Authorization header
Authorization: Bearer PGW-PUBLICKEY-<ENV>-XXXXXXXXXXXXXXXXXXXXXXXXXX

The prefix decides the environment. PGW-PUBLICKEY-TEST-… keys run in sandbox — no real money moves. PGW-PUBLICKEY-LIVE-… keys charge real cards. The API host and the UI host are the same either way.

Your Secret Key (PGW-SECRETKEY-…) is reserved for future server-to-server flows. Keep it out of the browser.

API reference

Response envelope

Every response uses the same shape:

Response envelope
{
  "status":  true,
  "message": "OK",
  "data":    { … }
}

status is true on success and false on failure. On non-2xx responses message is a merchant-facing string safe to show the customer, and data is null.

API reference

Amounts & currency

Amounts are integers in the minor unit of the currency. In Naira that means kobo: 500000 equals ₦5,000.00. In US dollars that means cents: 500000 equals $5,000.00. Supported currencies: NGN, USD.

API reference

Create a checkout session

POST
https://hostedcheckoutapi.alliancepay.cloud/api/v1/session

Call this from your server, once per payment attempt. Required fields are marked in the table below.

FieldTypeNotes
email
REQUIRED

string

Customer receipt email.

amount
REQUIRED

integer

Minor units — kobo for NGN, cents for USD.

currency
REQUIRED

string

ISO-4217. NGN or USD.

reference
REQUIRED

string

Your unique order reference.

firstName
REQUIRED

string

Customer first name.

lastName
REQUIRED

string

Customer last name.

mobile
REQUIRED

string

E.164 format (e.g. +2348012345678).

country
REQUIRED

string

ISO-3166 alpha-2 (NG).

description

string

Shown to the customer on the checkout page.

channels

array

Subset of ["card", "bank_transfer"]. Omit for both.

callbackUrl

string

HTTPS URL we redirect the customer back to after checkout completes.

metadata

object

Arbitrary JSON echoed back in verify responses.

Request
cURL
HTML / JS
Node.js
.NET (C#)
PHP
Python
curl -X POST https://hostedcheckoutapi.alliancepay.cloud/api/v1/session \
  -H "Authorization: Bearer $AP_PUBLIC_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email":       "customer@example.com",
    "amount":      500000,
    "currency":    "NGN",
    "reference":   "order_1717000000",
    "firstName":   "Ada",
    "lastName":    "Okonkwo",
    "mobile":      "+2348012345678",
    "country":     "NG",
    "description": "Yaba Coffee Order",
    "channels":    ["card", "bank_transfer"],
    "callbackUrl": "https://yourstore.com/checkout/return"
  }'
Response · 200 OK
200 OK
{
  "status":  true,
  "message": "Session created",
  "data": {
    "accessCode":       "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
    "authorizationUrl": "https://hostedcheckout.alliancepay.cloud/pay/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
    "reference":        "order_1717000000",
    "expiresAt":        "2026-08-04T14:00:00Z"
  }
}

accessCode is a signed JWT with a 30-minute lifetime.

API reference

Fetch session details

GET
https://hostedcheckoutapi.alliancepay.cloud/api/v1/checkout/{accessCode}/session

Reads the customer-facing view of the session (merchant name, amount, allowed channels, expiry). No auth header — the accessCode in the URL is the credential. Handy for custom loading screens.

200 OK
{
  "status": true,
  "message": "OK",
  "data": {
    "reference":     "order_1717000000",
    "amount":        500000,
    "currency":      "NGN",
    "merchantName":  "Yaba Coffee Roasters",
    "customerEmail": "customer@example.com",
    "channels":      ["card", "bank_transfer"],
    "status":        "pending",
    "expiresAt":     "2026-08-04T14:00:00Z",
    "callbackUrl":   "https://yourstore.com/checkout/return"
  }
}
API reference

Verify payment status

GET
https://hostedcheckoutapi.alliancepay.cloud/api/v1/transaction/verify/{reference}

This is the endpoint your server should call to decide whether to fulfil an order. You look it up by your own reference — the same value you passed when you created the session. Nothing else needs to be stored: no access codes, no JWTs, no per-session state.

Call it from your server after onSuccess, after the redirect back to your site, or on a schedule for pending orders. Only mark the order paid when status == "success" and the amount, currency and reference match what you expect.

cURL
HTML / JS
Node.js
.NET (C#)
PHP
Python
curl -X GET \
  "https://hostedcheckoutapi.alliancepay.cloud/api/v1/transaction/verify/$REFERENCE" \
  -H "Authorization: Bearer $AP_PUBLIC_KEY"
Response
200 OK
HTTP/1.1 200 OK
{
  "status":  "success",
  "message": "OK",
  "data": {
    "reference": "order_1717000000",
    "status":    "success",
    "amount":    500000,
    "currency":  "NGN",
    "channel":   "card"
  }
}
Status values
pending — no settlement yet. success — payment settled; fulfill. failed — declined or expired; do not fulfill.
Integration

Integration options

Once you have an accessCode, choose how to open the checkout. All three options behave the same for the customer.

1. Server-side redirect
HTTP
HTTP/1.1 303 See Other
Location: https://hostedcheckout.alliancepay.cloud/pay/{accessCode}
2. Iframe
HTML
<iframe
  src="https://hostedcheckout.alliancepay.cloud/pay/{accessCode}"
  style="width:100%;height:720px;border:0"
  allow="payment">
</iframe>
3. JavaScript SDK · pop-up modal

The SDK does the session creation for you. Ideal for e-commerce.

HTML
<script src="https://hostedcheckoutsdk.alliancepay.cloud/inline.js"></script>
<button id="pay">Pay ₦5,000</button>
<script>
  document.getElementById('pay').onclick = function () {
    AlliancePay.setup({
      key:       'PGW-PUBLICKEY-TEST-XXXXXXXXXXXXXXXXXXXXXXXXXX',
      email:     'customer@example.com',
      amount:    500000,
      currency:  'NGN',
      reference: 'order_' + Date.now(),
      firstName: 'Ada', lastName: 'Okonkwo',
      mobile:    '+2348012345678', country: 'NG',
      onSuccess: r  => console.log('paid',    r),
      onFailed:  r  => console.log('declined', r),
      onClose:   () => console.log('dismissed'),
    }).openIframe();
  };
</script>

success and failed fire callbacks but do not close the modal — the customer clicks "Return to merchant" themselves. Listen for close if you need to know when the iframe has been removed.

Integration

Webhooks (optional)

Webhooks are handled by the AlliancePay platform, not by Hosted Checkout. If you want push notifications instead of (or as a backup to) polling GET /api/v1/transaction/verify/{reference}, register a single webhook URL once in your AlliancePay merchant dashboard (Settings → API keys and Webhooks → Add URL). AlliancePay will POST the same JSON body for every payment made under your merchant, including those started through Hosted Checkout.

Payload

Delivered as POST <your webhook URL> with Content-Type: application/json. The Data.OrderReference field is the same reference you sent when you created the session — use it to look up the order in your database.

Webhook body
{
  "Status":     "success",
  "StatusCode": "00",
  "Message":    "Order details fetched successfully",
  "Data": {
    "OrderReference":         "order_1717000000",
    "PaymentReference":       "PA-REF-CFE3DE37-29FB-46DE-84A0-D0E849EEF1D8",
    "TotalAmountCharged":     50.00,
    "CurrencyName":           "NGN",
    "PaymentStatus":          5,
    "Status":                 "Successful",
    "PaymentMethod":          "Card Payment",
    "PaymentResponseCode":    "00",
    "PaymentResponseMessage": "Payment completed successfully",
    "DatePaymentConfirmed":   "2026-08-04T13:15:11Z",
    "Customer":               { "EmailAddress": "customer@example.com", "…": "…" },
    "OrderPayments":          [ { "…": "…" } ]
  }
}

The full schema (card details, customer object, order payments) is documented at alliance-pay.readme.io/docs/handling-asynchronous-events-webhooks.

Handler skeleton · Node.js
webhooks.ts
import express from "express";

const app = express();
app.use(express.json());

app.post("/webhooks/alliancepay", async (req, res) => {
  const { Status, Data } = req.body ?? {};

  if (Status === "success" && Data?.Status === "Successful") {
    // Look the order up in YOUR database by YOUR reference:
    await markOrderPaidIdempotent(Data.OrderReference, {
      amount:   Data.TotalAmountCharged,
      currency: Data.CurrencyName,
      channel:  Data.PaymentMethod
    });
  }
  // Acknowledge quickly — don't do slow work here.
  res.sendStatus(200);
});
Best practices
• Keep the handler idempotent — the same OrderReference may arrive more than once.
• Reply with a 2xx quickly; do slow work in a queue.
• Set up a backup polling job that calls GET /api/v1/transaction/verify/{reference} for any order still in pending after a few minutes — this covers webhook downtime.
Launch

Test values

Any PGW-PUBLICKEY-TEST-… key enables sandbox. No real money moves.

Mocking customer information

Customer-related parameters like firstName, lastName, email, mobile and country can take any value. They must still be in the right format to avoid validation errors during testing.

Successful card payments
AlliancePay
Test · Approved
5123 4500 0000 0008

CARD HOLDER

AlliancePay Test

VALID THRU

01/39

Mastercard · Sample
Success

CVV

100

PIN

1111
AlliancePay
Test · Approved
4508 7500 1574 1019

CARD HOLDER

AlliancePay Test

VALID THRU

01/39

VISA
Visa · Sample 1
Success

CVV

100

PIN

1111
AlliancePay
Test · Approved
4000 0000 0000 2503

CARD HOLDER

AlliancePay Test

VALID THRU

03/50

VISA
Visa · Sample 2
Success

CVV

111

PIN

1111
AlliancePay
Test · Approved
5060 9905 8000 0217 499

CARD HOLDER

AlliancePay Test

VALID THRU

03/50

verve
Verve · Sample
Success

CVV

111

PIN

1111

OTP

123456
Failed card payments
AlliancePay
Test · Declined
5060 9905 8000 0000 390

CARD HOLDER

AlliancePay Test

VALID THRU

03/50

verve
Verve · Sample
Declined

CVV

111

PIN

1111

OTP

123456
Bank transfer sandbox
Sandbox bank-transfer virtual accounts auto-settle in ~10 s after the modal opens. No real bank credentials required.
Launch

Going live

1

Complete AlliancePay merchant onboarding (KYC, settlement account, acquirer enablement for the card schemes × currencies you plan to accept).

2

Swap the -TEST- keys for -LIVE- in your frontend and server code.

3

Point callbackUrl at your production HTTPS return page.

4

Run a real ₦100 transaction end-to-end and confirm GET /api/v1/transaction/verify/{reference} returns success.

5

(Optional) Register your webhook URL in the AlliancePay dashboard so you get pushed settlement events.

6

Add monitoring on your verify calls (retries, alerting on non-success).

Nothing else changes — the URLs are the same for test and live.

API reference

Error reference

HTTPCommon causes
400

Missing required field. Check email, amount, firstName, lastName, mobile, country.

401

Bad or missing Bearer key, or session token expired (30 min). Create a new session.

402

Acquirer relationship not enabled for this card scheme × currency on your subsidiary. Contact AlliancePay.

409

You reused a reference. For bank transfer we return the previously allocated virtual account.

5xx

Transient upstream error. Retry with exponential back-off; verify status before creating a new session.

Launch

Support

Integration questions

API behaviour, sample code, debugging.

developers@alliancepay.cloud
Merchant onboarding

KYC, keys, settlement, acquirer enablement.

merchants@alliancepay.cloud

Full AlliancePay documentation lives at alliance-pay.readme.io. Include your subsidiary ID and (redacted) reference in every ticket.