Embed payment acceptance in a mobile application, or why you can forget about PCI DSS and PA DSS
Is PCI DSS needed?
Sooner or later, the majority of owners and developers of online stores and mobile applications that accept payments online, ask the question: “should my project comply with PCI DSS standards?”.
PCI DSS is a security standard that applies to all organizations in the field of processing payment cards: retail outlets, processing centers, financial institutions and service providers, as well as other organizations that store, process or transmit cardholder data and / or critical authentication data .
The PA-DSS standard applies to application providers and other application developers who store, process or transmit cardholder data and / or critical authentication data.

Everything is quite simple with the website: during integration, it’s enough to use a technical solution that redirects the payer to the card data entry form located on the PCI DSS website of the certified payment gateway or downloads this page in a frame also from the certified website. In this case, the merchant does not fall within the scope of the security standard, since the card data is not stored or transmitted through its server, and the merchant’s website does not have access to the payment gateway frame due to the security policies of web browsers.
With a mobile application, things are a little more complicated. There is a popular misconception that if a mobile application requests card data, then it automatically falls under the PCI DSS standard. But, in fact, the organization developing standards for PCI DSS (PCI SSC - Payment Card Industry Security Standards Council) has not yet issued separate standards for mobile applications. And this means that the standard is still not binding, but advisory in nature for the most popular category of mobile applications, namely :
Category 3. Payment applications running on any household handheld devices (for example, smartphones, tablets, PDAs), the functionality of which is limited not only to the adoption of payments.
But since the mobile application cannot exist without a backend (the server side serving the billing and the main business logic), one way or another, it transfers the information necessary for processing the payment to the merchant’s server. Here lies the nuance - so that intentionally or accidentally the developer of the mobile application does not program the application to transfer payment card data to some non-certified server, the mobile payment SDK should make the card data inaccessible for reading. This limitation provides the abolition of PCI DSS requirements:
PCI DSS may not apply directly to payment application providers if they do not store, process or transmit cardholder data, or do not have access to cardholder cardholder data.
Let's see how this is implemented in the Fondy mobile payment service SDK using the example of an Android solution (there is also an iOS SDK ).
The solution is to enter the card data into the View created by the SDK library, and the mobile application uses the public methods of this View to initiate the payment, stylize the form and receive information about the completion of payment.
Example demo application for Android
First, create the visual structure of our payment form - layout (by the way, the entire source code of the demo application can be found on github ):
activity_main.xml
Please note that all elements except the card data in the application are different, and the form for entering the card number, expiration date and CVV2 are encapsulated in the class com.cloudipsp.android.CardInputView. It looks something like this (for tests, you can use the details specified in the documentation: https://www.fondy.eu/ru/info/api/v1.0/2 ):

At the same time, all elements, including those belonging to the class com.cloudipsp.android.CardInputView, can easily be stylized to the design of the main application. Also, for further work of the application with cards connected to 3DSecure, we need an element of the class com.cloudipsp.android.CloudipspWebView - this is a WebView in which the payer will be redirected to the website of his issuing bank to enter a personal password (in this picture - the page emulating work 3dsecure of the card issuing bank server:

Now let's move on to our main class, which will implement the application logic: public class MainActivity. Initialize the Cloudipsp class object:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_amount).setOnClickListener(this);
editAmount = (EditText) findViewById(R.id.edit_amount);
spinnerCcy = (Spinner) findViewById(R.id.spinner_ccy);
editEmail = (EditText) findViewById(R.id.edit_email);
editDescription = (EditText) findViewById(R.id.edit_description);
cardInput = (CardInputView) findViewById(R.id.card_input);
cardInput.setHelpedNeeded(BuildConfig.DEBUG);
findViewById(R.id.btn_pay).setOnClickListener(this);
webView = (CloudipspWebView) findViewById(R.id.web_view);
cloudipsp = new Cloudipsp(MERCHANT_ID, webView);
spinnerCcy.setAdapter(new ArrayAdapter(this, android.R.layout.simple_spinner_item, Currency.values()));
}
Next, we attach the handler to the object of class com.cloudipsp.android.Card to get the result of entering the card number:
@Override
public void onCardInputErrorClear(CardInputView view, EditText editText) {
}
@Override
public void onCardInputErrorCatched(CardInputView view, EditText editText, String error) {
editText.getText();
}
Now we will know when the user will complete the data entry, or, in case of an error, we will receive information about the problem. After the card data is entered, we can create an order:
if (card != null) {
final Currency currency = (Currency) spinnerCcy.getSelectedItem();
final Order order = new Order(amount, currency, "vb_" + System.currentTimeMillis(), description, email);
cloudipsp.pay(card, order, new Cloudipsp.PayCallback() {
@Override
public void onPaidProcessed(Receipt receipt) {
Toast.makeText(MainActivity.this, "Paid " + receipt.status.name() + "\nPaymentId:" + receipt.paymentId+"\n Signature:"+receipt.signature, Toast.LENGTH_LONG).show();
}
@Override
public void onPaidFailure(Cloudipsp.Exception e) {
if (e instanceof Cloudipsp.Exception.Failure) {
Cloudipsp.Exception.Failure f = (Cloudipsp.Exception.Failure) e;
Toast.makeText(MainActivity.this, "Failure\nErrorCode: " +
f.errorCode + "\nMessage: " + f.getMessage() + "\nRequestId: " + f.requestId, Toast.LENGTH_LONG).show();
} else if (e instanceof Cloudipsp.Exception.NetworkSecurity) {
Toast.makeText(MainActivity.this, "Network security error: " + e.getMessage(), Toast.LENGTH_LONG).show();
} else if (e instanceof Cloudipsp.Exception.ServerInternalError) {
Toast.makeText(MainActivity.this, "Internal server error: " + e.getMessage(), Toast.LENGTH_LONG).show();
} else if (e instanceof Cloudipsp.Exception.NetworkAccess) {
Toast.makeText(MainActivity.this, "Network error", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Payment Failed", Toast.LENGTH_LONG).show();
}
e.printStackTrace();
}
});
}
As you can see, the integration is quite simple and does not require much effort on the part of the application developer. At the same time, the SDK solves two problems at the same time - it gives the merchant a tool for accepting payments on payment cards and eliminates the need to undergo certification for security standards.