Payments
Integrate Volume SDK
iOS
Get Started

Quick Start

Let's get started with Volume in less than 5 minutes.

iOS xcframework for Volume is a library with custom view that allows you to display Volume checkout and start accepting payments from your customers in zero time into any iOS app.

Getting Started

Get started by installing VolumeComponent xcframework.

via Cocoapod

   platform :ios, '14.0'
    source 'https://github.com/CocoaPods/Specs.git'
    source 'https://' + ENV['GIT_AUTHORIZATION'] + '@github.com/getvolume/VolumePods.git'
 
    target 'SampleApp' do
      use_frameworks!
      pod 'Alamofire'
      pod 'VolumePayComponent', '2.7.1'
    end

Where GIT_AUTHORIZATION is environment variable made of github user and it's token volume-public:<token> in that manner. Token is provided by Volume.

e.g. volume-public:github_pat_72A4HWM8I0LwB3_T0kenProv1dedByV0lume__V3o9ZRvFBM5cmENW8vf8ES365KNJ7b6u7gY1

The best way to do this is to export shell variable as:

   export GIT_AUTHORIZATION=volume-public:github_pat_72A4HWM8I0LwB3_T0kenProv1dedByV0lume__V3o9ZRvFBM5cmENW8vf8ES365KNJ7b6u7gY1

this will work only in your current terminal session if you prefer more permanent solution please consider adding this command to your .bashrc or .zshrc.

If you will encounter Cocoapod bug with runtime error: RuntimeError - [Xcodeproj] Unknown object version (56). the solution is described in stackoverflow (opens in a new tab)

Volume Provider & Volume Button

The volume provider should be placed at the root level of your application, this provides key global configuration for using volume in your application. When VolumeProvider is initialized then you can add Volume button to your screen by adding VolumeButtonComponent to ExampleAppView struct.

import VolumePayComponent
 
@main
struct ExampleApp: App {
 
    init() {
        do {
            try volumeProvider.initialize(
                    volumeSetup: VolumeSetup(
                            applicationId: "", //provided by Volume
                            volumeEnvironment: "sandbox",
                            volumeEventListener: DefaultVolumeEventListener { message in
                                debugPrint(message)
                            },
                            showSandboxBanks: true,
                            maxPaymentAmount: 15000,
                            minPaymentAmount: 1,
                            volumeTranslations: [ // Optional parameter
                                "DE": VolumeTranslations(buttonText: "Bezahlen mit",
                                        headingText: "Bezahlen Sie mit Ihrer Banking-App",
                                        modalTitleText: "Bank-App auswählen",
                                        modalSubtitleText: "Ihre Zahlung ist durch die Sicherheit Ihrer Bank geschützt",
                                        moreBanksText: "+ mehr",
                                        selectBankButtonText: "Wählen Sie zum Bezahlen die Bank-App aus",
                                        payerDetailsText: "Bitte geben Sie Ihre Daten ein:",
                                        accountHolderNameText: "Vorname und Nachname",
                                        ibanText: "IBAN",
                                        continueInBankText: "Weiter in der Bank-App")
                            ]
                    )
            )
        } catch {
            debugPrint(error)
        }
    }
 
    class DefaultVolumeEventListener: VolumeEventListener {
        let showEvent: (String) -> ()?
 
        init(showToast: @escaping (String) -> ()?) {
            showEvent = showToast
        }
 
        func onEvent(event: VolumeEvent) {
            showEvent(event.description)
        }
    }
 
