Card Charge
To integrate card payments, follow this guide to initiate charges, handle multi-step authentication (3DS, OTP, PIN, AVS), and verify transaction outcomes.
1 - Initiate Card Charge
| Field | Type | Required | Description |
|---|---|---|---|
| amount | Number | ✅ | Amount to charge (e.g. 1500) |
| currency | String | ✅ | 3-letter currency code (e.g. KES, NGN, USD) |
| String | ✅ | Customer email | |
| firstName | String | ✅ | Card holder first name |
| lastName | String | ✅ | Card holder last name |
| transactionId | String | ✅ | Your transaction ID used for tracking |
| cardDetails.number | String | ✅ | Card PAN |
| cardDetails.cvv | String | ✅ | Card CVV |
| cardDetails.expMonth | String | ✅ | Expiry month (MM) |
| cardDetails.expYear | String | ✅ | Expiry year (YY) |
| address | Object | ❌ | Billing address (required for |
| device3DSInfo | Object | ❌ | 3DS device data |
| ipAddress | String | ❌ | Customer IP address |
| redirectUrl | String | ❌ | Optional redirect return URL (provider dependent) |
Note: The card charge is processed asynchronously. Use the transactionId to track status via the get transaction endpoint or listen for webhooks.
To charge a customer, collect the required card details and send them to the charge card endpoint.
Example Request:
{
"amount": 10,
"ipAddress": "159.26.101.81",
"currency": "USD",
"email": "[email protected]",
"firstName": "Bruce",
"lastName": "Wayne",
"externalReference": "123456789",
"cardDetails": {
"cvv": "000",
"number": "4242424242424242",
"expMonth": "09",
"expYear": "28"
},
"address": {
"zip": "10025",
"country": "US",
"street1": "1007 Mountain Drive",
"city": "Gotham City",
"state": "NJ"
},
"device3DSInfo": {
"colorDepth": 30,
"screenHeight": 1050,
"screenWidth": 1680,
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"timeZone": 180,
"deviceId": "29b435613857666dhgfdhg3b0a778471fbe9dc72db044886c7cc1175e4af632d4eb"
}
}
{
"amount": 100,
"ipAddress": "102.218.103.10",
"currency": "NGN",
"email": "[email protected]",
"firstName": "Wally",
"lastName": "West",
"externalReference": "525252525",
"cardDetails": {
"cvv": "052",
"number": "4242424242424242",
"expMonth": "09",
"expYear": "28"
},
"address": {
"zip": "64101",
"country": "US",
"street1": "52 Flash Boulevard",
"city": "Central City",
"state": "MO"
}
}
Below is an example of the response:
{
"success": true,
"status": "PENDING",
"message": "Request queued"
}
2 - Get Transaction Status
Always verify the payment status before providing value to your customer. Use the get transaction endpoint with either:
- The transactionId from the charge response or
- Your externalReference
Here's an example of possible transaction objects with different steps required:
{
"success": true,
"data": {
"transactionId": "TMNT-JLA-CRISIS-2026",
"amount": 100,
"currency": "NGN",
"createdAt": 1772739561749,
"chargeStatus": "pending",
"receiverCurrency": "NGN",
"receiverAmount": 100,
"senderCurrency": "NGN",
"senderAmount": 100,
"status": "PENDING",
"type": "deposit",
"method": "card",
"fullTimestamp": "2026-03-05T19:39:21+00:00",
"externalReference": "EARTH-PRIME-01",
"stepRequired": "pin",
"metadata": {
"senderAccountName": "Diana Prince",
"cardFirstSix": "194110",
"cardLastFour": "1984"
}
}
}
{
"success": true,
"data": {
"transactionId": "TMNT-JLA-CRISIS-2026",
"amount": 100,
"currency": "NGN",
"createdAt": 1772739561749,
"chargeStatus": "pending",
"receiverCurrency": "NGN",
"receiverAmount": 100,
"senderCurrency": "NGN",
"senderAmount": 100,
"status": "PENDING",
"type": "deposit",
"method": "card",
"fullTimestamp": "2026-03-05T19:39:21+00:00",
"externalReference": "EARTH-PRIME-01",
"stepRequired": "otp",
"metadata": {
"senderAccountName": "Diana Prince",
"cardFirstSix": "194110",
"cardLastFour": "1984"
}
}
}
{
"success": true,
"data": {
"transactionId": "TMNT-JLA-CRISIS-2026",
"amount": 100,
"currency": "NGN",
"createdAt": 1772739561749,
"chargeStatus": "pending",
"receiverCurrency": "NGN",
"receiverAmount": 100,
"senderCurrency": "NGN",
"senderAmount": 100,
"status": "PENDING",
"type": "deposit",
"method": "card",
"fullTimestamp": "2026-03-05T19:39:21+00:00",
"externalReference": "EARTH-PRIME-01",
"stepRequired": "address_verification",
"metadata": {
"senderAccountName": "Diana Prince",
"cardFirstSix": "194110",
"cardLastFour": "1984"
}
}
}
{
"success": true,
"data": {
"transactionId": "ARKHAM-ASYLUM-777",
"amount": 0.5,
"currency": "USD",
"createdAt": 1772739766529,
"chargeStatus": "pending",
"receiverCurrency": "USD",
"receiverAmount": 0.5,
"senderCurrency": "USD",
"senderAmount": 0.5,
"status": "PENDING",
"type": "deposit",
"method": "card",
"fullTimestamp": "2026-03-05T19:42:46+00:00",
"externalReference": "PUDDIN-01",
"stepRequired": "redirect",
"metadata": {
"senderAccountName": "Harleen Quinzel",
"cardFirstSix": "091192",
"cardLastFour": "1992",
},
"redirectUrl": "https://redirect.com"
}
}
3 - Handle Webhooks
Configure webhooks to receive real-time transaction updates instead of polling the status endpoint.
Setup
- Configure your webhook URL in your dashboard.
- Implement webhook endpoint security and validation.
- Handle the webhook notifications in your application.
{
"event": "transaction_updated",
"data": {
"transactionId": "luQybnMnvjgnWEF6ZFyJ",
"status": "pending",
"type": "deposit",
"stepRequired": "pin",
"externalReference": "1234567890"
},
"timestamp": "2026-03-05T19:39:30.624Z"
}
{
"event": "transaction_updated",
"data": {
"transactionId": "luQybnMnvjgnWEF6ZFyJ",
"status": "pending",
"type": "deposit",
"stepRequired": "otp",
"externalReference": "1234567890"
},
"timestamp": "2026-03-05T19:39:30.624Z"
}
{
"event": "transaction_updated",
"data": {
"transactionId": "luQybnMnvjgnWEF6ZFyJ",
"status": "pending",
"type": "deposit",
"stepRequired": "address_verification",
"externalReference": "1234567890"
},
"timestamp": "2026-03-05T19:39:30.624Z"
}
{
"event": "transaction_updated",
"data": {
"transactionId": "RFJZcgeeTGilZgPp9zyn",
"status": "pending",
"type": "deposit",
"stepRequired": "redirect",
"externalReference": "12fd3456789x",
"redirectUrl": "https://redirect.com"
},
"timestamp": "2026-03-05T19:42:56.538Z"
}
When a stepRequired field is present:
otp— Prompt the customer to enter the OTP sent to their phone or email.pin— Prompt the customer to enter their card PIN.redirect— Redirect the customer to the provided redirectUrl to complete 3DS authentication.address_verification— Collect the customer's billing address to verify against card records.
4 - Authorise Card Charge
If a webhook or status response contains a stepRequired of otp, pin, or address_verification, collect the required information and submit it to the authorise card charge endpoint.
| Field | Type | Required | Description |
|---|---|---|---|
| type | String | ✅ | The step type: otp, pin, or address_verification |
| value | String | Object | ✅ | The authorisation value. A string for otp/pin, or an address object for address_verification |
Request Example:
{
"type": "pin",
"value": "1234",
}
{
"type": "otp",
"value": "123456"
}
{
"type": "address_verification",
"value": {
"street1": "123 Main St",
"city": "Lagos",
"state": "Lagos",
"zip": "100001",
"country": "NG"
},
"transactionsLocation": "transactions"
}
Example Response:
{
"success": true,
"message": "Charge Authorisation successful."
}
{
"success": true,
"message": "Verification successful. Next step: redirect",
"stepData": {
"stepRequired": "redirect",
"redirectUrl": "<https://3ds.bank.com/authorize?token=...">
}
}
Note: After a successful authorisation the transaction continues processing in the background. You will receive a final successful or failed webhook when the transaction completes.
5 - Handle Redirects (3DS)
When stepRequired is redirect, the customer must be sent to the provided URL to complete 3D Secure authentication with their bank.
- Extract the URL — Get
redirectUrlfrom the webhook or the transaction status response. - Redirect the customer — Send the customer to this URL. They will land on their bank's secure authentication page.
- Await the final status — After the customer completes (or abandons) authentication, wait for the final transaction_updated webhook with status: "successful" or status: "failed" before providing value.
Note: Do not poll aggressively during a redirect flow. The final outcome is delivered via webhook once the bank responds.
Updated 8 days ago
