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

We strongly discourage passing card information directly to the API to avoid transmitting card data through systems that are not PCI compliant.

If you are PCI-DSS certified and would like to be able to send cardholder information directly to our APIs from your servers, reach out to us!

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.

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

Send an email and amount to the chargeAPI endpoint along with a 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 code for the supported mobile money providers:

ProviderCodeCountry
MTNmtnGhana
AirtelTigoatlGhana
VodafonevodGhana
M-PesampesaKenya

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

On the successful creation of the charge, you need to handle the response based on the provider selected.

AirtelTigo and MTN

AirtelTigo and MTN requires the customer to complete the transaction process offline, the data.status field would be pay_offline, once you get this status, there's nothing left to do. You're expected to display the data.display_text to your user, and then listen for webhook for transaction notification or requery the verify transaction endpoint at interval.

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}

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

When creating the request for M-Pesa, kindly ensure the phone number is formated using the country code. For example, 0710000000 should be sent as +254710000000.

With M-Pesa, the customer is required to use their PIN to authorize the payment. In the data object, we return a status of pay_offline and a display_text stating that the customer’s authorization is required to complete the payment:

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}

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