Mobile Payment SDK

First Steps

Before you start coding, you are going to need some credentials:

  1. Merchant Account ID - the ID of your merchant account that will be used to process transactions

  2. Secret Key - a value that you will use to create unique security signatures for your transactions

You can find testing credentials at this link.

Your account needs to be configured through Merchant Support to process mobile SDK payments.

Get your own credentials by contacting Merchant Support.

Next, depending on where you are from, you will need to choose your closest production environment: this is where your instance of MPSDK will be hosted. Both testing and production environments are available in every location.

At the moment, the supported locations are as follows:

Location / Name Hostname SSL cert valid until

Germany - PROD

https://api.wirecard.com/

03/12/2020

Germany - TEST

https://api-test.wirecard.com/

03/12/2020

Singapore - PROD

https://api.wirecard.com.sg/

05/21/2020

Singapore - TEST

https://test.wirecard.com.sg/

09/04/2020

Toronto - PROD

https://engine.elastic-payments.com/

08/27/2020

Toronto - TEST

https://sandbox-engine.thesolution.com/

12/01/2019

Don’t forget to keep MPSDK up-to-date (i.e. updating before the SSL certification expires).

Basic Setup

Android

The device needs to be non-rooted and run at least Android 4.1 (Jelly Bean / API Level 16) for MPSDK to work.

There are two ways to set up the framework on Android
  1. Using a Dependency Manager

  2. Importing Through Android Studio

Using a Dependency Manager

With this option, you will be getting paymentSDK straight from the repository using JitPack.

First of all, you need to create your project in the Android studio. Then you add the following code to your build.gradle file:

repositories {
     maven { url "https://jitpack.io" }
 }
 dependencies {
     compile 'com.github.wirecard:paymentSDK-Android:2.7.1'
 }

Some of our consumers prefer an alternative version of MPSDK which does not feature the card scanner capability (i.e. scanning the card information using the phone’s camera).

If that’s you, add this dependency instead:

dependencies {
    compile 'com.github.wirecard:paymentSDK-Android:2.7.1-cardScannerDisabled'
 }
Importing in Android Studio

After you download the MPSDK package from our GitHub repository, use the Android Studio’s Import .JAR/.AAR Package option located in File → New → New Module.

Then, add the MPSDK module as a dependency to your build.gradle file as shown in the example:

dependencies {
   ...
   compile project(':paymentsdk')
   ...
 }
External Libraries

Our SDK uses various 3rd party libraries which you will need to include in your build.gradle file. These should be kept at their latest stable versions:

dependencies {
       ...
       compile 'com.android.support:appcompat-v7:26.0.1'
       compile 'com.zapp.library:merchant:1.1.0'
       compile 'org.iban4j:iban4j:3.2.1'
       compile 'com.android.support:customtabs:26.1.0' //only for card and PayPal payments
       compile 'com.squareup.retrofit2:retrofit:2.3.0'
       compile 'com.squareup.retrofit2:converter-gson:2.3.0'
       compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
       compile('com.squareup.retrofit2:converter-simplexml:2.3.0') {
         exclude module: 'stax'
         exclude module: 'stax-api'
         exclude module: 'xpp3'
 }

cardIOEnabledCompile 'io.card:android-sdk:5.5.1'

// iban validator
compile 'org.iban4j:iban4j:3.2.1'
// ocr
compile 'com.google.android.gms:play-services-vision:11.6.2'
// tracker
compile 'org.piwik.sdk:piwik-sdk:2.0.0'
       ...
 }

Including io.card:android-sdk is optional when using the alternative MPSDK version (without the card scanner feature).

It is important that you adjust com.android.support:appcompat to the latest version of the support library.

AndroidManifest Setup

MPSDK requires these permissions to function:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

If you plan on using the card scanner feature, you will need to:

  • add these permissions

    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.CAMERA" />
  • add this activity into your AndroidManifest file

    <activity
        android:name="de.wirecard.paymentsdk.ui.activity.CardScannerActivity" />

    If you do not require the card scanner capability in your app, you can safely omit this step.

    For card and PayPal payments, also add:

    <activity
    android:name="de.wirecard.paymentsdk.ui.activity.CustomTabsActivity"
    android:launchMode="singleTop"
    android:screenOrientation="portrait">
    <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data
    android:host="web.result"
    android:scheme="paymentsdkdemo" />
    </intent-filter>
    </activity>
Proguard

If you are using Proguard, you will need to add the following rules into your proguard-rules.pro file:

Rules for Proguard
 -dontwarn org.simpleframework.**
 -dontwarn io.card.**
 -dontwarn okhttp3.**
 -dontwarn okio.**
 -dontwarn retrofit2.**
 -dontwarn de.wirecard.paymentsdk.**

 -keepattributes Signature
 -keepattributes Exceptions
 -keepattributes JavascriptInterface
 -keepattributes *Annotation*

 -keep class org.simpleframework.** { *; }
 -keep interface org.simpleframework.** { *; }

 -keep class okhttp3.** { *;}

 -keep class okio.** { *; }
 -keep interface okio.** { *; }

 -keep class retrofit2.** { *; }

 -keep class io.card.**
 -keepclassmembers class io.card.** {
      *;
 }

 -keep class de.wirecard.paymentsdk.** { *; }
 -keep interface de.wirecard.paymentsdk.** { *; }

