Payment Channels

In A Nutshell
In a nutshell

Paystack enables you accept payments from customers using different payment channels such as: cards, mobile money accounts, QR codes, directly from their bank account or USSD.

If you use the the Popup or Redirect method, the paying customer will be shown all the payment methods selected on your dashboard. But if you don't want to use either option, you can initiate all the different payment channels directly from your server using the Charge API.

What channels are available?

Card payment channels are available on all Paystack accounts, while the other payment channels are only available in countries where they are supported.

Cards

Feature Availability

The Card API is available in all our markets for businesses that are PCI Compliant. If you intend to use this API, you should check the compliance requirements outlined below and reach out to us.

The Cards API allows you to send card details securely and compliantly to our server from your custom checkout. With this, PCI-DSS complaint businesses can build bespoke checkout experiences without compromising on security.

The sensitivity of card details requires businesses to adhere to the Payment Card Industry Data Security Standards (PCI-DSS), to ensure that they are securely processed. Paystack adheres to this as a PCI Level 1 Service Provider, allowing non-complaint businesses to use our Checkout and Mobile SDKs for card payments

Compliance Requirements

PCI-DSS certification documents can only be issued on behalf of the PCI Council by an accredited Qualified Security Assessor (QSA) after an audit.

The documents issued by the council are the Attestation of Compliance (AOC) and Report on Compliance. These documents are only valid for one year from the dated they were signed. We require you to submit these documents before you’re allowed to use this API.

For Paystack, a valid AOC needs to show the following:

  1. Issued after an audit by a QSA
  2. Signed off by a QSA
  3. Within one year of issue date
  4. Has the PCI SSC logo on the cover page
  5. Adheres to at least version 3.2.1 of PCI-DSS

If you have met the criteria above please submit your documents to support@paystack.com or through your Paystack relationship manager and we'll grant access to the APIs.

Bank accounts

Feature availability

This feature is currently available to businesses in Nigeria.

The Pay with Bank feature allows customers pay through internet banking portal or by providing their bank account number and authenticating using an OTP sent to their phone or email.

This is different from Bank Transfers where customers transfer money into a bank account.

Collect bank details

To collect bank details, you would need to prompt the user to select their bank and enter their account number. To fetch the list of supported banks, make a GET request to the list banksAPI endpoint, with the additional filter pay_with_bank=true.

The banks can be listed in a dropdown or any other format that allows the user to easily pick their bank of choice.

Create a charge

Send email, amount, metadata, bank (an object that includes the code of the bank and account_number supplied by customer) and birthday to our Charge endpoint to start.

Show Response
1curl https://api.paystack.co/charge
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{ "email": "customer@email.com",
5 "amount": "10000",
6 "bank": {
7 "code": "057",
8 "account_number": "0000000000"
9 }
10 }'
11-X POST
1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "z8q981z5kp7sfde",
6 "status": "send_birthday",
7 "display_text": "Please enter your birthday"
8 }
9}

If the selected bank is Kuda, you need to make use of phone and token instead of account_number in the bank object:

Show Response
1curl https://api.paystack.co/charge
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{ "email": "customer@email.com",
5 "amount": "10000",
6 "bank": {
7 "code": "50211",
8 "phone": "+2348100000000",
9 "token": "123456"
10 }
11 }'
12-X POST
13
1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "z8q981z5kp7sfde",
6 "status": "pending",
7 "display_text": "Processing transaction"
8 }
9}

When the API call is made, the value of the data.status key is pending as the payment is being processed in the background. The data.status then updates to either, success or failed depending on whether the transaction was successful or not.

Pay with Transfer

Feature availability

This feature is currently available to businesses in Nigeria and merchants need to reach out to support@paystack.com to enable it on their integration.

Pay with Transfer (PwT) is a feature that allow merchants or businesses create temporary bank accounts that customers can use to pay for goods or services. The account number is generated and tied to the current customer’s transaction. The account number becomes invalid after the customer’s transaction or when it exceeds it’s expiry time.

