iOS SDK

The iOS SDK provides UI components and methods that allow you to accept payments in your iOS app.

Introduction

The iOS SDK is a collection of methods and interfaces that allow you to build a secure and convenient payment flow for your iOS app. Integration is a two-step process:

  1. Initiate the transaction on the server
  2. Complete it on the SDK

Project requirements

The payment UI in the Paystack iOS SDK runs on iOS 14 or later. You can add the package to an app that targets iOS 13, but the payment UI is only available on iOS 14 and later. Before using the SDK, you need to ensure your app meets the following requirements:

  • iOS 14 or later to show the payment UI
  • Xcode 14 or later
  • Swift Package Manager

Installation

The iOS SDK package contains two libraries:

  1. PaystackCore: This contains the APIs and methods for processing payments.
  2. PaystackUI: This contains the UI components to collect the customer's payment information and display the payment status.

You can install these packages via the Swift Package Manager. To add the required packages, ensure you have the latest version of Xcode installed and follow these steps:

  1. Select File > Add Package Dependencies…
  2. Copy the repo URL and paste it into the search box of the package dependency popup
  3. Set the dependency rule to Up to Next Major Version from 1.0.0
  4. Add both the PaystackCore and PaystackUI libraries to your app target

You can read the Swift Package Manager documentation to learn more about adding packages to your project.

Paystack Core

The PaystackCore module uses a builder pattern to handle housekeeping and foundational tasks before the UI components can be used.

1import PaystackCore

The table below shows the methods available on PaystackBuilder:

MethodDescription
setKey("public-key")This method is used to set the public key. Without a public key, you can't complete a transaction.
enableLogging()Turns on debug logs. Logging is off by default.
setDisplayAudience(_:)Specifies who holds the device. .customerFacing, the default, is for customers paying on their own phone. .merchantFacing is for apps where the merchant shows the screen to the customer, such as a point-of-sale app. It applies to every payment you start with this Paystack object. See display audience.
1let paystack = try? PaystackBuilder
2 .newInstance
3 .setKey("pk_domain_xxxxxxxx")
4 .build()

To show the payment UI to customers on a merchant's device, set the display audience when you build the object:

1let paystack = try? PaystackBuilder
2 .newInstance
3 .setKey("pk_domain_xxxxxxxx")
4 .setDisplayAudience(.merchantFacing)
5 .build()
6

Initialize transaction

The SDK requires an access_code to display the UI component that accepts payment. To get the access_code, make a POST request to the Initialize TransactionAPI endpoint from your server:

Show Response
1curl https://api.paystack.co/transaction/initialize
2-H "Authorization: Bearer YOUR_SECRET_KEY"
3-H "Content-Type: application/json"
4-d '{ "email": "[email protected]",
5 "amount": "500000"
6 }'
7-X POST
1{
2 "status": true,
3 "message": "Authorization URL created",
4 "data": {
5 "authorization_url": "https://checkout.paystack.com/nkdks46nymizns7",
6 "access_code": "nkdks46nymizns7",
7 "reference": "nms6uvr1pl"
8 }
9}

On a successful initialization of the transaction, you get a response that contains an access_code. You need to return this access_code back to your mobile app.

Secret key safeguarding

Don't make an API request to the Initialize Transaction endpoint directly on your mobile app because it requires your secret key. Your secret key should only be used on your server where stronger security measures can be put in place.

Paystack UI

The PaystackUI module holds the UI components that manage the payment form and the available payment channels. You can add this module to your project as shown below:

1import PaystackUI

The payment UI supports light and dark mode and follows the device's appearance setting. The PaystackUI module comes with two methods:

  1. chargeUIButton: This is best suited for SwiftUI.
  2. presentChargeUI: This is best suited for UIKit.

chargeUIButton

This method gives you a button that you can customize to show the payment UI. This method takes the following parameters:

ParameterTypeDescription
accessCodeStringThe access code your server receives when it initializes the transaction.
onCompleteCallbackThe callback that handles post-payment processes. Its argument is a TransactionResult.
1paystack?.chargeUIButton(accessCode: "ACCESS_CODE", onComplete: paymentDone) {
2 Text("Initiate Payment")
3}

presentChargeUI

With this method, you create a button that shows the payment UI. The payment UI needs a view controller to present from, so pass a reference to the current view controller with the other parameters in the table below:

ParameterTypeDescription
onUIViewControllerThe view controller of the current view.
accessCodeStringThe access code your server receives when it initializes the transaction.
onCompleteCallbackThe callback that handles post-payment processes. Its argument is a TransactionResult.
1@IBAction func payButtonTapped(_ sender: Any) {
2 paystack?.presentChargeUI(on: self,
3 accessCode: "ACCESS_CODE",
4 onComplete: paymentDone)
5}

Transaction result

The TransactionResult exposes the different states of a transaction. It's the argument type for the PaystackUI onComplete callback:

StateDescription
.completedThe customer completed the payment process. This result contains ChargeCompletionDetails, which includes the transaction reference. Use the reference to verify the transaction status and amount on your server before providing value.
.cancelledThe customer closed the payment UI. This includes closing the error screen shown when the payment can't start, for example when the access code is invalid or the transaction has no channel the SDK supports. The payment can still complete after the customer closes the payment UI, for example a bank transfer that Paystack confirms later, so confirm the final status with your webhook.
.errorThe payment UI hit an error inside a payment channel that it can't recover from. It shows the error message and closes itself after 3 seconds. This result contains a ChargeError and, when available, the transaction reference. The ChargeError has a message you can show the customer and a cause property with the underlying error for your logs.
1func paymentDone(_ result: TransactionResult) {
2 switch (result){
3 case .completed(let details):
4 print("Transaction completed with reference: (details.reference)")
5 case .cancelled:
6 print("Transaction was cancelled")
7 case .error(error: let error, reference: let reference):
8 print("An error occurred: (error.message) with reference: (String(describing: reference))")
9 }
10}

Payment channels

The payment UI shows a payment channel when all three of these are true:

  1. You enabled the channel on your integration.
  2. The channel supports the transaction's currency.
  3. The SDK supports the channel.

If only one channel qualifies, the payment UI opens it immediately. Otherwise, the customer chooses from a list. To limit the channels for a transaction, pass the channels parameter when you initialize the transactionAPI.

The payment UI handles each channel's payment flow for you, then calls onComplete with a TransactionResult.

CountryCurrencyPayment channels
NigeriaNGNCard, Pay with Transfer, and Zap
GhanaGHSCard and mobile money (MTN, AirtelTigo, and Telecel)
KenyaKESCard, mobile money (M-PESA and Airtel Money), and Pesalink
Côte d'IvoireXOFCard
South AfricaZARCard, Capitec Pay, Scan to Pay, and SnapScan

When a channel attempt fails, for example a declined card or an expired session, the payment UI shows the reason and lets the customer try again or choose another channel. onComplete isn't called until the customer completes the payment, cancels it, or the payment UI hits an error it can't recover from.

Display audience

Zap works differently depending on who holds the device. Set the audience with setDisplayAudience(_:) on the Paystack builder:

Channel.customerFacing (default).merchantFacing
ZapOpen Zap buttonQR code to scan with Zap