Mobile Payment SDK
First Steps
Before you start coding, you are going to need some credentials:
-
Merchant Account ID - the ID of your merchant account that will be used to process transactions
-
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:
Gateway | Hostname |
---|---|
Germany - production |
|
Germany - test |
|
Singapore - production |
|
Singapore - test |
|
UK & Ireland - production |
|
UK & Ireland - test |
|
Central and Eastern Europe - production |
|
Central and Eastern Europe - test |
|
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.
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:
-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
:
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:
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 .
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
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.
|
-
Create and initialize the
WirecardCardPayment
object, which stores the transaction’s payload & signature:WirecardCardPayment wirecardCardPayment = new WirecardCardPayment (signature, requestTimeStamp, requestID,merchantID, transactionType, amount, currency);
-
Initialize the
WirecardResponseListener
object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:WirecardResponseListener InitializationWirecardResponseListener 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; } } };
-
Call the
WirecardClient
's methodmakePayment
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. -
Process the response. If everything went smoothly server-side, the
onResponse
method will be called. If any errors occurred,onError
will be called instead.
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);
Despite strict rules, we give you as much customization as possible within the limits of the PCI DSS standards.
-
styling of the input fields
-
background color of the form & buttons
-
labels, hints, and their colors
-
icons for the supported card providers
-
To begin customizing, initialize
PaymentPageStyle
:PaymentPageStyle style = new PaymentPageStyle();
-
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:
-
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>
-
Create a new instance of this fragment:
WirecardCardFormFragment wirecardCardFormFragment = new WirecardCardFormFragment.Builder(wirecardExtendedCardPayment).build();
-
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.
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. |
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);
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:
-
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; ... } } };
-
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 input form gained focus |
|
exp. month input form gained focus |
|
exp. year input form gained focus |
|
security code (CVC/CID) input form gained focus |
|
card number input form focus lost |
|
exp. month input form focus lost |
|
exp. year input form focus lost |
|
security code (CVC/CID) input form focus lost |
|
card number wasn’t recognized after typing 3 numbers |
|
card number has reached max length but card validity check wasn’t successful |
|
card number is not complete, user typing his number |
|
card passes validity check |
|
expiration month is not complete yet. For example, user types one number, and jumps to expiration year field. |
|
expiration month is valid. Note that we don’t have event for invalid state, because user is able to enter only valid month. |
|
called when expiration year is not complete yet. |
|
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 is not complete yet |
|
security code is complete |
|
all inputs(card number, expiration month, expiration year and security code) are valid. When you get this event, you can proceed to next step |
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();
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:
-
Add a card token (as is, or instead of cardholder’s last name) to
WirecardExtendedCardPayment
:wirecardExtendedCardPayment.setCardToken(new CardToken(token, maskedCardNumber));
-
Create the
WirecardCardFormFragment
usingWirecardCardFormFragment.Builder
like this:wirecardCardFormFragment = new WirecardCardFormFragment.Builder(wirecardExtendedCardPayment) .setCardBrand(cardBrand) //for example CardBrand.VISA .setExpirationDate(expirationDate) // for example "1219" .build();
-
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();
-
Call
WirecardClient
'smakePayment()
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
-
Create and initialize
WirecardPayPalPayment
:WirecardPayPalPayment wirecardPayment = new WirecardPayPalPayment(signature, requestTimeStamp, requestID, merchantID, transactionType, amount, currency);
-
Initialize the
WirecardResponseListener
object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:WirecardResponseListener InitializationWirecardResponseListener 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; } } };
-
Call
WirecardClient
's methodmakePayment
to execute the transaction:wirecardClient.makePayment(wirecardPayPalPayment, wirecardResponseListener, paymentPageStyle);
-
Process the response. If everything went smoothly server-side,
wirecardResponseListener
'sonResponse
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
-
Create and initialize
WirecardSepaPayment
:WirecardSepaPayment payment = new WirecardSepaPayment (signature, requestTimeStamp, requestID, merchantID, transactionType, amount, currency, creditorId, mandateId, mandateSignedDate, merchantName, dueDate);
-
Initialize the
WirecardResponseListener
object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:WirecardResponseListener InitializationWirecardResponseListener 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; } } };
-
Call
WirecardClient
's methodmakePayment
to execute the transaction:wirecardClient.makePayment(wirecardSepaPayment, wirecardResponseListener, paymentPageStyle);
-
Process the response. If everything went smoothly server-side,
wirecardResponseListener
'sonResponse
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
-
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'
-
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.
-
-
Initialize the
WirecardResponseListener
object, which stores callback methods that let you know the result of the transaction, or any errors, should they occur:WirecardResponseListener InitializationWirecardResponseListener 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; } } };
-
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" />
-
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" />
-
Call
WirecardClient
's methodmakePayment
to execute the transaction:wirecardClient.makePayment(wirecardSepaPayment, wirecardResponseListener, paymentPageStyle);
-
Next, either the PBBA dialog is shown or the banking application is opened.
-
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.
-
Process the response. If everything went smoothly server-side,
wirecardResponseListener
'sonResponse
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:
-
Contact our merchant support to create a test Wirecard Payment Gateway Apple Pay merchant account and set up its Apple Merchant ID.
-
Depending on whether you have an existing Apple Merchant ID, you will need to:
-
upload the CSR file you’ve received in the previous step,
or
-
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:
-
You can add a test card to the Wallet app.
-
Integrate paymentSDK into your application
-
Conduct testing
-
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:
-
You need full control over PKPaymentRequest (dynamic shipping methods and pricing); use
WDApplePayPayment
-
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.
-
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];
-
Initialize
WDApplePayPayment
WDApplePayPayment *applePayPayment = [[WDApplePayPayment alloc] initWithPayment:payment summaryItems:self.sumaryItems currency:currency];
-
Generate
requestID
,requestTimestamp
, andrequestSignature
on your server and assign them toWDApplePayPayment
: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
-
Create a
completionBlock
to handle the response, then callPKPaymentAuthorizationViewController
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); };
-
Execute the transaction:
[client makePayment:applePayPayment withCompletion:completionBlock]; }
-
Initialize
WDClient
:- (void)makeApplePayManaged { // it is better to keep client as property to keep reference WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
-
Initialize
WDApplePayPayment
:WDApplePayManagedPayment *applePayPayment = [[WDApplePayManagedPayment alloc] initWithMerchant:kAppleMerchantID andCountry:WDCountryGB]; applePayPayment.amount = [NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO]; applePayPayment.amountCurrency = WDCurrencyGBP;
-
Generate
requestID
,requestTimestamp
, andrequestSignature
on your server and assign them toWDApplePayManagedPayment
: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
-
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 };
-
Execute the transaction:
[client makePayment:applePayPayment withCompletion:completionBlock]; }
Simple Transactions
-
Initialize
WDClient
:- (void)makeCardPayment { // it is better to keep client as property to keep reference WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
-
Initialize
WDCardPayment
:WDCardPayment *payment = [[WDCardPayment alloc] initWithAmount:[NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO] amountCurrency:WDCurrencyEUR transactionType:WDTransactionTypePurchase];
-
Generate
requestID
,requestTimestamp
, andrequestSignature
on your server and assign them toWDCardPayment
: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
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 };
-
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:
-
Create a
WDCardField
(programmatically, or in XIB/Storyboard) and keep the instance reference in yourUIViewController
:\@interface PaymentViewController UIViewController<WDCardFieldDelegate> \@property (nonatomic, weak) IBOutlet WDCardField *cardField; \@property (nonatomic, weak) IBOutlet UIButton *paymentButton; \@property (nonatomic, strong) WDClient *client; @end
-
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]; }
-
Implement the
WDCardFieldDelegate
protocol to handle user actions listed inWDCardFieldState
:#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 }
-
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
-
Override
AppDelegate
's method:- (void)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { [self.client openURL:url]; }
-
Implement
makePBBAPayment
inAppDelegate
. You need to initializeWDClient
:- (void)makePBBAPayment // it is better to keep client as property to keep reference self.client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
-
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.
-
-
Generate
requestID
,requestTimestamp
, andrequestSignature
on your server and assign them to theWDPBBAPayment
: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
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 };
-
Execute the transaction:
[self.client makePayment:payment withCompletion:completionBlock]; }
-
You need to use the
PBBAButton
to call themakePBBAPayment
method. -
Next, either the PBBA dialog is shown or the banking application is opened.
-
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
-
Initialize
WDClient
:- (void)makePayPalPayment { // it is better to keep client as property to keep reference WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
-
Initialize
WDPayPalPayment
:WDPayPalPayment *payment = [[WDPayPalPayment alloc] initWithAmount:[NSDecimalNumber decimalNumberWithMantissa:1275 exponent:-2 isNegative:NO] currency:WDCurrencyEUR]; payment.transactionType = WDTransactionTypeDebit;
-
Generate
requestID
,requestTimestamp
, andrequestSignature
on your server and assign them to theWDPayPalPayment
: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
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 };
-
Execute the transaction:
[client makePayment:payment withCompletion:completionBlock]; }
SEPA Direct Debit
-
Initialize
WDClient
:- (void)makeSEPAPayment { // it is better to keep client as property to keep reference WDClient *client = [[WDClient alloc] initWithEnvironment:WDEnvironmentTEST];
-
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;
-
Generate
requestID
,requestTimestamp
, andrequestSignature
on your server and assign them toWDSEPAPayment
: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
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 };
-
Execute the transaction:
[client makePayment:payment withCompletion:completionBlock]; }