    var body: some Scene {
        WindowGroup {
            ExampleAppView()
        }
    }
}
 
 struct ExampleAppView: View {
 
    @State private var currency: String = "EUR"
    @State private var country: String = "DE"
    @State private var language: LanguageCode = "EN"
    @State private var merchantPaymentId: String = generateMerchantPaymentId()
 
    var body: some View {
        let volumeButtonEventListener: VolumeEventListener = DefaultVolumeButtonEventListener { event in
            switch event {
            case .navigateToPaymentConsent:
                self.merchantPaymentId = generateMerchantPaymentId()
            default: break
            }
        }
 
        return VStack {
            VolumeButtonComponent(
                    amount: 0.1,
                    reference: "Example Reference", // Generate new reference value each time navigateToPaymentConsent event is emitted
                    currency: $currency,
                    country: $country,
                    merchantPaymentId: merchantPaymentId, // Generate new value each time navigateToPaymentConsent event is emitted
                    isEnabled: true,
                    language: $language // Optional parameter
                    volumeButtonEventListener: volumeButtonEventListener,
                    metadata: [
                         "type": "shirt",
                         "color": "black",
                         "owner": [
                             "position": "CTO",
                             "description": "A tall guy",
                             "details": [
                                 "name": "John",
                                 "surname": "Doe",
                             ],
                         ],
                         "relatedItems": [
                             [ "itemName": "trousers", "color": "blue"],
                             [ "itemName": "shoes", "color": "white"],
                         ]
                    ],
                    merchantProvidedPayerDetails: MerchantProvidedPayerDetails(
                        email: "john.doe@example.com",
                        name: "John Doe",
                        phone: "+44 20 7946 0958",
                        account: PayerAccount(
                            holderName: "John Doe",
                            accountNumber: "12345678",
                            sortCode: "123456",
                            iban: "DE89370400440532013000"
                        ),
                        address: PayerAddress(
                            addressLine1: "123 Main Street",
                            addressLine2: "Apt 4B",
                            countryCode: "GB",
                            town: "London",
                            postCode: "SW1A 1AA"
                        ),
                        useForUxFlowOptimisation: true
                    )
            )
                    .padding(.horizontal, 15.0)
                    .padding(.vertical, 50)
        }
    }
}
 
func generateMerchantPaymentId() -> String {
    "This should be unique value" //TODO Get merchant Payment Id value from backend
}
 
class DefaultVolumeButtonEventListener: VolumeEventListener {
    let onEvent: (VolumeEvent) -> ()?
 
    init(onEventAction: @escaping (VolumeEvent) -> ()?) {
        onEvent = onEventAction
    }
 
    func onEvent(event: VolumeEvent) {
        onEvent(event)
    }
}

Available countries

CountryCountry codeCurrency
United KingdomGBGBP
GermanyDEEUR
FranceFREUR
NetherlandsNLEUR
SpainESEUR
BelgiumBEEUR

Properties

Expand the section below for a quick glance at what you need to know.

VolumeProvider properties

Required Properties

keytypeexampledescription
applicationIdString123456789Your Application Id as provided in your Merchant Portal. (Provided by Volume)
volumeEnvironmentStringsandboxEnvironment to be used, this is either 'live' | 'sandbox' | A full URI if we have provided a specific environment for you.

Optional Properties

keytypeexampledescription
onEventVolumeEventListenerEventsEvent listener, object that reacts to Volume events, see Events for detailed instructions on how this works
showSandboxBanksBooleantrueFlag to enable showing sandbox banks. Used for testing
minPaymentAmountDecimal0.01 (default: 0.01)Minimum value for the amount field for each payment, when supplying a value smaller than this, a PAYMENT_AMOUNT_TOO_SMALL event will be emitted and the payment will not reach the volume api.
maxPaymentAmountDecimal15000 (default: 15000)Maximum value for the amount field for each payment, when supplying a value greater than this, a PAYMENT_AMOUNT_TOO_LARGE event will be emitted and the payment will not reach the volume api.
buttonCustomisationButtonCustomisationTweak the look and feel of the Volume button, properties to make changes to the colours, text, and border of the button.
volumeTranslations[String: VolumeTranslations]Map of VolumeTranslations per language like "EN" or "DE". Allows to translate Volume component.
💡

For more information on Events with onEvent. Check out Events.

