Developer Documentation
Integrate ABCM Pay into your website or app from anywhere in the world. Everything you need to accept payments, manage wallets, and sell airtime/data/cable/electricity is below.
Getting Started
Three steps to your first live request:
- Create a free account and complete KYC verification.
- Go to API Keys in your dashboard to get your
X-Api-KeyandX-Api-Secret. - VTU services (airtime, data, cable, electricity, exam pins) require a separate approval - contact support once you're ready to go live with those.
https://www.test.abcmtech.com/api/v1 — all endpoints below are relative to this.
https://www.test.abcmtech.com/sandbox/v1 - with its own keys (get them from your dashboard's Sandbox Mode page). No real money, no real SMS, no real provider is ever contacted. Amounts ending in .01 simulate a failure, .00 always succeeds.
Authentication
Every request must include two headers. There is no OAuth flow or token expiry to manage - your key/secret pair works until you regenerate it.
curl https://www.test.abcmtech.com/api/v1/wallet/balance \ -H "X-Api-Key: pk_live_xxxxxxxxxxxxxxxx" \ -H "X-Api-Secret: sk_live_xxxxxxxxxxxxxxxx"
<?php
$ch = curl_init('https://www.test.abcmtech.com/api/v1/wallet/balance');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-Api-Key: pk_live_xxxxxxxxxxxxxxxx',
'X-Api-Secret: sk_live_xxxxxxxxxxxxxxxx',
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);const response = await fetch('https://www.test.abcmtech.com/api/v1/wallet/balance', {
headers: {
'X-Api-Key': 'pk_live_xxxxxxxxxxxxxxxx',
'X-Api-Secret': 'sk_live_xxxxxxxxxxxxxxxx',
},
});
const data = await response.json();import requests
response = requests.get(
'https://www.test.abcmtech.com/api/v1/wallet/balance',
headers={
'X-Api-Key': 'pk_live_xxxxxxxxxxxxxxxx',
'X-Api-Secret': 'sk_live_xxxxxxxxxxxxxxxx',
},
)
data = response.json()X-Api-Secret in client-side/browser code. Keep all API calls server-side.Virtual Accounts
Generate a dedicated bank account number for each customer so you can identify who paid you, automatically.
| Parameter | Type | Description | |
|---|---|---|---|
| customer_type | string | optional | individual (default) or business |
| first_name / last_name | string | required | Customer's name - for an individual customer |
| business_name / cac_number | string | required | Registered name and CAC number (starting RC or BN) - for a business customer |
| string | required | Customer's email | |
| reference | string | required | Your own unique reference for this account |
Look up a single virtual account you created.
List every virtual account under your merchant.
Stop an account from accepting further payments. Use /enable to reverse this.
Wallet
Returns your available and unsettled wallet balances in real time.
Transactions
Check the status of any single transaction by its reference.
Paginated list of all your transactions, newest first.
Payouts
Send money out of your wallet to any Nigerian bank account. Requires payout access to be enabled on your account first.
List of supported banks and their codes.
| Parameter | Type | Description | |
|---|---|---|---|
| bank_code | string | required | From /payout/banks |
| account_number | string | required | 10-digit NUBAN |
| Parameter | Type | Description | |
|---|---|---|---|
| amount | number | required | Amount in Naira |
| bank_code | string | required | Destination bank |
| account_number | string | required | Destination account |
| reference | string | optional | Your own idempotency reference |
VTU Services
Airtime, data, cable TV, electricity, and exam pins - all through one consistent API shape. Requires VTU API access to be explicitly enabled on your account by our team; a valid key/secret pair alone is not enough.
| Parameter | Type | Description | |
|---|---|---|---|
| network | string | required | mtn, glo, airtel, or 9mobile |
| phone | string | required | Recipient phone number |
| amount | number | required | ₦50 - ₦50,000 |
| Parameter | Type | Description | |
|---|---|---|---|
| phone | string | required | Recipient phone number |
| data_plan_id | integer | required | From /vtu/data-plans |
| Parameter | Type | Description | |
|---|---|---|---|
| cable_plan_id | integer | required | From /vtu/cable-plans |
| smart_card_number | string | required | Smart card / IUC number |
| Parameter | Type | Description | |
|---|---|---|---|
| disco_id | integer | required | From /vtu/discos |
| meter_number | string | required | |
| meter_type | string | required | Prepaid or Postpaid |
| amount | number | required | ₦500 - ₦100,000 |
| Parameter | Type | Description | |
|---|---|---|---|
| exam_type_id | integer | required | From /vtu/exam-types |
| quantity | integer | required | 1-20 |
Every VTU purchase returns a reference - use it here to poll status.
Collect Payments
Generate a payment link that shows your customer a dedicated bank account number to transfer into, on your own branded page - never a third-party site. Requires Collect Payments API access to be explicitly enabled on your account by our team.
| Parameter | Type | Description | |
|---|---|---|---|
| amount | number | required | Amount in Naira (minimum ₦100) |
| description | string | optional | Shown on the payment page, e.g. "Invoice #123" |
| customer_name | string | optional | |
| customer_email | string | optional | |
| callback_url | string | optional | Where your customer is redirected after paying. Defaults to a standard return page if omitted. |
curl -X POST "https://www.test.abcmtech.com/api/v1/checkout/create" \
-H "X-Api-Key: pk_live_xxxxxxxxxxxxxxxx" \
-H "X-Api-Secret: your-api-secret-key" \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"description": "Invoice #123",
"customer_name": "Jane Doe",
"customer_email": "jane@example.com"
}'Response:
{
"success": true,
"reference": "CHK-20260829092726-MT2QD1",
"order_no": "24260829092726346817",
"checkout_url": "https://checkout.palmpay.com/h5-checkout/?...",
"amount": 5000,
"currency": "NGN",
"status": "pending"
}
Poll this with the reference from the create response to check whether payment has completed.
checkout_url to complete payment. Once paid, we notify your account via webhook and credit your wallet automatically - no need to poll status unless you want to reflect it in your own UI immediately.
Virtual Cards
Issue Visa/Mastercard virtual cards for your customers, fund them, freeze/unfreeze, and track spend - all through one API regardless of which card provider is active on the backend. Requires Virtual Card API access to be explicitly enabled on your account by our team.
Creates (or returns the existing) cardholder profile for an email under your account. A cardholder must complete identity verification before a card can be issued to them.
| Parameter | Type | Description | |
|---|---|---|---|
| first_name | string | required | |
| last_name | string | required | |
| string | required | Also used to detect an existing cardholder | |
| phone | string | optional |
Returns the cardholder's current KYC status - poll this after creation until it reads APPROVED before issuing a card.
Issues a new card. Your wallet is charged the card creation fee shown in your dashboard.
| Parameter | Type | Description | |
|---|---|---|---|
| cardholder_id | integer | required | From the cardholder creation response |
| brand | string | optional | VISA (default) or MASTERCARD |
| label | string | optional | Your own nickname for the card |
Paginated list of every card issued under your account.
Loads USD onto the card. Your wallet is charged the funding amount plus the funding fee shown in your dashboard.
| Parameter | Type | Description | |
|---|---|---|---|
| amount | number | required | USD amount to load onto the card |
| Parameter | Type | Description | |
|---|---|---|---|
| amount | number | optional | Leave blank to unload the full balance |
Terminate is permanent - the card cannot be reactivated afterward.
Paginated spend history for the card, synced from the card provider on each request.
Webhooks
Configure your webhook URL in the dashboard under Webhook Settings. We'll POST to it whenever a payment is received on one of your virtual accounts.
{
"event": "payment.received",
"data": {
"reference": "ORDER_123",
"amount": 10000,
"currency": "NGN",
"virtual_account": "0123456789",
"payer_name": "John Doe",
"payer_bank": "ACCESS BANK",
"status": "successful",
"timestamp": "2026-08-27T14:30:00Z"
},
"signature": "sha256=abc123..."
}
Verify the signature against your webhook secret before trusting the payload. Respond with HTTP 200 within a few seconds, or we'll retry.
Error Codes
| HTTP | error_code | Meaning |
|---|---|---|
| 401 | MISSING_CREDENTIALS | X-Api-Key or X-Api-Secret header missing |
| 401 | INVALID_CREDENTIALS | Key/secret pair doesn't match any account |
| 403 | IP_NOT_WHITELISTED | Request came from an IP not on your account's API whitelist (only enforced if you've turned it on in API Keys) |
| 403 | KYC_REQUIRED | Complete KYC verification before using the API |
| 403 | SERVICE_NOT_ENABLED | This specific service (e.g. VTU) hasn't been enabled for your account yet |
| 429 | RATE_LIMITED / IP_RATE_LIMITED | Too many requests - see Retry-After / retry_after in the response |
| 422 | - | Validation error - check the message field for details |
Rate Limits
Standard endpoints: 60 requests/minute per merchant. Payouts: an additional 20 requests/hour per IP address, on top of your configured per-transaction limits. Rate-limited responses include a retry_after field (seconds) telling you exactly when to try again.