If you are using the alternative version without the card scanner feature, you can leave out this part:

 -keep class io.card.**
 -keepclassmembers class io.card.** {
      *;
iOS

The device cannot be jail-broken and must run at least iOS 7 for paymentSDK to work. It is recommended to use the latest stable version of Xcode.

Download the pod at our GitHub repository and add it to your Podfile:

Podfile
pod 'paymentSDK'
Authentication by Signature

When a payment goes through, there’s a lot of data to be exchanged between various endpoints. Payment information changes hands between your system (the merchant), the consumer’s device, and Wirecard Processing Gateway. To ensure that this information is not tampered with, we need to put safeguards in place.

We do this by employing a digital signature, which is used for all messages targeting the Wirecard Payment Gateway. This signature is a mathematical cipher, which - if validated - proves that the message was created by a known sender and was not altered while being transmitted.

Secret Key

You will use your Secret Key when generating the digital signature mentioned above.

The Secret Key is only used in server-side code for either:

  • generating the server request signature

  • validating the server response signature

If you did not receive your Secret Key at the time you were setting up your merchant account with us, please contact Merchant Support and ask for Secret Key generation.

We ask you to never share your Secret Key with anyone, or store it inside your application or phone. This is crucial to ensure the security of your transactions.

Signature v2

You will be generating the signature on your own server’s backend, as it is the only place where you will store your Secret Key.

See Signature v2 for more information.

Note that when generating the signature for MPSDK, you can leave out payload fields related to Payment Page (redirect_url, custom_css_url, ip_address). This means that you only use the mandatory fields:

Signature v2 Payload Example (for MPSDK)
HS256
request_time_stamp=2017-03-23T09:14:51Z
merchant_account_id=33f6d473-3036-4ca5-acb5-8c64dac862d1
request_id=A7B51ED4-9EB0-48D1-82AA-2145A7792C6B
transaction_type=authorization
requested_amount=1.01
requested_amount_currency=EUR
Signature v1 (DEPRECATED)

Although we link the Signature v1 documentation here, it is now considered the legacy version. For all intents and purposes, if you haven’t used MPSDK before, use Signature v2.

Signature v1 docs link here .

3D Secure

3D Secure flow & implementation is handled implicitly by MPSDK. There is only the on-demand option to omit the 3D Secure protocol (it is activated by default for merchants). For a detailed flow, see this link.

Integrating MPSDK on Android

For downloading MPSDK and basic setup, refer to Basic Setup.

Do This First

Regardless of the payment method, you need to create and initialize a WirecardClient instance before anything else:

paymentSDK only works with non-rooted devices; if it detects a device that is rooted, it will throw an exception during initialization of the WirecardClient object.

WirecardClient wirecardClient;
String environment = WirecardEnvironment.TEST.getValue();
try {
    wirecardClient = WirecardClientBuilder.newInstance(context, environment)
                    .build();
} catch (WirecardException exception) {
    //device is rooted
}

The example above also handles the "device is rooted" exception situation by using try and catch.

For credit card & PayPal payments, add this line when creating the payment object (e.g. WirecardCardPayment):

wirecardPayment.setProcessingURL("paymentsdkdemo://web.result");
Additional Features

Features which are not bound to a single payment method are listed here:

Checking Transaction Status

You can use the checkPayment method to see the current status of your transaction

checkPayment Format
wirecardClient.checkPayment(wirecardPayment, wirecardResponseListener);

Instead of wirecardPayment use the relevant payment object (e.g. wirecardCardPayment). It should contain the same request ID & MAID as the transaction you are checking.

Credit Card
Fullscreen Form
Do not forget to create and initialize an instance of the WirecardClient object before you go further, as explained at the start of this section.
Simple Transactions
  1. Create and initialize the WirecardCardPayment object, which stores the transaction’s payload & signature:

    WirecardCardPayment wirecardCardPayment = new WirecardCardPayment (signature, requestTimeStamp, requestID,merchantID, transactionType, amount, currency);
  2. Initialize the WirecardResponseListener object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:

    WirecardResponseListener Initialization
    WirecardResponseListener wirecardResponseListener = new WirecardResponseListener() {
        @Override
        public void onResponse(WirecardPaymentResponse paymentResponse) {
            // handle server response
            if (paymentResponse.getTransactionState().equals(TransactionState.SUCCESS)) {
                // handle successful transaction
            } else {
                // handle unsuccessful transaction
            }
        }
        @Override
        public void onError(WirecardResponseError responseError) {
            // handle error
            switch (responseError.getErrorCode()) {
                case WirecardErrorCode.ERROR_CODE_GENERAL:
                    String detailedMessage = responseError.getErrorMessage();
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_INVALID_PAYMENT_DATA:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_NETWORK_ISSUE:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_USER_CANCELED:
                    //...
                    break;
            }
        }
    };
  3. Call the WirecardClient's method makePayment to send the transaction request:

    wirecardClient.makePayment(wirecardCardPayment, wirecardResponseListener, paymentPageStyle);

    You can customize the UI through resources of the paymentPageStyle object. We will revisit the 'how' at the end of this section.

  4. Process the response. If everything went smoothly server-side, the onResponse method will be called. If any errors occurred, onError will be called instead.

Referenced Transactions

If you need to perform referenced transactions (i.e. one’s using token or parentTransactionID), set them in the wirecardCardPayment instance:

wirecardPayment.setParentTransactionID(parentTransactionID);

OR

CardToken cardToken = new CardToken(tokenID, maskedAccountNumber);
wirecardPayment.setCardToken(cardToken);
Customizing the UI

Despite strict rules, we give you as much customization as possible within the limits of the PCI DSS standards.

You can customize the following
  • styling of the input fields

  • background color of the form & buttons

  • labels, hints, and their colors

  • icons for the supported card providers

  1. To begin customizing, initialize PaymentPageStyle:

    PaymentPageStyle style = new PaymentPageStyle();
  2. Then, provide your customized resources:

    PaymentPageStyle style = new PaymentPageStyle();
               style.backgroundResourceId = R.color.yellow;
               style.inputTextColor = context.getResources().getColor(R.color.red);
               style.inputFieldColor = context.getResources().getColor(R.color.red);
               style.inputHintTextColor = context.getResources().getColor(R.color.red_transparent);
               style.payButtonBackgroundResourceId = R.color.blue;
               style.toolbarResourceId = R.color.red;
               style.inputLabelTextColor = context.getResources().getColor(R.color.blue);
               style.scanButtonTextColor = context.getResources().getColor(R.color.red);
               style.toolbarTextColor = context.getResources().getColor(R.color.yellow);
               style.payButtonTextColor = context.getResources().getColor(R.color.yellow);
    
               //!!!
               Set<CardBrand> supportedCardBrands = new HashSet<>();
               supportedCardBrands.add(CardBrand.MASTERCARD);
               supportedCardBrands.add(CardBrand.AMEX);
               style.supportedCardBrands = supportedCardBrands;
    
               ...
If you do not configure Set<CardBrand> supportedCardBrands at this point, all of the possible card brands will be considered supported by default.
Embedded Form
Do not forget to create and initialize an instance of the WirecardClient object before you go further, as explained at the start of this section.

Since you’re using an embedded component instead of rendering the whole page, there are some changes in the approach.

You need to initialize the WirecardCardFormFragment component first:

  1. In the XML layout, create a container where you will place the WirecardCardFormFragment :

    <FrameLayout
       android:id="@+id/container"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
     </FrameLayout>
  2. Create a new instance of this fragment:

    WirecardCardFormFragment wirecardCardFormFragment = new WirecardCardFormFragment.Builder(wirecardExtendedCardPayment).build();
  3. Add wirecardCardFormFragment into the container created in first step:

    getSupportFragmentManager()
        .beginTransaction()
        .add(R.id.container, wirecardCardFormFragment)
        .commit();

Now you should be able to see the card component in your layout.

Customizing The Form Fragment

To style the fragment, create WirecardCardFormFragment using WirecardCardFormFragment.Builder:

WirecardCardFormFragment wirecardCardFormFragment = new WirecardCardFormFragment.Builder(wirecardExtendedCardPayment)
.setLocale("de")
.setTextSize(12)
.setHintColorID(hintColorID)
.setTextColorID(textColorID)
.setRequestFocus(true)
.build();

To set supported card brands, use WirecardCardFormFragment.Builder method setSupportedCardBrands(Set<CardBrand> supportedCardBrands):

Set<CardBrand> supportedCardBrands = new HashSet<>();
supportedCardBrands.add(CardBrand.MASTERCARD);
supportedCardBrands.add(CardBrand.AMEX);

builder.setSupportedCardBrands(supportedCardBrands);
If you do not set the supported card brands, all of them are shown as supported by default.
Initializing the Payment Object

After setting the fragment into the layout, the steps are similar to the normal process.

The way you enable the payment object is almost identical to the full screen form approach; however, instead of WirecardCardPayment, use WirecardExtendedCardPayment:

WirecardExtendedCardPayment wirecardExtendedCardPayment = new WirecardExtendedCardPayment(signature, requestTimeStamp, requestID, merchantID, transactionType, amount, currency);

Optionally, if a last name is required for successful transaction, add it to WirecardExtendedCardPayment:

CustomerData accountHolder = new CustomerData();
accountHolder.setLastName(lastName);
wirecardExtendedCardPayment.setAccountHolder(accountHolder);
Initializing the Input State Listener

As the name suggests, Input State Listener notifies you of any state changes in your card input fields (e.g. you can use this for showing text message or alerts for certain cases).

To use it, follow these steps:

  1. Create a WirecardInputFormsStateChangedListener instance:

    WirecardInputFormsStateChangedListener wirecardInputFormsStateChangedListener = new WirecardInputFormsStateChangedListener() {
        @Override
            public void onStateChanged(int code) {
                switch(code){
                    case WirecardInputFormsStateChangedListener.CARD_NUMBER_FORM_FOCUS_GAINED:
                        ...
                        break;
                    case WirecardInputFormsStateChangedListener.EXPIRATION_MONTH_FORM_FOCUS_GAINED:
                        ...
                        break;
                    ...
                }
            }
    };
  2. Create a WirecardInputFormsStateManager instance. This manages communication between the input fields and the listener:

    WirecardInputFormsStateManager wirecardInputFormsStateManager = new WirecardInputFormsStateManager(context, wirecardInputFormsStateChangedListener);

WirecardInputFormsStateManager provides two methods:

  • startReceivingEvents()

  • stopReceivingEvents()

The manager wraps the BroadcastReceiver, so you can treat these two methods like BroadcastReceiver’s registerReceiver()/unregisterReceiver().

Regardless, call startReceivingEvents() in the onResume() method, and stopReceivingEvents() in the onPause() method:

@Override
public void onResume() {
    super.onResume();
    wirecardInputFormsStateManager.startReceivingEvents();
}
@Override
public void onPause() {
    super.onPause();
    wirecardInputFormsStateManager.stopReceivingEvents();
}

Here is a list of constants for fired events included in WirecardInputFormsStateChangedListener:

Constant Event Description

CARD_NUMBER_FORM_FOCUS_GAINED

card number input form gained focus

EXPIRATION_MONTH_FORM_FOCUS_GAINED

exp. month input form gained focus

EXPIRATION_YEAR_FORM_FOCUS_GAINED

exp. year input form gained focus

SECURITY_CODE_FORM_FOCUS_GAINED

security code (CVC/CID) input form gained focus

CARD_NUMBER_FORM_FOCUS_LOST

card number input form focus lost

EXPIRATION_MONTH_FORM_FOCUS_LOST

exp. month input form focus lost

EXPIRATION_YEAR_FORM_FOCUS_LOST

exp. year input form focus lost

SECURITY_CODE_FORM_FOCUS_LOST

security code (CVC/CID) input form focus lost

CARD_BRAND_UNSUPPORTED

card number wasn’t recognized after typing 3 numbers

CARD_NUMBER_INVALID

card number has reached max length but card validity check wasn’t successful

CARD_NUMBER_INCOMPLETE

card number is not complete, user typing his number

CARD_NUMBER_VALID

card passes validity check

EXPIRATION_MONTH_INCOMPLETE

expiration month is not complete yet. For example, user types one number, and jumps to expiration year field.

EXPIRATION_MONTH_VALID

expiration month is valid. Note that we don’t have event for invalid state, because user is able to enter only valid month.

EXPIRATION_YEAR_INCOMPLETE

called when expiration year is not complete yet.

EXPIRATION_YEAR_VALID

expiration year is valid. Note that we don’t have event for invalid state, because user is able to enter only valid year.

SECURITY_CODE_INCOMPLETE

security code is not complete yet

SECURITY_CODE_VALID

security code is complete

CARD_VALID

all inputs(card number, expiration month, expiration year and security code) are valid. When you get this event, you can proceed to next step

Executing Credit Card Transactions

Before you execute the transaction, you need to get the data from the input fields to the handler:

wirecardExtendedCardPayment = wirecardCardFormFragment.getWirecardExtendedCardPayment();

Now that WirecardExtendedCardPayment has the payment data, you can call WirecardClient's makePayment() method and execute the transaction.

It is possible to clear all input fields (e.g. for situations where the app goes to background).

wirecardCardFormFragment.clearAllFields();

You can also get the card brand of the currently entered card number:

wirecardCardFormFragment.getCardBrand();

Favorite Payment Use Case Example

You might want to offer users who have already made a purchase with you a streamlined way to pay, where they only enter the security code (CVC/CID) instead of all the data (which is now saved as the card token). You still need to follow all of the steps from the Embedded Form section, but with some differences:

  1. Add a card token (as is, or instead of cardholder’s last name) to WirecardExtendedCardPayment:

    wirecardExtendedCardPayment.setCardToken(new CardToken(token, maskedCardNumber));
  2. Create the WirecardCardFormFragment using WirecardCardFormFragment.Builder like this:

    wirecardCardFormFragment = new WirecardCardFormFragment.Builder(wirecardExtendedCardPayment)
            .setCardBrand(cardBrand) //for example CardBrand.VISA
            .setExpirationDate(expirationDate) // for example "1219"
            .build();
  3. Same as in the previous example, you need to get the updated WirecardExtendedCardPayment, now containing the security code from the input field:

    wirecardExtendedCardPayment = wirecardCardFormFragment.getWirecardExtendedCardPayment();
  4. Call WirecardClient's makePayment() method to execute the transaction:

    wirecardClient.makePayment(WirecardExtendedCardPayment, wirecardResponseListener, paymentPageStyle);
PayPal
Do not forget to create and initialize an instance of the WirecardClient object before you go further, as explained at the start of this section.
Simple Transactions
  1. Create and initialize WirecardPayPalPayment:

    WirecardPayPalPayment wirecardPayment = new WirecardPayPalPayment(signature, requestTimeStamp, requestID, merchantID, transactionType, amount, currency);
  2. Initialize the WirecardResponseListener object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:

    WirecardResponseListener Initialization
    WirecardResponseListener wirecardResponseListener = new WirecardResponseListener() {
        @Override
        public void onResponse(WirecardPaymentResponse paymentResponse) {
            // handle server response
            if (paymentResponse.getTransactionState().equals(TransactionState.SUCCESS)) {
                // handle successful transaction
            } else {
                // handle unsuccessful transaction
            }
        }
        @Override
        public void onError(WirecardResponseError responseError) {
            // handle error
            switch (responseError.getErrorCode()) {
                case WirecardErrorCode.ERROR_CODE_GENERAL:
                    String detailedMessage = responseError.getErrorMessage();
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_INVALID_PAYMENT_DATA:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_NETWORK_ISSUE:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_USER_CANCELED:
                    //...
                    break;
            }
        }
    };
  3. Call WirecardClient's method makePayment to execute the transaction:

    wirecardClient.makePayment(wirecardPayPalPayment, wirecardResponseListener, paymentPageStyle);
  4. Process the response. If everything went smoothly server-side, wirecardResponseListener's onResponse method is called. If any errors occurred, onError will be called instead.

Recurring Transactions

If you require recurring transactions, set the Periodic object into the wirecardPayPalPayment instance:

Periodic periodic = new Periodic(periodicType, sequenceType);
wirecardPayPalPayment.setPeriodic(periodic);
SEPA Direct Debit
Do not forget to create and initialize an instance of the WirecardClient object before you go further, as explained at the start of this section.
Simple Transactions
  1. Create and initialize WirecardSepaPayment:

    WirecardSepaPayment payment = new WirecardSepaPayment (signature, requestTimeStamp, requestID, merchantID, transactionType, amount, currency, creditorId, mandateId, mandateSignedDate, merchantName, dueDate);
  2. Initialize the WirecardResponseListener object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:

    WirecardResponseListener Initialization
    WirecardResponseListener wirecardResponseListener = new WirecardResponseListener() {
        @Override
        public void onResponse(WirecardPaymentResponse paymentResponse) {
            // handle server response
            if (paymentResponse.getTransactionState().equals(TransactionState.SUCCESS)) {
                // handle successful transaction
            } else {
                // handle unsuccessful transaction
            }
        }
        @Override
        public void onError(WirecardResponseError responseError) {
            // handle error
            switch (responseError.getErrorCode()) {
                case WirecardErrorCode.ERROR_CODE_GENERAL:
                    String detailedMessage = responseError.getErrorMessage();
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_INVALID_PAYMENT_DATA:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_NETWORK_ISSUE:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_USER_CANCELED:
                    //...
                    break;
            }
        }
    };
  3. Call WirecardClient's method makePayment to execute the transaction:

    wirecardClient.makePayment(wirecardSepaPayment, wirecardResponseListener, paymentPageStyle);
  4. Process the response. If everything went smoothly server-side, wirecardResponseListener's onResponse method is called. If any errors occurred, onError is called instead.

Recurring Transactions

If you require recurring transactions, set the Periodic object into the wirecardSepaPayment instance:

Periodic periodic = new Periodic(periodicType, sequenceType);
wirecardSepaPayment.setPeriodic(periodic);
Pay by Bank app (PBBA)
Do not forget to create and initialize an instance of the WirecardClient object before you go further, as explained at the start of this section.
Simple Transactions
  1. Add a dependency for the Pay by Bank app merchant library. For more details on dependencies see Basic Setup and Integration:

    compile 'com.zapp.library:merchant:1.1.0'
  2. Create and initialize WirecardPBBAPayment:

    WirecardPBBAPayment wirecardPayment = new WirecardPBBAPayment(signature, timestamp, requestID, merchantID, transactionType, amount, currency, zappTransactionType, zappDeliveryType, returnValue);
    Important notes
    • The only supported transaction type is debit.

    • The only supported currency is GBP.

    • IP address is mandatory for this payment method.

    • zappTransactionType is one of following options: BILLPT, PAYMT, INVOICE, DONATIONS .

    • zappDeliveryType is one of following options: COLLST, DELTAD, DIGDEL, SERVICE, F2F, NONE.

    • ReturnValue is the URL scheme used in the bank application to redirect the consumer back to your application.

    • If a user cancels the Pay by Bank app popup with the payment code BRN by pressing the X button at the top right, ERROR_CODE_USER_CANCELED is returned to let the merchant know that the user cancelled the transaction. Users cannot cancel a transaction if the CFI app is installed.

  3. Initialize the WirecardResponseListener object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:

    WirecardResponseListener Initialization
    WirecardResponseListener wirecardResponseListener = new WirecardResponseListener() {
        @Override
        public void onResponse(WirecardPaymentResponse paymentResponse) {
            // handle server response
            if (paymentResponse.getTransactionState().equals(TransactionState.SUCCESS)) {
                // handle successful transaction
            } else {
                // handle unsuccessful transaction
            }
        }
        @Override
        public void onError(WirecardResponseError responseError) {
            // handle error
            switch (responseError.getErrorCode()) {
                case WirecardErrorCode.ERROR_CODE_GENERAL:
                    String detailedMessage = responseError.getErrorMessage();
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_INVALID_PAYMENT_DATA:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_NETWORK_ISSUE:
                    //...
                    break;
                case WirecardErrorCode.ERROR_CODE_USER_CANCELED:
                    //...
                    break;
            }
        }
    };
  4. Update AndroidManifest.xml with a starting activity for the custom URL scheme:

    <activity android:name=".MainActivity"
        android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter android:autoVerify="true">
            <data android:scheme="paymentsdkdemo" android:host="open.pbba" />
    
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
        </intent-filter>
    </activity>

    To avoid app instability, add also android:configChanges="orientation|screenSize" to the activity record in your AndroidManifest file:

    Example Usage
            <activity
                android:name=".ui.activity.PaymentActivity"
                android:label="Payment"
                android:configChanges="orientation|screenSize" />
  5. You need to use PBBAButton for executing transactions (see Pay by Bank app guidelines for more details):

    <com.zapp.library.merchant.ui.view.PBBAButton
        android:id="@+id/pbba"
        android:layout_width="@dimen/pbba_button_width"
        android:layout_height="@dimen/pbba_button_height" />
  6. Call WirecardClient's method makePayment to execute the transaction:

    wirecardClient.makePayment(wirecardSepaPayment, wirecardResponseListener, paymentPageStyle);
  7. Next, either the PBBA dialog is shown or the banking application is opened.

  8. Consumer makes the payment in the banking application and is redirected back to your application. The application returns success or timeout depending on the response.

  9. Process the response. If everything went smoothly server-side, wirecardResponseListener's onResponse method is called. If any errors occurred, onError is called instead.

Integrating MPSDK on iOS

Apple Pay®
Apple Pay is fully PSD2 compliant.
Wirecard ensures that our merchants will stay PSD2 compliant without any additional change in the implementation process.
Before you start you should have access to your testing environment at this point.

Since Apple Pay® is a proprietary service, the setup process requires a different approach.

To set it up, you need to:

  1. Contact our merchant support to create a test Wirecard Payment Gateway Apple Pay merchant account and set up its Apple Merchant ID.

  2. Depending on whether you have an existing Apple Merchant ID, you will need to:

    1. upload the CSR file you’ve received in the previous step,

      or

    2. register with the Apple Merchant ID provided by Wirecard and upload the CSR file.

      Additional information can be found in Apple’s documentation.

After you’ve set up your accounts:

  1. You can add a test card to the Wallet app.

  2. Integrate paymentSDK into your application

  3. Conduct testing

  4. Add a live card to the Wallet app and switch the Wirecard Payment Gateway to production mode (do not forget to use production credentials - MAID/SK/AppleMerchantID/csr)

Executing ApplePay Transactions

There are two approaches, depending on your requirements:

  1. You need full control over PKPaymentRequest (dynamic shipping methods and pricing); use WDApplePayPayment

  2. If you only execute simple transactions with a fixed shipping price, use WDApplePayManagedPayment, and paymentSDK will handle the PKPaymentRequest by itself.

You will find a detailed approach to using both of these in their respective subsections.

Integrating with WDApplePayPayment
  1. Initialize WDClient:

    - (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
                           didAuthorizePayment:(PKPayment *)payment
                                    completion:(void (^)(PKPaymentAuthorizationStatus status))completion
    {
        // it is better to keep client as property to keep reference
        WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
  2. Initialize WDApplePayPayment

    WDApplePayPayment *applePayPayment = [[WDApplePayPayment alloc] initWithPayment:payment
                                                                        summaryItems:self.sumaryItems
                                                                            currency:currency];
  3. Generate requestID, requestTimestamp, and requestSignature on your server and assign them to WDApplePayPayment:

     applePayPayment.merchantAccountID = merchantAccountID;   // provided by support
     applePayPayment.requestID = [[NSUUID UUID] UUIDString];  // generated on server, unique to merchant
     applePayPayment.requestTimestamp = [NSDate date];        // generated on server
     applePayPayment.requestSignature = signature;            // generated on server
  4. Create a completionBlock to handle the response, then call PKPaymentAuthorizationViewController completion block to handle response:

    WDCompletionBlock completionBlock = ^(WDPaymentResponse *_Nullable response, NSError *_Nullable error) {
         if (error) {
             IPLogError(@"error: %@", error);
             UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                 message:error.localizedDescription
                                                                delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
             [alertView show];
             completion(PKPaymentAuthorizationStatusFailure);
             return;
         }
         completion(PKPaymentAuthorizationStatusSuccess);
     };
  5. Execute the transaction:

    [client makePayment:applePayPayment withCompletion:completionBlock];
    }
Integrating with WDApplePayManagedPayment
  1. Initialize WDClient:

    - (void)makeApplePayManaged
     {
         // it is better to keep client as property to keep reference
         WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
  2. Initialize WDApplePayPayment:

    WDApplePayManagedPayment *applePayPayment = [[WDApplePayManagedPayment alloc] initWithMerchant:kAppleMerchantID
                                                                                         andCountry:WDCountryGB];
    applePayPayment.amount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO];
    applePayPayment.amountCurrency = WDCurrencyGBP;
  3. Generate requestID, requestTimestamp, and requestSignature on your server and assign them to WDApplePayManagedPayment:

    applePayPayment.merchantAccountID = merchantAccountID;   // provided by support
    applePayPayment.requestID = [[NSUUID UUID] UUIDString];  // generated on server, unique to merchant
    applePayPayment.requestTimestamp = [NSDate date];        // generated on server; UTC
    applePayPayment.requestSignature = signature;            // generated on server
  4. Create a WDCompletionBlock to handle the response:

    WDCompletionBlock completionBlock = ^(WDPaymentResponse *_Nullable response, NSError *_Nullable error) {
         if (error) {
             IPLogError(@"error: %@", error);
             UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                 message:error.localizedDescription
                                                                delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
             [alertView show];
             return;
         }
         // handle successful response
     };
  5. Execute the transaction:

    [client makePayment:applePayPayment withCompletion:completionBlock];
    }
Simple Transactions
  1. Initialize WDClient:

    - (void)makeCardPayment
     {
         // it is better to keep client as property to keep reference
         WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
  2. Initialize WDCardPayment:

    WDCardPayment *payment = [[WDCardPayment alloc] initWithAmount:[NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]
                                                      amountCurrency:WDCurrencyEUR
                                                     transactionType:WDTransactionTypePurchase];
  3. Generate requestID, requestTimestamp, andrequestSignature on your server and assign them to WDCardPayment:

     payment.merchantAccountID = merchantAccountID;   // provided by support
     payment.requestID = [[NSUUID UUID] UUIDString];  // generated on server, unique to merchant
     payment.requestTimestamp = [NSDate date];        // generated on server
     payment.requestSignature = signature;            // generated on server
  4. Create a WDCompletionBlock to handle the response:

    WDCompletionBlock completionBlock = ^(WDPaymentResponse *_Nullable response, NSError *_Nullable error) {
         if (error) {
             IPLogError(@"error: %@", error);
             UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                 message:error.localizedDescription
                                                                delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
             [alertView show];
             return;
         }
         // handle successful response
     };
  5. Execute the transaction:

    [client makePayment:payment withCompletion:completionBlock];
     }
WDCardField Alternative

WDCardField is a specialized field for collecting card data, with properties similar to UITextField. It is designed to fit in a single line and can be used where an UITextField would be appropriate:

  1. Create a WDCardField (programmatically, or in XIB/Storyboard) and keep the instance reference in your UIViewController:

    \@interface PaymentViewController UIViewController<WDCardFieldDelegate>
    
    \@property (nonatomic, weak) IBOutlet WDCardField *cardField;
    \@property (nonatomic, weak) IBOutlet UIButton *paymentButton;
    \@property (nonatomic, strong) WDClient *client;
    
    @end
  2. Initialize it using WDCardPayment:

    Initializing WDCardField
    @implementation PaymentViewController
    
    - (void)viewDidLoad {
         WDCardPayment *payment = [[WDCardPayment alloc] initWithAmount:[NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]
                                                         amountCurrency:WDCurrencyEUR
                                                        transactionType:WDTransactionTypePurchase];
         WDCard *card = nil;
         WDCardToken *token = nil;
         if (shouldCollectSecurityCodeOnly) {
             token = [WDCardToken new];
             token.tokenID = @"4585779929881111";
             token.maskedAccountNumber = @"444433******1111";
    
             // It is convenient to set the card data if you're only collecting the security code. The respective card brand security code is validated.
             card = [WDCard new];
             card.brand = WDCardBrandVisa;
             card.expiryDate = [NSDate date];
         }
         WDCardField *cardField = self.cardField;
         cardField.cardPayment = [self buildPaymentWithToken:token];
         cardField.card = card;
         cardField.delegate = self; // it can be set via XIB as well
    
         // initalize a WDClient instance
         self.client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
     }
  3. Implement the WDCardFieldDelegate protocol to handle user actions listed in WDCardFieldState:

    #pragma mark - WDCardFieldDelegate
    
    - (void)cardField:(WDCardField *)cardField didChangeState:(WDCardFieldState)state {
         // simple data validation
         self.paymentButton.enabled = cardField.valid;
    
         // you can improve the UX by handling state and showing hints to user
     }
  4. Execute the transaction:

    Triggering the Payment
    #pragma mark - Payment Button action
    
    - (IBAction)makePayment:(UIButton *)sender {
         WDPayment *payment = self.cardField.cardPayment;
    
         // The data can be created in advance; requestTimestamp expiration is 30 mins.
         payment.merchantAccountID = merchantAccountID;   // provided by support
         payment.requestID = [[NSUUID UUID] UUIDString];  // generated on server unique to merchant
         payment.requestTimestamp = [NSDate date];        // generated on server
         payment.requestSignature = signature;            // generated on server
    
         // Create a block to handle the response
         WDCompletionBlock completionBlock = ^(WDPaymentResponse *_Nullable response, NSError *_Nullable error) {
             if (error) {
                 WDErrorCode errorCode = error.code;
                 // handle error
                 return;
             }
             // handle success
         }];
    
         // Triggering the payment
         [self.client makePayment:payment withCompletion:completionBlock];
     }
    
     @end