Create a PwT charge

At the point of payment, you initiate a request to the Create ChargeAPI endpoint, passing the email, amount and bank_transfer object. The bank_transfer object takes the account_expires_at which is used to set the expiry of an account number for a transaction:

Show Response
1#!/bin/sh
2
3url="https://api.paystack.co/charge"
4authorization="Authorization: Bearer YOUR_SECRET_KEY"
5content_type="Content-Type: application/json"
6data='{
7 "email": "another@one.com",
8 "amount": "25000",
9 "bank_transfer": {
10 "account_expires_at": "2023-09-12T13:10:00Z"
11 }
12}'
13
14curl "$url" -H "$authorization" -H "$content_type" -d "$data" -X POST
1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "status": "pending_bank_transfer",
6 "display_text": "Please make a transfer to the account specified",
7 "reference": "4tn28gwznc",
8 "amount": 20000,
9 "account_name": "PAYSTACK CHECKOUT",
10 "account_number": "1231084927",
11 "bank": {
12 "slug": "test-bank",
13 "name": "Test Bank",
14 "id": 24
15 },
16 "account_expires_at": "2023-09-12T13:10:55.000Z"
17 }
18}
Bank Transfer ParamTypeDescription
account_expires_atStringAccount validity period in ISO 8601 format (YYYY-MM-DDThh:mm:ssZ). Minimum time is 15 mins from the current time and maximum time is 8 hours from the current time. You can also set this to null so we automatically set it to 8 hours from the current time.
Account expiry

If the difference between account_expires_at and the current time is less than 15 mins we will default to a 15 mins. If the difference between account_expires_at and the current time exceeds 8 hours we will default to 8 hours.

If you need to control the transfers your business receives you should implement Inbound Transfer Approvals . This enables you to reject or accept transfers based on your various business requirements.

Verifying transfer

Receiving notifications

To receive notifications, you need to implement a webhook URL and set the webhook URL on your Paystack Dashboard

A bank transfer is initiated by a customer and processed by their bank. In order to confirm payment, you need to implement webhooks and listen to the following events:

EventDescription
charge.successThis is sent when the customer’s transfer is successful.
bank.transfer.rejectedThis is sent when the customer either sent an incorrect amount or when the customer has been flagged by our fraud system.
1{
2 "event": "charge.success",
3 "data": {
4 "id": 3104021987,
5 "domain": "test",
6 "status": "success",
7 "reference": "zuz8ggd1ro",
8 "amount": 25000,
9 "message": null,
10 "gateway_response": "Approved",
11 "paid_at": "2023-09-12T13:29:09.000Z",
12 "created_at": "2023-09-12T13:27:50.000Z",
13 "channel": "bank_transfer",
14 "currency": "NGN",
15 "ip_address": "172.91.42.100",
16 "metadata": "",
17 "fees_breakdown": null,
18 "log": null,
19 "fees": 375,
20 "fees_split": null,
21 "authorization": {
22 "authorization_code": "AUTH_q5nfynycgm",
23 "bin": "008XXX",
24 "last4": "X553",
25 "exp_month": "09",
26 "exp_year": "2023",
27 "channel": "bank_transfer",
28 "card_type": "transfer",
29 "bank": null,
30 "country_code": "NG",
31 "brand": "Managed Account",
32 "reusable": false,
33 "signature": null,
34 "account_name": null,
35 "sender_country": "NG",
36 "sender_bank": null,
37 "sender_bank_account_number": "XXXXXXX553",
38 "sender_name": "Jadesola Oluwashina",
39 "narration": "Channel Tests"
40 },
41 "customer": {
42 "id": 138496675,
43 "first_name": null,
44 "last_name": null,
45 "email": "another@one.com",
46 "customer_code": "CUS_1eq06yu8efl8u63",
47 "phone": null,
48 "metadata": null,
49 "risk_action": "default",
50 "international_format_phone": null
51 },
52 "plan": {},
53 "subaccount": {},
54 "split": {},
55 "order_id": null,
56 "paidAt": "2023-09-12T13:29:09.000Z",
57 "requested_amount": 25000,
58 "pos_transaction_data": null,
59 "source": {
60 "type": "api",
61 "source": "merchant_api",
62 "entry_point": "charge",
63 "identifier": null
64 }
65 }
66}

