Accept Payments

In A Nutshell
In a nutshell

To accept a payment, create a transaction using our API, our client Javascript library, Popup JS, or our SDKs. Every transaction includes a link that can be used to complete payment.

Paystack Popup provides a simple and convenient payment flow for web. It can be integrated in five easy steps, making it the easiest way to start accepting payments. See demo of the payment methods on the checkout here.

Collect customer information

To initialize the transaction, you need to pass information such as email, amount, transaction reference, etc. The key, email and amount parameters are the only required parameters. The table below lists the parameters that you can pass when initializing a transaction.

keyYesYour public key from Paystack. Use test key for test mode and live key for live mode
emailYesEmail address of customer
amountYesAmount in the subunit of the supported currency you are debiting customer. Do not pass this if creating subscriptions.
refNoUnique case sensitive transaction reference. Only -,., =and alphanumeric characters allowed. If you do not pass this parameter, Paystack will generate a unique reference for you.
currencyNoOn of the supported currency the charge should be performed in. It defaults to your integration currency.
channelsNoAn array of payment channels to control what channels you want to make available to the user to make a payment with. Available channels include; ['card', 'bank', 'ussd', 'qr', 'mobile_money', 'bank_transfer']
metadataNoObject containing any extra information you want recorded with the transaction. Fields within the custom_field object will show up on merchant receipt and within the transaction information on the Paystack Dashboard. You can learn more on the Metadata page.
labelNoString that replaces customer email as shown on the checkout form
callbackNoFunction that runs when payment is successful. This should ideally be a script that uses the verify endpoint on the Paystack API to check the status of the transaction.
onCloseNoJavascript function that is called if the customer closes the payment window instead of making a payment.
onBankTransferConfirmationPendingNoJavascript function that is called if the customer clicks on Close Checkout before we receive their bank transfer. (This only applies to Pay-with-Transfer transactions)
For single split payments
subaccountYesThe code for the subaccount that owns the payment. e.g. ACCT_8f4s1eq7ml6rlzj
transaction_chargeNoA flat fee to charge the subaccount for this transaction, in the subunit of the supported currency. This overrides the split percentage set when the subaccount was created. Ideally, you will need to use this if you are splitting in flat rates (since subaccount creation only allows for percentage split).
bearerNoDecide who will bear Paystack transaction charges between account and subaccount. Defaults to account.
For multi-split payments
split_codeYesThe split code of the transaction split. e.g. SPL_98WF13Eb3w
For subscriptions
planYesPlan code generated from creating a plan. This makes the payment become a subscription payment.
quantityNoUsed to apply a multiple to the amount returned by the plan code above.

The customer information can be retrieved from your database if you already have it stored, or from a form like in the example below:

1<form id="paymentForm">
2 <div class="form-group">
3 <label for="email">Email Address</label>
4 <input type="email" id="email-address" required />
5 </div>
6 <div class="form-group">
7 <label for="amount">Amount</label>
8 <input type="tel" id="amount" required />
9 </div>
10 <div class="form-group">
11 <label for="first-name">First Name</label>
12 <input type="text" id="first-name" />
13 </div>
14 <div class="form-group">
15 <label for="last-name">Last Name</label>
16 <input type="text" id="last-name" />
17 </div>
18 <div class="form-submit">
19 <button type="submit" onclick="payWithPaystack()"> Pay </button>
20 </div>
23<script src=""></script>

In this sample, notice how:

  1. The Paystack inline javascript is included using a script tag. This is how you import Paystack into your code.
  2. The amount here can be hardcoded if you want to charge a specific amount.
  3. The Pay button has been tied to an onClick function called payWithPaystack. This is the action that causes the Paystack popup to load.
Helpful Tip

If you don't collect email addresses from your customer, you can generate an email address using the information you have alongside your website url. E.g, if you only collect phone numbers from your customers, you can create email addresses like

Initialize transaction

When you have all the details needed to initiate the transaction, the next step is to tie them to the javascript function that passes them to Paystack and displays the checkout popup modal.