Pay by Bank app
  1. Override AppDelegate's method:

    - (void)application:(UIApplication *)app
                openURL:(NSURL *)url
                options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
    {
        [self.client openURL:url];
    }
  2. Implement makePBBAPayment in AppDelegate. You need to initialize WDClient:

    - (void)makePBBAPayment
         // it is better to keep client as property to keep reference
         self.client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
  3. Initialize WDPBBAPayment:

    WDPBBAPayment *payment = [[WDPBBAPayment alloc] initWithAmount:[NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]
                                                    amountCurrency:WDCurrencyGBP
                                                   transactionType:WDTransactionTypeDebit];
    payment.IPAddress = @"127.0.0.1";
    payment.pbbaReturnAppScheme = @"app-scheme";      // the scheme is defined by merchant, shall be unique and enabled in App's Info.plist
    payment.pbbaDeliveryType = pbbaDeliveryType;      // possible values zapp.in.DeliveryType
    payment.pbbaTransactionType = pbbaTransactionType;// possible values zapp.in.TxType
    Important notes
    • The only supported transaction type is debit.

    • The only supported currency is GBP.

    • IPAddress is mandatory for this payment method.

    • pbbaTransactionType is one of following options: BILLPT, PAYMT, INVOICE, DONATIONS .

    • pbbaDeliveryType is one of following options: COLLST, DELTAD, DIGDEL, SERVICE, F2F, NONE.

    • pbbaReturnAppScheme is the URL scheme used in the bank application to redirect the consumer back to your application.
      More information for PBBA specific parameters can be found in PBBA REST API.

  4. Generate requestID, requestTimestamp, and requestSignature on your server and assign them to the WDPBBAPayment:

    payment.merchantAccountID = merchantAccountID;   // provided by support
    payment.requestID = [[NSUUID UUID] UUIDString];  // generated on server, unique to merchant
    payment.requestTimestamp = [NSDate date];        // generated on server
    payment.requestSignature = signature;            // generated on server
  5. Create a WDCompletionBlock to handle the response:

    WDCompletionBlock completionBlock = ^(WDPaymentResponse *_Nullable response, NSError *_Nullable error) {
         if (error) {
             IPLogError(@"error: %@", error);
             UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                 message:error.localizedDescription
                                                                delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
             [alertView show];
             return;
         }
         // handle successful response
     };
  6. Execute the transaction:

        [self.client makePayment:payment withCompletion:completionBlock];
    }
  7. You need to use the PBBAButton to call the makePBBAPayment method.

  8. Next, either the PBBA dialog is shown or the banking application is opened.

  9. Consumer makes the payment in the banking application and is redirected back to your application. The application returns success or timeout depending on the response.