Alternatively, you can use the Check Pending ChargeAPI endpoint to manually verify the status of the transaction.

USSD

This Payment method is specifically for Nigerian customers. Nigerian Banks provide USSD services that customers use to perform transactions, and we've integrated with some of them to enable customers complete payments.

The Pay via USSD channel allows your Nigerian customers to pay you by dialling a USSD code on their mobile device. This code is usually in the form of * followed by some code and ending with #. The user is prompted to authenticate the transaction with a PIN and then it is confirmed.

All you need to initiate a USSD charge is the customer email and the amount to charge.

When the user pays, a response will be sent to your webhook. Hence, for this to work properly as expected, webhooks must be set up on your Paystack Dashboard.

Create a charge

Send an email and amount to the chargeAPI endpoint. Specify the USSD type you are charging as well.

Below are all the USSD types we support. We'll add to list as we have more:

BankType
Guaranty Trust Bank737
United Bank of Africa919
Sterling Bank822
Zenith Bank966
Show Response
1curl https://api.paystack.co/charge
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{ "email": "some@body.nice",
5 "amount":"10000",
6 "ussd": {
7 "type": "737"
8 },
9 "metadata": {
10 "custom_fields":[{
11 "value": "makurdi",
12 "display_name": "Donation for",
13 "variable_name": "donation_for"
14 }]
15 }
16 }'
17-X POST
1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "yjr1r8rwhedara4",
6 "status": "pay_offline",
7 "display_text": "Please dial *737*33*4*18791# on your mobile phone to complete the transaction",
8 "ussd_code": "*737*33*4*18791#"
9 }
10}

When a charge is made, the default response provides a USSD code for the customer to dial to complete the payment.

Handle response

When the user completes payment, a response is sent to the merchant’s webhook. Hence, for this to work properly as expected, webhooks must be set up for the merchant..

The charge.success event is raised on successful payment. The sample response to be sent to the user’s webhook would look like:

1{
2 "event": "charge.success",
3 "data": {
4 "id": 53561,
5 "domain": "live",
6 "status": "success",
7 "reference": "2ofkbk0yie6dvzb",
8 "amount": 150000,
9 "message": "madePayment",
10 "gateway_response": "Payment successful",
11 "paid_at": "2018-06-25T12:42:58.000Z",
12 "created_at": "2018-06-25T12:38:59.000Z",
13 "channel": "ussd",
14 "currency": "NGN",
15 "ip_address": "54.246.237.22, 162.158.38.185, 172.31.15.210",
16 "metadata": "",
17 "log": null,
18 "fees": null,
19 "fees_split": null,
20 "authorization": {
21 "authorization_code": "AUTH_4c6mhnmmeusp4yd",
22 "bin": "XXXXXX",
23 "last4": "XXXX",
24 "exp_month": "05",
25 "exp_year": "2018",
26 "channel": "ussd",
27 "card_type": "offline",
28 "bank": "Guaranty Trust Bank",
29 "country_code": "NG",
30 "brand": "offline",
31 "reusable": false,
32 "signature": null,
33 "account_name": null
34 },
35 "customer": {
36 "id": 16200,
37 "first_name": "John",
38 "last_name": "Doe",
39 "email": "customer@email.com",
40 "customer_code": "CUS_bpy9ciomcstg55y",
41 "phone": "",
42 "metadata": null,
43 "risk_action": "default"
44 },
45 "plan": {},
46 "subaccount": {},
47 "paidAt": "2018-06-25T12:42:58.000Z"
48 }
49}
USSD recurring charge

Charging returning customers directly is not currently available. Simply call the endpoint to start a new transaction.

Mobile money

Feature Availability

This feature is only available to businesses in Ghana and Kenya.

