- 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
Payment Drop-In Buttons
Drop-in buttons extend standard buttons in order to easily integrate separate payment brands to your app. This article is intended to guide you through the process of creating and configuring drop-in buttons.
Before you start adding buttons, please install the SDK and set up your server. Then you can proceed with the following guide.
Create payment button
The easiest way to create payment button is to add it in Interface Builder. Payment button needs only payment brand to be set to automatically display appropriate logo. You can set your own logo for the button and do all necessary customizations as well.
- Drag-n-drop standard button to the view and set class
OPPPaymentButton
onIdentity Inspector
tab. - Create an outlet for the button in your view controller.
- Set payment brand for the button, e.g. in
viewDidLoad
method. - Customize the payment button if necessary.
@property (nonatomic) IBOutlet OPPPaymentButton *paymentButton;
@IBOutlet var paymentButton: OPPPaymentButton!
- (void)viewDidLoad {
[super viewDidLoad];
self.paymentButton.paymentBrand = @"VISA";
}
override func viewDidLoad() {
super.viewDidLoad()
self.paymentButton.paymentBrand = "VISA"
}
[self.paymentButton setImage:[UIImage imageNamed:@"logo"] forState:UIControlStateNormal];
[self.paymentButton setBackgroundImage:[UIImage imageNamed:@"bg"] forState:UIControlStateNormal];
self.paymentButton.setImage(UIImage.init(named: "logo"), for: .normal)
self.paymentButton.setBackgroundImage(UIImage.init(named: "bg"), for: .normal)
NOTE: Do the image customization before setting a payment brand. Otherwise your image might be overwritten by a default brand logo.
Card payment button
Payment button can be used as card payment button irrespective of card brands. Payment brand will be detected based on card number. Payment brand need to be set as "CARD" for card payment button. Brand detection will be supported only for payment brands sent in CheckoutSettings.
self.paymentButton.paymentBrand = @"CARD";
self.paymentButton.paymentBrand = "CARD"
Implement button action method
Firstly add an action method to your view controller. In code sample you can see main steps that should be implemented in this method.
- (IBAction)paymentButtonAction:(id)sender {
// button will be used to get payment brand
OPPPaymentButton *button = (OPPPaymentButton *)sender;
// request checkout ID from your server
// configure OPPCheckoutProvider
// present checkout for specific payment brand and implement callbacks
}
@IBAction func paymentButtonAction(_ sender: Any) {
// button will be used to get payment brand
let button = sender as! OPPPaymentButton
// request checkout ID from your server
// configure OPPCheckoutProvider
// present checkout for specific payment brand and implement callbacks
}
Request checkout ID
To initiate payment checkout ID should be created. 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 json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any] {
let checkoutID = json?["checkoutId"] as? String
}
}.resume()
Create and configure checkout provider
OPPCheckoutProvider
should be initialized with payment provider, checkout ID and checkout settings.
OPPPaymentProvider *provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeTest];
OPPCheckoutSettings *checkoutSettings = [[OPPCheckoutSettings alloc] init];
checkoutSettings.paymentBrands = @[@"VISA"];
checkoutSettings.shopperResultURL = @"com.companyname.appname.payments://result";
OPPCheckoutProvider *checkoutProvider = [OPPCheckoutProvider checkoutProviderWithPaymentProvider:provider
checkoutID:checkoutID
settings:checkoutSettings];
let provider = OPPPaymentProvider(mode: OPPProviderMode.test)
let checkoutSettings = OPPCheckoutSettings()
checkoutSettings.paymentBrands = ["VISA"]
checkoutSettings.shopperResultURL = "com.companyname.appname.payments://result"
let checkoutProvider = OPPCheckoutProvider(paymentProvider: provider, checkoutID: checkoutID!, settings: checkoutSettings)
NOTE: for some payment brands no additional user info in app is required, shopper will be directly redirected to the issuer web page (e.g. PayPal). In this case you don't need to create checkout settings.
Tokenization
mSDK checkout page can display stored token for selected payment brand. You need to add additional parameter to the normal prepare checkout request (step 1). Your server should send shopper's tokens along with other configuration data such as amount, currency, order type and etc.
NOTE: mSDK automatically displays the first token for selected payment brand.
Present checkout and implement callbacks
Present checkout for specific payment brand using OPPCheckoutProvider
API.
- Payment form (Credit cards). If the shopper has stored tokens for selected payment brand the first of them will be displayed on the screen.
- Web page (to support asynchronous payments follow the Asynchronous Payments guide)
[checkoutProvider presentCheckoutWithPaymentBrand:button.paymentBrand
loadingHandler:^(BOOL inProgress) {
// Executed whenever SDK sends request to the server or receives the response.
// You can start or stop loading animation based on inProgress parameter.
} completionHandler:^(OPPTransaction * _Nullable transaction, NSError * _Nullable error) {
if (transaction.type == OPPTransactionTypeAsynchronous) {
// Open transaction.redirectURL in Safari browser to complete the transaction
} else if (transaction.type == OPPTransactionTypeSynchronous) {
// Send request to your server to obtain transaction status
if (transaction.resourcePath) {
// Get the payment status using the resourcePath.
}
}
} cancelHandler:^{
// Executed if the shopper closes the payment page prematurely.
}];
checkoutProvider?.presentCheckout(withPaymentBrand: button.paymentBrand,
loadingHandler: { (inProgress) in
// Executed whenever SDK sends request to the server or receives the answer.
// You can start or stop loading animation based on inProgress parameter.
}, completionHandler: { (transaction, error) in
if transaction.type == .asynchronous {
// Open transaction.redirectURL in Safari browser to complete the transaction
} else if transaction.type == .synchronous {
// Send request to your server to obtain transaction status
if transaction.resourcePath {
// Get the payment status using the resourcePath.
}
}
}, cancelHandler: {
// Executed if the shopper closes the payment page prematurely.
})
Get the Payment Status
Finally your app should request the payment status from your server (again, adapt this example to your own setup).
Based on chosen approach you will have to send checkout Id or resource path to your server.
NSURLRequest *merchantServerRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://YOUR_URL/paymentStatus/CHECKOUT_ID"]];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// handle error
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
BOOL transactionStatus = [result[@"paymentResult"] boolValue];
}] resume];
let merchantServerRequest = NSURLRequest(url: URL(string: "https://YOUR_URL/paymentStatus/CHECKOUT_ID"))
URLSession.shared.dataTask(with: request) { data, response, error in
if let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any] {
let transactionStatus = json?["paymentResult"] as? Bool
}
}.resume()
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
.
self.provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeLive];
let provider = OPPPaymentProvider(mode: OPPProviderMode.live)
3. Change your backend to use the correct API endpoints and credentials.
Create payment button
The easiest way to create payment button is to add it in your layout's xml. Payment button needs only payment brand to be set to automatically display appropriate logo. You can set your own logo for the button and do all necessary customizations as well.
-
Add
PaymentButtonFragment
to your activity. You can do it in two ways:
Declare it inside the activity's layout file<fragment android:name="com.oppwa.mobile.connect.checkout.dialog.PaymentButtonFragment" android:id="@+id/payment_button_fragment" android:layout_margin="10dp" android:layout_width="100dp" android:layout_height="65dp"/>
PaymentButtonFragment paymentButtonFragment = (PaymentButtonFragment) getSupportFragmentManager().findFragmentById(R.id.payment_button_fragment);
val paymentButtonFragment = supportFragmentManager.findFragmentById( R.id.payment_button_fragment) as PaymentButtonFragment
Or, programmatically add the fragment to an existing ViewGroup
PaymentButtonFragment paymentButtonFragment = new PaymentButtonFragment(); getSupportFragmentManager() .beginTransaction() .add(R.id.payment_button_fragment, paymentButtonFragment) .commit();
val paymentButtonFragment = PaymentButtonFragment() supportFragmentManager.beginTransaction() .add(R.id.payment_button_fragment, paymentButtonFragment) .commit()
Set payment brand and add
OnClickListener
paymentButtonFragment.setPaymentBrand("PAYPAL"); paymentButtonFragment.getPaymentButton().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /* request new checkout id */ } });
paymentButtonFragment.paymentBrand = "PAYPAL" paymentButtonFragment.paymentButton.setOnClickListener { /* request new checkout id */ }
NOTE: If Google Pay used as a payment option add this before payment brand is set: paymentButtonFragment.setPaymentButtonIntegrationMode(PaymentButtonIntegrationMode.PAYMENT_OPTION)-
Customize the payment button if necessary
paymentButtonFragment.getPaymentButton().setImageResource(R.drawable.image_resource); paymentButtonFragment.getPaymentButton().setBackgroundResource(R.drawable.background_resource);
paymentButtonFragment.paymentButton.apply { setImageResource(R.drawable.image_resource) setBackgroundResource(R.drawable.button_base_background) }
Card payment button
Payment button can be used as card payment button irrespective of card brands. Payment brand will be detected based on card number. Payment brand need to be set as "CARD" for card payment button. Brand detection will be supported only for payment brands sent in CheckoutSettings.
paymentButtonFragment.setPaymentBrand("CARD");
paymentButtonFragment.paymentBrand = "CARD"
Tokenization
The mSDK checkout page can display stored token for selected payment brand. Add the additional parameter to the normal prepare checkout request. Your server should send shoppers' tokens along with other configuration data such as amount, currency, order type and etc.
NOTE: mSDK automatically displays the first token for selected payment brand.
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.
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
}
Submit transaction
Create CheckoutSettings
. You can configure the payment brands in the checkoutSettings
the shopper can also use for payment in addition to the payment brand set in the setPaymentBrand
method:
Set<String> paymentBrands = new LinkedHashSet<String>();
paymentBrands.add("VISA");
paymentBrands.add("MASTER");
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")
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"
Or leave it empty:
CheckoutSettings checkoutSettings = new CheckoutSettings(checkoutId, null, Connect.ProviderMode.TEST);
val checkoutSettings = CheckoutSettings(checkoutId, null, Connect.ProviderMode.TEST)
Submit transaction and handle CheckoutActivityResult
.
public class MainActivity extends AppCompatActivity {
private final ActivityResultLauncher checkoutLauncher = registerForActivityResult(
new CheckoutActivityResultContract(),
this::handleCheckoutResult
);
private void submitTransaction() {
try {
// set the ActivityResultLauncher to handle CheckoutActivityResult
paymentButtonFragment.setActivityResultLauncher(checkoutLauncher);
paymentButtonFragment.submitTransaction(checkoutSettings);
} catch (PaymentException e) {
// error occurred
}
}
private void handleCheckoutResult(@NonNull CheckoutActivityResult result) {
if (result.isCanceled()) {
// shopper cancelled the checkout process
return;
}
String resourcePath = result.getResourcePath();
if (resourcePath != null) {
// request payment status using the resourcePath
}
}
}
class MainActivity : AppCompatActivity() {
private val checkoutLauncher = registerForActivityResult(CheckoutActivityResultContract()) {
result: CheckoutActivityResult -> handleCheckoutResult(result)
}
private fun submitTransaction() {
try {
// set the ActivityResultLauncher to handle CheckoutActivityResult
paymentButtonFragment.setActivityResultLauncher(checkoutLauncher)
paymentButtonFragment.submitTransaction(checkoutSettings)
} catch (e: PaymentException) {
// error occurred
}
}
private fun handleCheckoutResult(result: CheckoutActivityResult) {
if (result.isCanceled) {
// shopper cancelled the checkout process
return
}
val resourcePath = result.resourcePath
if (resourcePath != null) {
// request payment status using the resourcePath
}
}
}
For ASYNC transaction also override onNewIntent
method of your activity
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent.getScheme().equals("YOUR_SCHEME")) {
/* request payment status */
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
if (intent.scheme == "YOUR_SCHEME") {
/* request payment status */
}
}
[Optional] Receiving callbacks during checkout process
The checkout may send the callback CheckoutActivity.ACTION_ON_BEFORE_SUBMIT
when shopper submits the payment.
To receive it you should complete the following steps:
Create your broadcast receiver to listen the intents from the checkout.
public class CheckoutBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (CheckoutActivity.ACTION_ON_BEFORE_SUBMIT.equals(action)) {
String paymentBrand = intent.getStringExtra(CheckoutActivity.EXTRA_PAYMENT_BRAND);
String checkoutId = intent.getStringExtra(CheckoutActivity.EXTRA_CHECKOUT_ID);
ComponentName senderComponentName = intent.getParcelableExtra(
CheckoutActivity.EXTRA_SENDER_COMPONENT_NAME);
/* You can use this callback to request a new checkout ID if selected payment brand requires
some specific parameters or just send back the same checkout id to continue checkout process */
intent = new Intent(CheckoutActivity.ACTION_ON_BEFORE_SUBMIT);
intent.setComponent(senderComponentName);
intent.setPackage(senderComponentName.getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(CheckoutActivity.EXTRA_CHECKOUT_ID, checkoutId);
/* You also can abort the transaction by sending the CheckoutActivity.EXTRA_TRANSACTION_ABORTED */
intent.putExtra(CheckoutActivity.EXTRA_TRANSACTION_ABORTED, true);
context.startActivity(intent);
}
}
}
class CheckoutBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val action = intent?.action
if (CheckoutActivity.ACTION_ON_BEFORE_SUBMIT == action) {
val paymentBrand = intent.getStringExtra(CheckoutActivity.EXTRA_PAYMENT_BRAND)
val checkoutId = intent.getStringExtra(CheckoutActivity.EXTRA_CHECKOUT_ID)
val senderComponentName: ComponentName? = intent.getParcelableExtra(
CheckoutActivity.EXTRA_SENDER_COMPONENT_NAME)
/* You can use this callback to request a new checkout ID if selected payment brand requires
some specific parameters or just send back the same checkout id to continue checkout process */
val newIntent = Intent(CheckoutActivity.ACTION_ON_BEFORE_SUBMIT)
newIntent.component = senderComponentName
newIntent.setPackage(senderComponentName!!.packageName)
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
newIntent.putExtra(CheckoutActivity.EXTRA_CHECKOUT_ID, checkoutId)
/* You also can abort the transaction by sending the CheckoutActivity.EXTRA_TRANSACTION_ABORTED */
newIntent.putExtra(CheckoutActivity.EXTRA_TRANSACTION_ABORTED, true)
context.startActivity(newIntent)
}
}
}
Declare your broadcast receiver in AndroidManifest.xml
.
<receiver
android:name=".CheckoutBroadcastReceiver"
android:exported="false" />
NOTE: It is important to set android:exported="false"
to your broadcast receiver. In this case the only messages the broadcast receiver can receive are those sent by components of the same application or applications with the same user ID.
To provide the best security our SDK uses directed broadcasts. This way our broadcast is received only by the specified BroadcastReceiver. For this reason you should pass ComponentName
of your receiver to the submitTransaction
function.
CheckoutSettings settings = new CheckoutSettings(...);
ComponentName receiverComponentName = new ComponentName("yourPackageName", "yourReceiverClassName");
paymentButtonFragment.submitTransaction(checkoutSettings, receiverComponentName);
val checkoutSettings = CheckoutSettings(...)
val receiverComponentName = ComponentName("yourPackageName", "yourReceiverClassName")
paymentButtonFragment.submitTransaction(checkoutSettings, receiverComponentName)
[Only for versions from 2.26.0 upto 2.32.0] Your activity that contains payment button fragment will receive new intent from the CheckoutBroadcastReceiver
for the brands that do not need UI. In this case you should pass this intent to the payment button fragment in the onNewIntent
method of your activity:
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent.getAction() != null
&& intent.getAction().equals(CheckoutActivity.ACTION_ON_BEFORE_SUBMIT)) {
/* Pass intent from the CheckoutBroadcastReceiver to the payment button */
paymentButtonFragment.continueOnNewIntent(intent);
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
if (intent.action != null
&& intent.action == CheckoutActivity.ACTION_ON_BEFORE_SUBMIT) {
/* Pass intent from the CheckoutBroadcastReceiver to the payment button */
paymentButtonFragment.continueOnNewIntent(intent)
}
}
Request Payment Status
Finally your app should request the payment status from your server (adapt this example to your own setup).
Based on chosen approach you will have to send checkout Id or resource path to your server.
public String requestPaymentStatus() {
URL url;
String urlString;
HttpURLConnection connection = null;
String paymentStatus = null;
urlString = YOUR_URL + "/paymentStatus/" + CHECKOUT_ID;
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
}
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 CheckoutSettings
.
CheckoutSettings checkoutSettings = new CheckoutSettings(checkoutId, paymentBrands, Connect.ProviderMode.LIVE);
val checkoutSettings = CheckoutSettings(checkoutId, paymentBrand, Connect.ProviderMode.LIVE)
3. Change your backend to use the correct API endpoints and credentials.
Apple Pay Button Types
Several Apple Pay button types and styles are provided that you can use in your app. Beginning in iOS 14 and macOS 11, you can use the automatic style to let the current system appearance determine the appearance of the Apple Pay buttons in your app. Apple Pay button type can be customised with checkoutSettings.applePayType property but only to checkout payment selection screen and not the payment button integration.
The Apple Pay button type "continue" is supported for the iOS 15 and above.
//Apple Pay button type is set to Buy
checkoutSettings.applePayType = PKPaymentButtonTypeBuy;
//Apple Pay button type is set to Buy
checkoutSettings.applePayType = PKPaymentButtonType.buy
NOTE: By default PKPaymentButtonTypePlain/plain button type will be set.
You can change the button type by setting the checkoutSettings.applePayType property to any of the PKPaymentButtonType value available at Objective-C Apple Pay Button Types documentation for Objective-C and Swift Apple Pay Button Types documentation for Swift.