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 method or Redirect Method, the paying customer will be shown all the available payment methods on the checkout. 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.

Charge API

The charge API allows you to pass details of any payment instrument directly to Paystack, along with the transaction details (email, amount, etc). We cover all the different payment methods in detail below, but in this section, we want to discuss how to handle responses from the charge API. Here is a sample payload to the Charge API containing transaction details and an object for a payment instrument - in this case Mobile money:

1{
2 "amount": 1000,
3 "email": "[email protected]",
4 "currency": "GHS",
5 "mobile_money": {
6 "phone" : "0553241149",
7 "provider" : "MTN"
8 }
9}
10

Handling Charge API responses

When you call the Charge API, the response contains a data.status which tells you what the next step in the process. Depending on the value in the data.status, you may need to prompt the user for an input as indicated in the response message (like OTP or pin or date of birth), or display an action that the user needs to complete on their device - like scanning a QR code or dialling a USSD code or redirecting to a 3DSecure page. So you follow the prompt on the data.status until there is no more user input required, then you can call the verify endpoint to confirm payment.

For the steps that prompt for user input, you will be required to display a form to the user to collect the requested input and send it to the relevant endpoint as shown in the table below. For the steps that require the user to complete an action on their device, we recommend that you display a button for the user to confirm the payment after they have performed that action so that you can call the verify endpoint to confirm the payment.

Below is the list of responses you can receive from the charge endpoint and what you should do next:

ValueDescription
pendingTransaction is being processed. Call Check pending charge at least 10 seconds after getting this status to check status
timeoutTransaction has failed. You may start a new charge after showing data.message to user
successTransaction is successful. Give value after checking to see that all is in order
send_birthdayCustomer's birthday is needed to complete the transaction. Show data.display_text to user with an input that accepts the birthdate and submit to the Submit Birthday endpoint with reference and birthday
send_otpPaystack needs OTP from customer to complete the transaction. Show data.display_text to user with an input that accepts OTP and submit the OTP to the Submit OTP with reference and otp
failedTransaction failed. No remedy for this, start a new charge after showing data.messageto user

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

Where is this available?
This feature is currently only available for Naira collections 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 an account number.

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 filters gateway=emandate & pay_with_bank=true with this filter.

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 code of bank and account_number supplied by customer), birthday to our Charge endpoint as available 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: "[email protected]", amount: "10000", "bank": {
5 "code": "057", "account_number": "0000000000" }}'
6-X POST
1{
2 "status": true,
3 "message":"Charge attempted",
4 "data": {
5 "amount": 10000,
6 "currency":"NGN",
7 "transaction_date":"2017-05-24T05:56:12.000Z",
8 "status": "success",
9 "reference":"zuvbpizfcf2fs7y",
10 "domain":"test",
11 "gateway_response": "Successful",
12 "message": NULL,
13 "channel": "card",
14 "ip_address":"xx.xxx.xxx.xx, xxx.xx.xx.xx"
15 "log": NULL
16 "fees": 3
17 "authorization":{
18 "authorization_code":"AUTH_xxxxxxx"
19 "bin":"408408"
20 "last4":"4081"
21 "exp_month":"12"
22 "exp_year":"2020"
23 "channel":"card"
24 "card_type":"visa visa"
25 "bank":"TEST BANK"
26 "country_code":"NG"
27 "brand":"visa"
28 "reusable":true
29 "signature":"SIG_xxxxxxxxxxxxxx"
30 }
31 "customer":{
32 "id":14571
33 "first_name":NULL
34 "last_name":NULL
35 "email":"[email protected]"
36 "customer_code":"CUS_xxxxxxxxxx"
37 "phone": NULL
38 "metadata": NULL
39 "risk_action":"default"
40 }
41 "plan": NULL
42 }
43}

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.

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
1<?php
2$curl = curl_init();
3 curl_setopt_array($curl, array( CURLOPT_URL => "https://api.paystack.co/charge", CURLOPT_RETURNTRANSFER => true,
4 CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
5 CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => "{
6 "email":"[email protected].nice",
7 "amount":"10000",
8
9 "ussd":{
10 "type": "737"
11 },
12 "metadata":{
13 "custom_fields":[
14 {
15 "value":"makurdi",
16
17 "display_name": "Donation for",
18 "variable_name": "donation_for"
19 }
20 ]
21 }
22}",
23 CURLOPT_HTTPHEADER => array( "Authorization: Bearer sk_test_6e618e981cd81972adc46c2dad0fd319ff7f16f4", "Content-Type: application/json", ),
24));
25$response = curl_exec($curl);
26$err = curl_error($curl);
27curl_close($curl);
28if ($err) {
29 echo "cURL Error #:" . $err;
30} else {
31 echo $response;
32}
33?>
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 },
34 "customer": {
35 "id": 16200,
36 "first_name": "John",
37 "last_name": "Doe",
38 "email": "[email protected]",
39 "customer_code": "CUS_bpy9ciomcstg55y",
40 "phone": "",
41 "metadata": null,
42 "risk_action": "default"
43 },
44 "plan": {
45
46 },
47 "subaccount": {
48
49 },
50 "paidAt": "2018-06-25T12:42:58.000Z"
51 }
52}

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