The Mobile Money channel allows your customers to pay you by using their phone number enabled for mobile money. At the point of payment, the customer is required to authorize the payment on the mobile phones.

Since payment is completed offline, you need to have a webhook URL  which we’ll use to send the final status of the payment to your server.

Create a charge

To initiate a charge for mobile money, you need to make a POST request to the chargeAPI passing the customer’s email, amount, and mobile_money object:

1curl https://api.paystack.co/charge
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{ "amount": 100,
5 "email": "customer@email.com",
6 "currency": "GHS",
7 "mobile_money": {
8 "phone" : "0551234987",
9 "provider" : "mtn"
10 }
11 }'
12-X POST

Provider code

Here are the character codes for the supported mobile money providers:

ProviderCodeCountry
MTNmtnGhana
ATMoney & Airtel MoneyatlGhana and Kenya
VodafonevodGhana
M-PESAmpesaKenya

All providers, except Vodafone, rely on the customer completing the transaction offline. The data.status field will be pay_offline, and the customer will be prompted to authorise the transaction on their phones. You should show the customer the data.display_text and then listen for the charge.success webhook event. The transaction should be completed within 180 seconds, after which the transactions fail. This is a limitation set by the network providers.

Here is a sample response that requires the customer to complete the process offline:

1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "8nn5fqljd0suybr",
6 "status": "pay_offline",
7 "display_text": "Please complete authorization process on your mobile phone"
8 }
9}
Transaction Verification

You should call the Verify TransactionAPI endpoint after the 180 seconds to get the status and reason of the transaction failure. This is found in the data.message parameter in the response.

Vodafone

For Vodafone, the customer is required to generate a voucher code by dialing the USSD code show in the data.display_text field, this voucher code should be collected and passed to the submit OTPAPI endpoint to authorize the transaction.

1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "r13havfcdt7btcm",
6 "status": "send_otp",
7 "display_text": "Please dial *110# to generate a voucher code. Then input the voucher"
8 }
9}

If the mobile money customer enters the otp on time and we are able to get a response just in time, we return the success response:

1{
2 "message": "Charge attempted",
3 "status": true,
4 "data": {
5 "amount": 100,
6 "channel": "mobile_money",
7 "created_at": "2018-11-17T14:39:56.000Z",
8 "currency": "GHS",
9 "domain": "live",
10 "fees": 153,
11 "gateway_response": "Approved",
12 "id": 59333,
13 "ip_address": "35.177.189.123, 162.158.155.220",
14 "message": "madePayment",
15 "paid_at": "2018-11-17T14:40:18.000Z",
16 "reference": "l7lvu4y3xcka6zu",
17 "status": "success",
18 "transaction_date": "2018-11-17T14:39:56.000Z",
19 "authorization": {
20 "authorization_code": "AUTH_33lz7ev5tq",
21 "bank": "MTN Mobile Money",
22 "bin": "055XXX",
23 "brand": "Mtn mobile money",
24 "channel": "mobile_money",
25 "country_code": "GH",
26 "exp_month": 12,
27 "exp_year": 9999,
28 "last4": "X149",
29 "reusable": false,
30 "account_name": null
31 },
32 "customer": {
33 "customer_code": "CUS_s3aa4mx0yyvrqye",
34 "email": "customer@email.com",
35 "id": 16763,
36 "risk_action": "default"
37 }
38 }
39}

If the transaction is started successfully and the pin is not entered on time, we return this:

1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "84oow6t0rf715g6",
6 "status": "pending"
7 }
8}

M-PESA

Feature Availability

M-PESA allows Kenya-based businesses to charge individual customers and M-PESA Till numbers.

With M-PESA merchants can charge individual users using their phone number. We recommend that you include the country code in the phone number. For example, 0722000000 should be sent as +254722000000 to the chargeAPI endpoint. The customer will be prompted to enter their PIN to complete the transaction.

M-PESA Till

You can also get paid by other businesses from their M-PESA Till numbers. The mobile_money object should have provider set to mptill and the account which is the other business's M-PESA Till number. They will receive a prompt on the phone assigned the till for authorization.