1var paymentForm = document.getElementById('paymentForm');
2paymentForm.addEventListener('submit', payWithPaystack, false);
3function payWithPaystack() {
4 var handler = PaystackPop.setup({
5 key: 'YOUR_PUBLIC_KEY', // Replace with your public key
6 email: document.getElementById('email-address').value,
7 amount: document.getElementById('amount').value * 100, // the amount value is multiplied by 100 to convert to the lowest currency unit
8 currency: 'NGN', // Use GHS for Ghana Cedis or USD for US Dollars
9 ref: 'YOUR_REFERENCE', // Replace with a reference you generated
10 callback: function(response) {
11 //this happens after the payment is completed successfully
12 var reference = response.reference;
13 alert('Payment complete! Reference: ' + reference);
14 // Make an AJAX call to your server with the reference to verify the transaction
15 },
16 onClose: function() {
17 alert('Transaction was not completed, window closed.');
18 },
19 });
20 handler.openIframe();
Important notes
  1. The key field here takes your Paystack public key.
  2. The amount should be in the subunit of the supported currency.
  3. It's ideal to generate a unique reference from your system for every transaction to avoid duplicate attempts.
  4. The callback method is called when payment has been completed successfully on the Paystack checkout. See the next section to see for how to handle the callback.
  5. the onClose method is called if the user closes the modal without completing payment.

Handle the callback method

The callback method is triggered when the transaction is completed. This is where you verify the transaction status.

Helpful Tip

To verify the transaction, you have to set up a route or page on your server that you pass the transaction reference to. From your server, you call the Paystack verify endpoint to confirm the status of the transaction. You should then return the response to your frontend.

In your callback function, you should make a request to your server where the verification is performed:

1callback: function(response){
2 // make API request to your server or serveless function here
Do not use your secret key in your frontend

Never call the Paystack API directly from your frontend to avoid exposing your secret key on the frontend. All requests to the Paystack API should be initiated from your server, and your frontend gets the response from your server.

Verify the transaction status

After payment is made, the next step is to confirm the status of the transaction. A transaction can be confirmed by using either webhooks or the verify transactions endpoint. Regardless of the method used, you need to use the following parameter to confirm if you should deliver value to your customer or not:

data.statusThis inidicates if the payment is successful or not
data.amountThis indicates the price of your product or service in the lower denomination (e.g for NGN 50, you'd see 5000 and so on)
Verify amount

When verifying the status of a transaction, you should also verify the amount to ensure it matches the value of the service you are delivering. If the amount doesn't match, do not deliver value to the customer.


Here, you call the Initialize TransactionAPI from your server to generate a checkout link, then redirect your users to the link so they can pay. After payment is made, the users are returned to your website at the callback_url


Confirm that your server can conclude a TLSv1.2 connection to Paystack's servers. Most up-to-date software have this capability. Contact your service provider for guidance if you have any SSL errors.

Collect customer information

To initialize the transaction, you'll need to pass information such as email, first name, last name amount, transaction reference, etc. Email and amount are required. You can also pass any other additional information in the metadata object field.

The customer information can be retrieved from your database, session or cookie if you already have it stored, or from a form like in the example below.

1<form action="/save-order-and-pay" method="POST">
2 <input type="hidden" name="user_email" value="<?php echo $email; ?>">
3 <input type="hidden" name="amount" value="<?php echo $amount; ?>">
4 <input type="hidden" name="cartid" value="<?php echo $cartid; ?>">
5 <button type="submit" name="pay_now" id="pay-now" title="Pay now">Pay now</button>

Initialize transaction

When a customer clicks the payment action button, initialize a transaction by making a POST request to our API. Pass the email, amount and any other parameters to the Initialize TransactionAPI endpoint.

If the API call is successful, we will return an authorization URL which you will redirect to for the customer to input their payment information to complete the transaction.

Important notes

  1. The amount should be in the subunit of the supported currency.
  2. We used the cart_id from the form above as our transaction reference. You should use a unique transaction identifier from your system as your reference.
  3. We set the callback_url in the transaction_data array. If you don't do this, we'll use the one that is set on your dashboard. Setting it in the code allows you to be flexible with the redirect URL if you need to
  4. If you don't set a callback URL on the dashboard or on the code, the users will not be redirected back to your site after payment.
  5. You can set test callback URLs for test transactions and live callback URLs for live transactions.
2 $url = "";
4 $fields = [
5 'email' => "",
6 'amount' => "20000"
7 ];
9 $fields_string = http_build_query($fields);
11 //open connection
12 $ch = curl_init();
14 //set the url, number of POST vars, POST data
15 curl_setopt($ch,CURLOPT_URL, $url);
16 curl_setopt($ch,CURLOPT_POST, true);
17 curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
18 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
19 "Authorization: Bearer SECRET_KEY",
20 "Cache-Control: no-cache",
21 ));
23 //So that curl_exec returns the contents of the cURL; rather than echoing it
24 curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
26 //execute post
27 $result = curl_exec($ch);
28 echo $result;

Verify Transaction

If the transaction is successful, Paystack will redirect the user back to a callback_url you set. We'll append the transaction reference in the URL. In the example above, the user will be redirected to

So you retrieve the reference from the URL parameter and use that to call the verify endpoint to confirm the status of the transaction. Learn more about verifying transactions.

It's very important that you call the Verify endpoint to confirm the status of the transactions before delivering value. Just because the callback_url was visited doesn't prove that transaction was successful.

Handle Webhook

When a payment is successful, Paystack sends a charge.success webhook event to webhook URL that you provide. Learn more about using webhooks.

Mobile SDKs

You can integrate Paystack directly into your Android or iOS app using our mobile SDK. For mobile frameworks like Ionic or React Native, please find the libraries here.

Charge API

The Create ChargeAPI endpoint allows you to pass details of any payment channel directly to Paystack, along with the transaction details (email, amount, etc). We provide a couple of payment channels that you can harness based on your use case.

Use cases

The Charge API exposes the core components powering our checkout. Developers can use these component to develop solutions that will cater to their customers specific needs. Some of these needs include:

  1. Serving non-smartphone users. Some of your users might be using mobile phones that can't access the internet. With the charge API, you can initiate a payment request form your server and send a prompt for payment completion via phone numbers to these users.
  2. Harnessing mobile OS APIs for a better user experience. Some businesses offer their products via mobile apps (Android and iOS). Mobile operating systems provide a rich set of APIs that developers can take advantage of. One of such APIs allow developers to autofill an OTP in a form. There are also APIs for dialing codes. Developers can combine the charge API with the mobile OS APIs to provide a richer experience to their users.

Here is a sample payload to the Charge API containing transaction details and an object for a payment instrument - in this case Mobile money:

2 "amount": 1000,
3 "email": "",
4 "currency": "GHS",
5 "mobile_money": {
6 "phone": "0553241149",
7 "provider": "MTN"
8 }

Handling Charge API responses

When you call the Create ChargeAPI endpoint, 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 listen for events via webhooks.

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 listen for events via webhooks.

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

pendingTransaction is being processed. Call Check pending charge at least 10seconds 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. You can now provide value
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 BirthdayAPI 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 OTPAPI endpoint with reference and otp
failedTransaction failed. No remedy for this, start a new charge after showing data.message to user

Handle Webhook

When a payment is successful, Paystack sends a charge.success webhook event to webhook URL that you provide. It is highly recommended that you use webhooks to confirm the payment status before delivering value to your customers.