Mobile money

The Pay via Mobile Money channel allows Ghanaian customers to pay you by entering the phone number enabled for mobile money.

When the customer clicks pay, they will receive a prompt on the mobile device attached to their number asking them to confirm the payment by inputting a PIN.

When the user pays, a response will be sent to your webhook. This means that you must have webhooks set up on your Paystack Dashboard.

Create a charge

Send an email and amount to the chargeAPI endpoint along with a mobile_money object.

The body has the structure:

1{
2 "amount": 100,
3 "email": "[email protected]",
4 "currency": "GHS",
5 "mobile_money": {
6 "phone": "0553241149",
7 "provider": "mtn"
8 }
9}

Provider code

Here are the 3 character code for the 3 supported mobile money providers:

ProviderCharacter code
MTN"mtn"
Vodafone"vod"
Airtel/Tigo"tgo"
1<?php
2
3$curl = curl_init();
4
5curl_setopt_array($curl, array(
6 CURLOPT_URL => "https://api.paystack.co/charge",
7 CURLOPT_RETURNTRANSFER => true,
8 CURLOPT_ENCODING => "",
9 CURLOPT_MAXREDIRS => 10,
10 CURLOPT_TIMEOUT => 30,
11 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
12 CURLOPT_CUSTOMREQUEST => "POST",
13 CURLOPT_POSTFIELDS => "{
14 "amount": 100,
15 "email": "[email protected].com",
16 "currency": "GHS",
17 "mobile_money": {
18 "phone" : "0553241149",
19 "provider" : "mtn"
20 }
21 }",
22 CURLOPT_HTTPHEADER => array(
23 "Authorization: Bearer SECRET_KEY",
24 "Content-Type: application/json"
25 ),
26));
27
28$response = curl_exec($curl);
29$err = curl_error($curl);
30
31curl_close($curl);
32
33if ($err) {
34 echo "cURL Error #:" . $err;
35} else {
36 echo $response;
37}

Airtel 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}

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 },
31 "customer": {
32 "customer_code": "CUS_s3aa4mx0yyvrqye",
33 "email": "[email protected]",
34 "id": 16763,
35 "risk_action": "default"
36 }
37 }
38}

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}

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 },
34 "customer": {
35 "id": 16678,
36 "first_name": "Babafemi",
37 "last_name": "Aluko",
38 "email": "[email protected]",
39 "customer_code": "CUS_2jk1i8ezoam49br",
40 "phone": "",
41 "metadata": null,
42 "risk_action": "allow"
43 },
44 "plan": {},
45 "subaccount": {},
46 "subaccount_group": {},
47 "paidAt": "2018-11-15T06:10:54.000Z"
48 }
49}

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

Test Phone number
The test phone number is 0551234987 and is only available for MTN. No PIN/OTP authorization is required for this phone number.

QR code

The QR option generates a QR code which allows customers to use their bank's mobile app to complete payments. We currently have only Visa QR option available. We'll have more options later.

When the customer scans the code, they authenticate on their bank app to complete the payment.

When the user pays, a response will be sent to your webhook. This means that you need to have webhooks set up on your Paystack Dashboard.

Create a charge

Send an email and amount to the chargeAPI endpoint along with a qr object.

The body has the structure:

1{
2 "amount": 100,
3 "email": "[email protected]",
4 "currency": "NGN",
5 "qr": {
6 "provider": "visa"
7 }
8}
Show Response
1<?php
2$curl = curl_init();
3curl_setopt_array($curl, array(
4 CURLOPT_URL => "https://api.paystack.co/charge",
5 CURLOPT_RETURNTRANSFER => true,
6 CURLOPT_ENCODING => "",
7 CURLOPT_MAXREDIRS => 10,
8 CURLOPT_TIMEOUT => 30,
9 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
10 CURLOPT_CUSTOMREQUEST => "POST",
11 CURLOPT_POSTFIELDS => "{
12 "amount": 100,
13 "email": "[email protected].com",
14 "currency": "NGN",
15 "qr": {
16 "provider" : "visa"
17 }
18 }",
19 CURLOPT_HTTPHEADER => array(
20 "Authorization: Bearer SECRET_KEY",
21 "Content-Type: application/json" ),
22));
23$response = curl_exec($curl);
24$err = curl_error($curl);
25curl_close($curl);
26if ($err) {
27 echo "cURL Error #:" . $err;
28} else {
29 echo $response;
30}
31?>
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}
11

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 },
34 "customer": {
35 "id": 16787,
36 "first_name": "I",
37 "last_name": "SURRENDER",
38 "email": "[email protected]",
39 "customer_code": "CUS_ehg851zbxon0bvx",
40 "phone": "",
41 "metadata": null,
42 "risk_action": "default"
43 },
44 "plan": {},
45 "subaccount": {},
46 "subaccount_group": {},
47 "paidAt": "2018-12-05T15:58:45.000Z"
48 }
49}

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