1curl https://api.paystack.co/charge
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{ "amount": 100,
5 "email": "customer@email.com",
6 "currency": "KES",
7 "mobile_money": {
8 "account" : "1234567",
9 "provider" : "mptill"
10 }
11 }'
12-X POST

Both M-PESA Till and individual require the customer to authorise the transaction on their phones. As such you should show them the display_text value when building a custom experience.

1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "jq3psd5n96sprwl",
6 "status": "pay_offline",
7 "display_text": "Please complete authorization process on your mobile phone"
8 }
9}
Transaction Verification

Since M-PESA transactions happen asynchronously, failures due to customer errors aren’t captured easily. We recommend you implement Verify Transactions when they take too long to get completed.

Handle response

When the user completes payment, a response is sent to the merchant’s webhook. Hence, for this to work properly as expected, webhooks must be set up for the merchant.

The charge.success event is raised on successful payment. The sample response to be sent to the user’s webhook would look like:

1{
2 "event": "charge.success",
3 "data": {
4 "id": 59214,
5 "domain": "live",
6 "status": "success",
7 "reference": "gf4n3ykzj6a7u89",
8 "amount": 100,
9 "message": "madePayment",
10 "gateway_response": "Approved",
11 "paid_at": "2018-11-15T06:10:54.000Z",
12 "created_at": "2018-11-15T06:10:32.000Z",
13 "channel": "mobile_money",
14 "currency": "GHS",
15 "ip_address": "18.130.236.148, 141.101.99.73",
16 "metadata": "",
17 "log": null,
18 "fees": 153,
19 "fees_split": null,
20 "authorization": {
21 "authorization_code": "AUTH_0aqm8ddx6s",
22 "bin": "055XXX",
23 "last4": "X149",
24 "exp_month": "12",
25 "exp_year": "9999",
26 "channel": "mobile_money",
27 "card_type": "",
28 "bank": "MTN Mobile Money",
29 "country_code": "GH",
30 "brand": "Mtn mobile money",
31 "reusable": false,
32 "signature": null,
33 "account_name": "BoJack Horseman"
34 },
35 "customer": {
36 "id": 16678,
37 "first_name": "Babafemi",
38 "last_name": "Aluko",
39 "email": "customer@email.com",
40 "customer_code": "CUS_2jk1i8ezoam49br",
41 "phone": "",
42 "metadata": null,
43 "risk_action": "allow"
44 },
45 "plan": {},
46 "subaccount": {},
47 "subaccount_group": {},
48 "paidAt": "2018-11-15T06:10:54.000Z"
49 }
50}

Charging returning customers directly is not currently available. Simply call the endpoint to start a new transaction. We have some test credentials that can be used to run some tests.

EFT

EFT payments are an instant bank transfer payment method where customers pay merchants through their internet banking interfaces. When the developer specifies an EFT provider, we do a redirect to the providers platform where the customer provides their payment details after which the payment is authorized.

Where is this available?

This feature is only available to South African customers.

Create a charge

You need to send the email, amount, currency, and the EFT provider to the chargeAPI endpoint:

Show Response
1curl https://api.paystack.co/charge
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{
5 "amount": 5000,
6 "currency": "ZAR",
7 "email": "customer@email.com",
8 "eft": {
9 "provider": "ozow"
10 }
11}'
12-X POST
1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "18c0ywb63zutno0",
6 "status": "open_url",
7 "url": "https://crayon.paystack.co/eft/EFT_OZOW/121502"
8 }
9}
Available Providers

Ozow is currently the only provider available.

Handle response

When the user completes payment, a response is sent to the merchant’s webhook. The merchant needs to setup webhooks to get the status of the payment. The charge.success event is raised on successful payment.

QR code

The QR option generates a QR code that allow customers to use a supported mobile app to complete payments.

When the customer scans the code, they authenticate on a supported app to complete the payment. When the user pays, a response will be sent to your webhook. This means that you need to implement and set a webhook URL on your Paystack Dashboard.