VolumePaymentView has following setters
keytypeconstraintsexampledescription
amountDecimalMin 0.01 , up to 2 decimal places1Amount to be paid, ie £1.00.
currencyStringISO 4217GBPCurrency of payment
countryStringISO 3166-1 alpha-2GBCountry of origin of the payment.
referenceStringMax 18 chars, AlphanumericABC-123Pass a bank transfer reference, it will be visible by both a client and merchant in bank transfer history.
merchantPaymentIdString (Optional)Max 50 chars, unique per payment123456Pass a merchantPaymentId to associate a unique identifier for the payment, this will be returned to you in any webhook or api responses for the given payment
isEnabledBooleantrueChanges the Enabled/Disabled state of the Volume button
languageStringENSets the language to be used on Volume component
volumeButtonEventListenerVolumeEventListenerEvent listener, object that reacts to Volume events, see Events for detailed instructions on how this works
metadataDictionary String to AnyMax 5000 chars lengthmetadata is an optional JSON object which will be passed back in webhooks as paymentMetadata. It can only accepts primitives (as well as dictionaries and arrays of primitives).
paymentIdentifiersProviderPaymentIdentifiersProviderOptionalProvider for PaymentIdentifiers like MerchantPaymentId and Reference that are generatedPaymentIdentifiers on Merchant backend

Regenerating Merchant Payment ID

Each time VolumeEvent.NavigateToPaymentConsent is emitted Merchant Payment ID should be set to a new unique value.

Rendering Volume Button without MerchantPaymentId (Optional)

The PaymentIdentifiersProvider is an optional feature that allows merchants to provide a MerchantPaymentId and Reference fields when the user clicks the Volume Pay button. This enables the rendering of the Volume Button before creating a Payment entity on the merchant side. providePaymentIdentifiers(): An asynchronous method that returns a PaymentIdentifiers object containing the payment identifiers.

class VolumePaymentIdentifiersProvider: PaymentIdentifiersProvider {
    func providePaymentIdentifiers() async -> PaymentIdentifiers {
        do {
            let merchantPaymentIdFromBackend = "123" // Get merchant Payment Id from backend
            let referenceFromBackend = "ref123" // Get reference from backend
            let generatedPaymentIdentifiers = PaymentIdentifiers(
                merchantPaymentId: merchantPaymentIdFromBackend,
                reference: referenceFromBackend
            )
            return generatedPaymentIdentifiers
        } catch {
            // Return result with error message in case of exception
            // If errorMessage is not null then it will be displayed to the user as an error message
            return PaymentIdentifiers(
                merchantPaymentId: "",
                reference: "",
                errorMessage: error.localizedDescription
            )
        }
    }
}
 
// Usage in the VolumePaymentButtonView
VolumeButtonComponent(
        amount: 0.1,
        reference: "Example Reference", // will be overridden by paymentIdentifiersProvider
        currency: $currency,
        country: $country,
        merchantPaymentId: merchantPaymentId, // will be overridden by paymentIdentifiersProvider
        isEnabled: true,
        language: $language // Optional parameter
        volumeButtonEventListener: volumeButtonEventListener,
        paymentIdentifiersProvider: VolumePaymentIdentifiersProvider()
)

IMPORTANT: When paymentIdentifiersProvider is provided then merchantPaymentId and reference fields values will be ignored and paymentIdentifiersProvider will be called each time user clicks on the Volume Button.

Merchant Provided Payer Details

The merchantProvidedPayerDetails parameter allows merchants to pre-populate payer information to optimize the user experience during payment flow. This is also required to gain access to Volume's Confirmation of Payer feature, and to enable the search and filtering of payments by these details.

Key Benefits

  • Faster UX: Automatic bank detection based on provided IBAN for EURO payments
  • Improved Conversion: Pre-filled forms reduce user friction
  • Confirmation of Payer: Verify the identity of account holders against your KYC data

Usage

  VolumeButtonComponent(
 // other parameters
      merchantProvidedPayerDetails: MerchantProvidedPayerDetails(
          email: "john.doe@example.com",
          name: "John Doe",
          phone: "+44 20 7946 0958",
          account: PayerAccount(
              holderName: "John Doe",
              accountNumber: "12345678",
              sortCode: "123456",
              iban: "DE89370400440532013000"
          ),
          address: PayerAddress(
              addressLine1: "123 Main Street",
              addressLine2: "Apt 4B",
              countryCode: "GB",
              town: "London",
              postCode: "SW1A 1AA"
          ),
          useForUxFlowOptimisation: true
      )
  )

Properties