PayPal
  1. Initialize WDClient:

    - (void)makePayPalPayment
     {
         // it is better to keep client as property to keep reference
         WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
  2. Initialize WDPayPalPayment:

    WDPayPalPayment *payment = [[WDPayPalPayment alloc] initWithAmount:[NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]
                                                               currency:WDCurrencyEUR];
    payment.transactionType = WDTransactionTypeDebit;
  3. Generate requestID, requestTimestamp, and requestSignature on your server and assign them to the WDPayPalPayment:

    payment.merchantAccountID = merchantAccountID;   // provided by support
    payment.requestID = [[NSUUID UUID] UUIDString];  // generated on server, unique to merchant
    payment.requestTimestamp = [NSDate date];        // generated on server
    payment.requestSignature = signature;            // generated on server
  4. Create a WDCompletionBlock to handle the response:

    WDCompletionBlock completionBlock = ^(WDPaymentResponse *_Nullable response, NSError *_Nullable error) {
         if (error) {
             IPLogError(@"error: %@", error);
             UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                 message:error.localizedDescription
                                                                delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
             [alertView show];
             return;
         }
         // handle successful response
     };
  5. Execute the transaction:

    [client makePayment:payment withCompletion:completionBlock];
     }
SEPA Direct Debit
  1. Initialize WDClient:

    - (void)makeSEPAPayment
     {
         // it is better to keep client as property to keep reference
         WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
  2. Initialize WDSEPAPayment:

    WDSEPAPayment *payment = [[WDSEPAPayment alloc] initWithCreditor:creditorID
                                                           andMandate:mandateID];
    payment.transactionType = WDTransactionTypePendingDebit;
    payment.amount          = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO];
    payment.amountCurrency  = WDCurrencyEUR;
  3. Generate requestID, requestTimestamp, and requestSignature on your server and assign them to WDSEPAPayment:

    payment.merchantAccountID = merchantAccountID;   // provided by support
    payment.requestID = [[NSUUID UUID] UUIDString];  // generated on server, unique to merchant
    payment.requestTimestamp = [NSDate date];        // generated on server
    payment.requestSignature = signature;            // generated on server
  4. Create a WDCompletionBlock to handle the response:

    WDCompletionBlock completionBlock = ^(WDPaymentResponse *_Nullable response, NSError *_Nullable error) {
         if (error) {
             IPLogError(@"error: %@", error);
             UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                                 message:error.localizedDescription
                                                                delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
             [alertView show];
             return;
         }
         // handle successful response
     };
  5. Execute the transaction:

    [client makePayment:payment withCompletion:completionBlock];
     }
Custom URL: