- Get Started
- Guides
- Integrations
- References
- API Reference
- Basic Payment
- Forex
- Authentication
- Card Account
- Apple Pay
- Virtual Account
- Bank Account
- Token Account
- Customer
- Billing Address
- Merchant Billing Address
- Shipping Address
- Merchant Shipping Address
- Corporate
- Sender
- Recipient
- Merchant
- Marketplace & Cart
- Airline
- Lodging
- Passenger
- Tokenization
- Recurring Migration
- 3D Secure
- Custom Parameters
- Async Payments
- Webhook notifications
- Job
- Risk
- Point of Sale
- Response Parameters
- Card On File
- Chargeback
- Result Codes
- Payment Methods
- Transaction Flows
- Regression Testing
- Data Retention Policy
- Release Notes
- API Reference
- Support
First integration
This guide will help you to make your first payment with ready-to-use payment forms.
Demo app
You are welcome to get started with our demo application. You can start making test transactions without any efforts including setting up a server, we provide a test integration server for you. Please note, that it is configured for demo purposes only.
The demo app is provided along with SDK since version 2.5.0.
NOTE: Before running the application, make sure SDK files are copied to the demo app folder. Find more details in the readme.txt file.
iOS
Android
Requirements
- Xcode 15 and iOS 14 SDK or higher
- iOS 10.0+ deployment target
Install the SDK
- Drag and drop
OPPWAMobile.xcframework
&ipworks3ds_sdk.xcframework
to the "Frameworks" folder of your project.
Make sure "Copy items if needed" is checked.
- Check "Frameworks, Libraries, and Embedded Content" section under the general settings tab of your application's target. Ensure the Embed dropdown has Embed and Sign selected for the framework.
You can now import the framework with:
#import <OPPWAMobile/OPPWAMobile.h>
#import <OPPWAMobile/OPPWAMobile.h>
There are two versions of the ipworks3ds_sdk.xcframework
included: one to be used for development and one for production. The production version includes more strict security measures that would not allow for common development processes to occur, including running with attached debuggers or using simulators/emulators. The deployment version includes _deploy
in the filename.
If you integrate SDK to the Swift app, please see the Apple guide Importing Objective-C into Swift to check how to import Objective-C headers correctly.
- Add the Mobile SDK for Android.
Add the required dependencies to your
build.gradle
. Refer dependencies.txt provided in the release. It contains list of required dependencies for Mobile SDK.
Drag and drop oppwa.mobile.aar
& ipworks3ds_sdk.aar
(use ipworks3ds_sdk_deploy.aar
for production) to the "libs" folder of the module where you plan to integrate Mobile SDK. In the build.gradle
file of this module add:
implementation fileTree(dir: "libs", include: ["*.aar"])
Make sure viewBinding feature is enabled.
buildFeatures {
viewBinding true
}
Set Up Your Server
To start working with our SDK, you should expose two APIs on your backend for your iOS app to communicate with:
To start working with our SDK, you should expose two APIs on your backend for your Android app to communicate with:
- Endpoint 1: Creating a checkout ID,
- Endpoint 2: Getting result of payment.
See detailed instruction in our guide "Set Up Your Server".
Request Checkout ID
Your app should request a checkout ID from your server. This example uses our sample integration server; please adapt it to use your own backend API.
NSURLRequest *merchantServerRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://YOUR_URL/?amount=100¤cy=EUR&paymentType=DB"]];
[[[NSURLSession sharedSession] dataTaskWithRequest:merchantServerRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// TODO: Handle errors
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
self.checkoutID = JSON[@"checkoutId"];
}] resume];
let merchantServerRequest = NSURLRequest(url: URL(string: "https://YOUR_URL/?amount=100¤cy=EUR&paymentType=DB")!)
URLSession.shared.dataTask(with: merchantServerRequest as URLRequest) { (data, response, error) in
// TODO: Handle errors
if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let checkoutID = json?["checkoutId"] as? String
}
}.resume()
public String requestCheckoutId() {
URL url;
String urlString;
HttpURLConnection connection = null;
String checkoutId = null;
urlString = YOUR_URL + "?amount=48.99¤cy=EUR&paymentType=DB";
try {
url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
JsonReader reader = new JsonReader(
new InputStreamReader(connection.getInputStream(), "UTF-8"));
reader.beginObject();
while (reader.hasNext()) {
if (reader.nextName().equals("checkoutId")) {
checkoutId = reader.nextString();
break;
}
}
reader.endObject();
reader.close();
} catch (Exception e) {
/* error occurred */
} finally {
if (connection != null) {
connection.disconnect();
}
}
return checkoutId;
}
fun requestCheckoutId(): String? {
val url: URL
var connection: HttpURLConnection? = null
var checkoutId: String? = null
val urlString = YOUR_URL.toString() + "?amount=48.99¤cy=EUR&paymentType=DB"
try {
url = URL(urlString)
connection = url.openConnection() as HttpURLConnection
val reader = JsonReader(InputStreamReader(connection.inputStream, "UTF-8"))
reader.beginObject()
while (reader.hasNext()) {
if (reader.nextName() == "checkoutId") {
checkoutId = reader.nextString()
break
}
}
reader.endObject()
reader.close()
} catch (e: Exception) {
/* error occurred */
} finally {
connection?.disconnect()
}
return checkoutId
}
Present Checkout UI
1. Initialize Payment Provider with test mode
self.provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeTest];
let provider = OPPPaymentProvider(mode: OPPProviderMode.test)
2. Configure the Checkout Settings
Define the settings for the checkout screen. Initialize OPPCheckoutSettings
, it controls the information that is shown to the shopper.
For the first integration we recommend you to enable only synchronous payment methods, other payment brands need additional configuration.
OPPCheckoutSettings *checkoutSettings = [[OPPCheckoutSettings alloc] init];
// Set available payment brands for your shop
checkoutSettings.paymentBrands = @[@"VISA", @"DIRECTDEBIT_SEPA"];
// Set shopper result URL
checkoutSettings.shopperResultURL = @"com.companyname.appname.payments://result";
let checkoutSettings = OPPCheckoutSettings()
// Set available payment brands for your shop
checkoutSettings.paymentBrands = ["VISA", "DIRECTDEBIT_SEPA"]
// Set shopper result URL
checkoutSettings.shopperResultURL = "com.companyname.appname.payments://result"
NOTE: In order to make sure that the Mobile SDK seamlessly supports every payment method, setting shopperResultUrl is mandatory. To learn more, see Asynchronous Payments guide.
3. Present the Checkout Page
Initialize OPPCheckoutProvider
with the received checkout ID and created settings.
OPPCheckoutProvider *checkoutProvider = [OPPCheckoutProvider checkoutProviderWithPaymentProvider:provider
checkoutID:checkoutID
settings:checkoutSettings];
let checkoutProvider = OPPCheckoutProvider(paymentProvider: provider, checkoutID: checkoutID!, settings: checkoutSettings)
Then, open the payment page and implement the callbacks.
// Since version 2.13.0
[checkoutProvider presentCheckoutForSubmittingTransactionCompletionHandler:^(OPPTransaction * _Nullable transaction, NSError * _Nullable error) {
if (transaction.type == OPPTransactionTypeSynchronous) {
// Send request to your server to obtain the status of the synchronous transaction
// You can use transaction.resourcePath or just checkout id to do it
// Error is no more an decisive factor for transaction termination
if (transaction.resourcePath) {
// get the payment status using the resourcePath
}
} else {
// The SDK opens transaction.redirectUrl in a browser
// See 'Asynchronous Payments' guide for more details
}
} cancelHandler:^{
// Executed if the shopper closes the payment page prematurely
}];
// Since version 2.13.0
checkoutProvider?.presentCheckout(forSubmittingTransactionCompletionHandler: { (transaction, error) in
if transaction.type == .synchronous {
// If a transaction is synchronous, just request the payment status
// You can use transaction.resourcePath or just checkout ID to do it
// Error is no more an decisive factor for transaction termination
if transaction.resourcePath {
// get the payment status using the resourcePath
}
} else if transaction.type == .asynchronous {
// The SDK opens transaction.redirectUrl in a browser
// See 'Asynchronous Payments' guide for more details
}
}, cancelHandler: {
// Executed if the shopper closes the payment page prematurely
})
For versions 2.12.0 and earlier use another method to open the checkout page.
Note there is an additional callback paymentBrandSelectedHandler
which allows you to create and pass to the SDK new checkout ID. In newer versions this callback is moved to OPPCheckoutProviderDelegate
. You may need this feature to send additional parameters at 1st step for specific payment brands. Otherwise set callback to nil
.
[checkoutProvider presentCheckoutForSubmittingTransactionCompletionHandler:^(OPPTransaction * _Nullable transaction, NSError * _Nullable error) {
// Handle transaction submitting result as shown in previous sample
} paymentBrandSelectedHandler:nil cancelHandler:^{
// Executed if the shopper closes the payment page prematurely
}];
checkoutProvider?.presentCheckout(forSubmittingTransactionCompletionHandler: { (transaction, error) in
// Handle transaction submitting result as shown in previous sample
}, paymentBrandSelectedHandler:nil, cancelHandler: {
// Executed if the shopper closes the payment page prematurely
})
NOTE: To ensure that the credit card data of the shopper is safe, close the payment pages when the app is sent to the background. Use the method
dismissCheckoutAnimated:completion:
of OPPCheckoutProvider
.[Optional] 4. Security. Disable third party keyboards.
A malicious third party keyboard may perform key-logging and transmit the logged information to an attacker’s server. It's recommended to disable the usage of third party keyboards entirely in your application. Note that this may degrade the user experience of your application.
- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(UIApplicationExtensionPointIdentifier)extensionPointIdentifier {
if (extensionPointIdentifier == UIApplicationKeyboardExtensionPointIdentifier) {
return NO;
}
return YES;
}
func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplicationExtensionPointIdentifier) -> Bool {
if (extensionPointIdentifier == UIApplicationExtensionPointIdentifier.keyboard) {
return false
}
return true
}
1. Configure the Checkout Settings
Define the settings for the checkout screen. Initialize CheckoutSettings
with received checkout ID, it controls the information that is shown to the shopper.
For the first integration we recommend you to enable only synchronous payment methods, other payment brands need additional configuration.
Set<String> paymentBrands = new LinkedHashSet<String>();
paymentBrands.add("VISA");
paymentBrands.add("MASTER");
paymentBrands.add("DIRECTDEBIT_SEPA");
CheckoutSettings checkoutSettings = new CheckoutSettings(checkoutId, paymentBrands, Connect.ProviderMode.TEST);
// since mSDK version 6.0.0 the shopper result URL is not required
checkoutSettings.setShopperResultUrl("companyname://result");
val paymentBrands = hashSetOf("VISA", "MASTER", "DIRECTDEBIT_SEPA")
val checkoutSettings = CheckoutSettings(checkoutId, paymentBrands, Connect.ProviderMode.TEST)
// since mSDK version 6.0.0 the shopper result URL is not required
checkoutSettings.shopperResultUrl = "companyname://result"
2. Present the Checkout Page
Start the checkout activity and handle the result.
public class MainActivity extends AppCompatActivity {
private final ActivityResultLauncher checkoutLauncher = registerForActivityResult(
new CheckoutActivityResultContract(),
this::handleCheckoutResult
);
private void startCheckout() {
checkoutLauncher.launch(checkoutSettings);
}
private void handleCheckoutResult(@NonNull CheckoutActivityResult result) {
if (result.isCanceled()) {
// shopper cancelled the checkout process
return;
}
String resourcePath = result.getResourcePath();
if (resourcePath != null) {
// get the payment status using the resourcePath
}
}
}
class MainActivity : AppCompatActivity() {
private val checkoutLauncher = registerForActivityResult(CheckoutActivityResultContract()) {
result: CheckoutActivityResult -> handleCheckoutResult(result)
}
private fun startCheckout() {
checkoutLauncher.launch(checkoutSettings)
}
private fun handleCheckoutResult(result: CheckoutActivityResult) {
if (result.isCanceled) {
// shopper cancelled the checkout process
return
}
val resourcePath = result.resourcePath
if (resourcePath != null) {
// get the payment status using the resourcePath
}
}
}
NOTE: The getErrorInfo() method of the PaymentError can be used to get more details about the error.
Get the Payment Status
Finally your app should request the payment status from your server (again, adapt this example to your own setup) for any result except cancelled.
NSString *URL = [NSString stringWithFormat:@"https://YOUR_URL/paymentStatus?resourcePath=%@", [transaction.resourcePath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *merchantServerRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:URL]];
[[[NSURLSession sharedSession] dataTaskWithRequest:merchantServerRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// handle error
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
BOOL status = [result[@"paymentResult"] boolValue];
}] resume];
let url = String(format: "https://YOUR_URL/paymentStatus?resourcePath=%@", transaction.resourcePath!.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)
let merchantServerRequest = NSURLRequest(url: URL(string: url)!)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let transactionStatus = json?["paymentResult"] as? Bool
}
}.resume()
NOTE: The transaction status may be not available immediately. To support all statuses please refer to the "Result Codes".
public String requestPaymentStatus() {
URL url;
String urlString;
HttpURLConnection connection = null;
String paymentStatus = null;
urlString = YOUR_URL + "/paymentStatus?resourcePath=" + URLEncoder.encode(RESOURCE_PATH, "UTF-8");
try {
url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
JsonReader jsonReader = new JsonReader(
new InputStreamReader(connection.getInputStream(), "UTF-8"));
jsonReader.beginObject();
while (jsonReader.hasNext()) {
if (jsonReader.nextName().equals("paymentResult")) {
paymentStatus = jsonReader.nextString();
break;
}
}
jsonReader.endObject();
jsonReader.close();
} catch (Exception e) {
/* error occurred */
} finally {
if (connection != null) {
connection.disconnect();
}
}
return paymentStatus;
}
fun requestPaymentStatus(): String? {
val url: URL
var connection: HttpURLConnection? = null
var paymentStatus: String? = null
val urlString = YOUR_URL.toString() + "/paymentStatus?resourcePath=" + URLEncoder.encode(RESOURCE_PATH, "UTF-8")
try {
url = URL(urlString)
connection = url.openConnection() as HttpURLConnection
val jsonReader = JsonReader(InputStreamReader(connection.inputStream, "UTF-8"))
jsonReader.beginObject()
while (jsonReader.hasNext()) {
if (jsonReader.nextName() == "paymentResult") {
paymentStatus = jsonReader.nextString()
break
}
}
jsonReader.endObject()
jsonReader.close()
} catch (e: Exception) {
/* error occurred */
} finally {
connection?.disconnect()
}
return paymentStatus
}
NOTE: The transaction status may be not available immediately. To support all statuses please refer to the "Result Codes".
Testing
The sandbox environment only accepts test payment parameters.
You can find test values for credit cards and bank accounts in our Testing Guide.
Go to Production
1. Talk to your account manager to get the live credentials.
2. Adjust the server type to LIVE in your initialization of OPPPaymentProvider
CheckoutSettings
.
self.provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeLive];
let provider = OPPPaymentProvider(mode: OPPProviderMode.live)
CheckoutSettings checkoutSettings = new CheckoutSettings(checkoutId, paymentBrands, Connect.ProviderMode.LIVE);
val checkoutSettings = CheckoutSettings(checkoutId, paymentBrand, Connect.ProviderMode.LIVE)