PropertyTypeRequiredDescription
emailStringNoCustomer's email address
nameStringNoCustomer's full name
phoneStringNoCustomer's phone number ideally in +XX 123456 format
accountPayerAccountNoCustomer's bank account details
addressPayerAddressNoCustomer's address details
useForUxFlowOptimisationBooleanNoEnable UX optimizations like bank detection

PayerAccount Properties

PropertyTypeRequiredDescription
holderNameStringNoAccount holder's name as it appears on the bank account
accountNumberStringNoBank account number (use with sortCode)
sortCodeStringNoBank sort code without dashes (use with accountNumber)
ibanStringNoInternational Bank Account Number

PayerAddress Properties

PropertyTypeRequiredDescription
addressLine1StringNoFirst line of the address
addressLine2StringNoSecond line of the address
countryCodeStringNoISO 3166-1 alpha-2 country code
townStringNoCity or town
postCodeStringNoPostal code or ZIP code

Account Identification Rules

⚠️

Important: You must use either IBAN (EUR) or the combination of account number and sort code (GBP), but not both:

  • IBAN Method: When iban is provided, accountNumber and sortCode should be null or not provided
  • Account Number Method: When accountNumber and sortCode are provided, iban should be null or not provided

Example with IBAN:

PayerAccount(
  holderName: "John D.",
  iban: "DE89370400440532013000",
  accountNumber: null,
  sortCode: null,
)

Example with Account Number and Sort Code:

PayerAccount(
  holderName: "John D.",
  accountNumber: "12345678",
  sortCode: "123456",
  iban: null,
)

Important Notes

⚠️

When using merchantProvidedPayerDetails with IBAN, ensure the country parameter matches the country of the provided IBAN. Note that there are banks like Revolut or Wise that are available in many countries.

  • Bank detection works automatically for EURO payments when a valid IBAN is provided
  • The useForUxFlowOptimisation flag is set to true to enable all UX improvements
  • All fields are optional, allowing partial pre-population based on available data

Implementing the after payment screen (Callback) in mobile app

IMPORTANT: Handling properly Callback links is critical for the smooth User journey ending in Merchant app on payment status page.

Follow instructions for the Volume Callback handling: Callback

iOS Banks detection required setup

To make bank detection work Apple require we add some values in your Info.plist to indicate intent to work with app schemes, we use this to detect which banking apps the end user has installed on their phone so that we can show them only banks they have installed.

To complete the setup there are some <string> tags we need to add under the LSApplicationQueriesSchemes key in Info.plist file.

<key>LSApplicationQueriesSchemes</key>
	<array>
		<string>BMBGB</string>
		<string>revolut</string>
		<string>natwestbank</string>
		<string>monzo</string>
		<string>santanderretail</string>
		<string>rbs</string>
		<string>lloyds-retail</string>
		<string>ukcomhsbcmobilebanking</string>
		<string>zappcfi437759</string>
		<string>hsbc-pwnwguti5z</string>
		<string>zapp</string>
		<string>launchAIB</string>
		<string>ie.aib.mobilebanking</string>
		<string>BOIOneAPP</string>
		<string>halifax-retail</string>
		<string>starlingbank</string>
		<string>tescobank</string>
		<string>tsbmobile</string>
		<string>sparda-app</string>
		<string>bankingappspardaproduktion</string>
		<string>secureappspardaproduktion</string>
		<string>sapp-pushtan</string>
		<string>sapp-invest</string>
		<string>de.sparda.securego</string>
		<string>bos-retail</string>
		<string>launchbca</string>
		<string>comfirstdirectbankingonthego</string>
		<string>cs-com.virginmoney.uk.mobile.ios</string>
		<string>transferwise</string>
		<string>ybssavings</string>
		<string>chase-international</string>
	</array>

Testing

After you have completed the steps above, then you can start testing.

We strongly recommend to use sandbox environment before switching to live environment.

Please note that sandbox testing will not open the Banking app due to lack of testing environment offered by the different banks in the UK. However, a successful test will open the bank environment via the browser. The user experience will differ bank by bank. Ask us more information at support@getvolume.com or use the chat in this page to get immediate assistance.

Please check Sandbox Banks Credentials to be able to test with Natwest Sandbox and other sandbox banks.