Create a charge

Send an email and amount to the chargeAPI endpoint along with a qr object. The qr object should contain a provider parameter, specifying the QR provider for the transaction. The available QR providers are:

ProviderAvailability
scan-to-paySouth Africa
visaNigeria
Supported Apps

The scan-to-pay provider supports both SnapScan and Scan to Pay (formerly Masterpass) supported apps for completing a payment.

Show Response
1curl https://api.paystack.co/charge
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{ "amount": 100,
5 "email": "customer@email.com",
6 "currency": "NGN",
7 "qr": {
8 "provider" : "visa"
9 }
10 }'
11-X POST
1{
2 "status": true,
3 "message": "Charge attempted",
4 "data": {
5 "reference": "48rx32f1womvcr4",
6 "status": "pay_offline",
7 "qr_code": "0002010216421527000104176552045499530356654031005802NG5920Babafemi enterprises6005Lagos62230519PSTK_104176000926|16304713a",
8 "url": "https://files.paystack.co/qr/visa/104176/Babafemi_enterprises_visaqr_1544025482956.png"
9 }
10}

Handle response

When the user completes payment, a response is sent to the merchant’s webhook. Hence, for this to work properly as expected, webhooks must be set up for the merchant.

The charge.success event is raised on successful payment. The sample response to be sent to the user’s webhook would look like:

1{
2 "event": "charge.success",
3 "data": {
4 "id": 59565,
5 "domain": "test",
6 "status": "success",
7 "reference": "48rx32f1womvcr4",
8 "amount": 10000,
9 "message": "madePayment",
10 "gateway_response": "Payment successful",
11 "paid_at": "2018-12-05T15:58:45.000Z",
12 "created_at": "2018-12-05T15:58:02.000Z",
13 "channel": "qr",
14 "currency": "NGN",
15 "ip_address": "18.130.45.28, 141.101.107.157",
16 "metadata": "",
17 "log": null,
18 "fees": null,
19 "fees_split": null,
20 "authorization": {
21 "authorization_code": "AUTH_2b4zs69fgy7qflh",
22 "bin": "483953",
23 "last4": "6208",
24 "exp_month": "12",
25 "exp_year": "2018",
26 "channel": "qr",
27 "card_type": "DEBIT",
28 "bank": "Visa QR",
29 "country_code": "NG",
30 "brand": "VISA",
31 "reusable": false,
32 "signature": null,
33 "account_name": "BoJack Horseman"
34 },
35 "customer": {
36 "id": 16787,
37 "first_name": "I",
38 "last_name": "SURRENDER",
39 "email": "customer@email.com",
40 "customer_code": "CUS_ehg851zbxon0bvx",
41 "phone": "",
42 "metadata": null,
43 "risk_action": "default"
44 },
45 "plan": {},
46 "subaccount": {},
47 "subaccount_group": {},
48 "paidAt": "2018-12-05T15:58:45.000Z"
49 }
50}
QR code recurring charge

Charging returning customers directly is currently not available. You need to call the endpoint to start a new transaction.

Supported Apps

In order to complete a payment, your customers can scan or enter the code in a supported application. Here are the supported applications by providers:

Visa

Customers can scan Visa QR codes from the following banking apps:

  • Ecobank
  • First Bank
  • Fidelity Bank
  • Access Bank
  • Access (Diamond) Bank
  • Zenith Bank

SnapScan

Customers can complete a payment in a snap by scanning the QR code with their SnapScan iOS or Android app.

Scan to Pay

Customers can use Scan to Pay (formerly Masterpass) QR codes from any of the mobile apps listed below:

Banking AppsWalletsStandalone Scan to Pay
Standard BankUkhesheNedbank Scan to Pay
FNB BankingSpot (by Virgin Money)Standard Bank Scan to Pay
Nedbank MoneyVodapayAbsa Scan to Pay
Capitec BankTelkom Pay
AbsaInstapay
RMBNedbank Avo