Web Content Display

Open Payment Gateway - OPG

This documentation guides you through optile's Open Payment Gateway (OPG) features (for frontend checkout and backend use cases), and provides you with important information about the various integration scenarios, testing possibilities, and references.

At the end of this document we compiled a Glossary of Terms that can help you understanding the integration with optile.

Notice: to view further details, some articles require you to be signed in.

Web Content Display

First Steps

Every potential checkout webpage includes information about the purchase, payment amount, customer details, and a few additional details. This information is always issued from your server side system via HTTP POST Request. This is what we call a LIST Request.

You will need a valid account on our website to be able to test these features . If you do not already have an account, please contact us at: support@optile.net and we can create one for you. As soon as you receive your optile account credentials, you may start experimenting with the OPG Sandbox. Try your first LIST Request by following the four main steps as described below:

1. Configure your OPG Sandbox
  • In the portal go to the Dashboard and open the Provider Contracts section.
  • Choose the Test Adapter "TESTPSP". Make sure you add a valid URL e.g., (http://www.dummyvalidurl.com).
  • Select "Countries and networks", e.g., with Germany (DE) and France (FR) and the payment methods VISA, MasterCard, SEPA Direct Debit, PayPal, and Carte Bleue.
  • In the country-methods matrix at the end of the dialog, select Carte Bleue to only be available in France but not in Germany.
  • Access the Routing App from the Merchant Portal and activate the routes per country by choosing a routing strategy.
2. Generate a Sandbox Payment Token

A Token must be generated so that it can be used to authenticate your system against the Payment Gateway API.

To generate a Sandbox token, you would:

  • Go to the portal dashboard, open "Tokens" and generate a Sandbox Payment Token. It will be used later to authenticate your system against the Payment Gateway.
  • Copy and save the value immediately, as it can neither be shown again nor recovered due to security reasons. (But no worries, you can always generate a new one).
3. Install a tool for manual testing

We suggest that you use one of the browser plugins presented in Tools for Manual Testing. This will enable you to submit JSON POST requests easily by hand.

4. Do a LIST Request

Use the following values to submit your first LIST Request with the chosen tool:

  • URL: https://api.sandbox.oscato.com/api/lists
  • HTTP Method: POST
  • Basic Authentication User Name: [Your merchant code]
  • Basic Authentication Password: [Your sandbox payment token]
  • Header Content Type: application/vnd.optile.payment.enterprise-v1-extensible+json
  • Header Accept: application/vnd.optile.payment.enterprise-v1-extensible+json
  • Request Body Content: Copy and Paste the content on the side to the tool that you're using. This content is just an example, make sure that it stays in JSON Format.

You can read more about authentication and version headers in API Access.

For your request you should get back a successful HTTP 200 response with a list of available payment methods for this transaction (attribute networks.applicable).

If you configured your OPG Sandbox as described above, you will not see Carte Bleue in this list yet, all the other payment networks would be shown based on the example content above.

5. Visualize the LIST

You can use optile's Hosted Payment Page to easily visualize the content of a generated LIST with a default style by following the steps below:

  • Examine the LIST Response and take the content of the links.self attribute. That's the URL of the LIST Resource:

    https://api.sandbox.oscato.com/pci/v1/59722056cb4280f9550078e3lffpph128vffgueil7chn475bs

  • Append it as query parameter listUrl to the following URL of the Hosted Payment Page and open it in a browser:

    https://resources.sandbox.oscato.com/paymentpage/v2/responsive.html?listUrl=https://api.sandbox.oscato.com/pci/v1/59722056cb4280f9550078e3lffpph128vffgueil7chn475bs

Note that a LIST is only valid for 30 minutes, and as long no successful CHARGE has been made on it. Afterwards you will get an error and should create a new LIST Session (That's also why the above example link will not work).

Play Around

Do another LIST Request with an incremented transactionId (it's technically not required but still good practice to keep them unique) and change the attribute country to FR. Submit again, and now you should see a similar list in the response, but this time with Carte Bleue because we configured it earlier only for France.

Also, you can copy the logo URL (attribute links.logo) of one of the networks and open it in a browser. The logo of that payment method will show.

Take one of the credit cards in the list and open the URL from links.localizedForm in a browser. You will see a snippet of a simple HTML form without any styling. If you'd like, you may open the HTML source code. This snippet is another building block provided by OPG to generate the payment page.

To see an out-of-the-box example how a payment page is rendered, take a look at our Demo. There you can also play around with the country parameter that should go into the LIST Request, as well as several parameters offered by our AJAX Integration JavaScript library.

Example of LIST Request
{
  "transactionId": "tr101",
  "country": "DE",
  "customer": {
    "number": "42",
    "email": "john.doe@example.com"
  },
  "payment": {
    "amount": 19.99,
    "currency": "EUR",
    "reference": "Shop 101/20-03-2016"
  },
  "style" : {
    "client":"RESPONSIVE"
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "notificationUrl":"https://dev.oscato.com/shop/notify.html"
  }
}

Example of LIST Response
{
"links": {
  "self": "https://api.sandbox.oscato.com/pci/v1/5a4f43dabc12312dfef5752blt5et3mnk2abc123u0fm79bud2"},
"timestamp": "2018-01-05T09:22:31.355+0000",
"operation": "LIST",
"resultCode": "00000.11.000",
"resultInfo": "4 applicable and 0 registered networks are found",
"returnCode": {
  "name": "OK",
  "source": "GATEWAY" },
"status": {
  "code": "listed",
  "reason": "listed" },
"interaction": {
  "code": "PROCEED",
  "reason": "OK" },
"identification": {
  "longId": "5a4f43d7148b512dfef5752blt5et3mnk226k45uu0fm79bud2",
  "shortId": "02694-35736",
  "transactionId": "id_h0010" },
"networks": {
  "applicable": [{
    "code": "MASTERCARD", ... }]
... }

Web Content Display

Tools for Manual Testing

In order to see your optile payment (Sandbox) credentials working or to experiment with requests and responses, we encourage you to use a simple tool to submit POST requests before you start implementing. As a starting point you can follow the First Steps we have compiled for you.

Depending on your preferred environment we recommend these tools:

1. Insomnia

Free and open source, compatible with Windows, Mac and Linux operating systems. Download from the official page.

2. Firefox Add-On: RESTer

Get it from Firefox Add-ons

RESTer

3. Chrome App: Advanced REST Client

Get it from Chrome Web Store

4. Command line tool: cURL

Mac and Linux operating systems should have cURL available by default.

How to install cURL on Windows:

  1. Go to http://curl.haxx.se/download.html
  2. Download Win32 or Win64 Generic with SSL
  3. Copy curl.exe into a system path, e.g. C:\Windows\System32

Get your Merchant Code and Payment Token together, and run this command:

Command
curl --user [YOUR MERCHANT CODE]/[YOUR TOKEN]: --header "Accept:application/vnd.optile.payment.enterprise-v1-extensible+json" --data "transactionId=222&country=DE&payment.amount=9.99&payment.reference=Order-111&payment.currency=EUR&customer.number=333" -k https://api.sandbox.oscato.com/api/lists

Note that this request does not use JSON as content type for the input but (implicitly) application/x-www-form-urlencoded. If successful, the result will be JSON script and start like this (depending on your configuration):

JSON Result Example
{
"links": {
  "self": "https://api.sandbox.oscato.com/pci/v1/5a4fabc1238b512dfef5752blt5et3mnk226k4abc12379bud2"},
"timestamp": "2018-01-05T09:22:31.355+0000",
"operation": "LIST",
"resultCode": "00000.11.000",
"resultInfo": "4 applicable and 0 registered networks are found",
"returnCode": {
  "name": "OK",
  "source": "GATEWAY"}
...
}

Web Content Display

API Access

Authentication

Most Payment Gateway API calls require HTTP Basic Authentication using your Merchant Code and Payment Token (the "credentials") meaning:

  • Login Name: [your merchant code]
  • Password: [your payment token]

You need to access the Merchant Portal to generate payment tokens. Please be sure that you have the right permission levels to do that. Case you have questions regarding this, please consult our support team.

Note that the Login Name contains the Merchant Code only and the Password contains the Payment Token.

This applies to all calls which are issued from your server system, e.g., the LIST Request. This is why we generate this set of calls from the Server Payment API on the API Console page. You should not trigger any of these calls from a browser (or any other client under control of the end customer), since that would expose your credentials.

However, a few calls should be triggered from a browser (or other client), e.g. the CHARGE Request. These we refer to as Client Payment API on the API Console page. They do not require authentication with your credentials, only knowledge of a preceding LIST ID (which is a randomly generated token). Do not include your credentials in these calls issued from a customer client, e.g. on the browser.

Accept and Content Type Headers

For every request you should set two HTTP headers.

  • Content Type indicates what content format your input has
  • Accept indicates what content format you expect to receive in the reply

A typical value is: application/vnd.optile.payment.enterprise-v1-extensible+json

This implies communication via JSON. The level and version part (enterprise-v1-extensible in this case) can be adapted. See below for possible values.

At the moment we technically grant all merchants enterprise access in the OPG. But this may be adapted to the individual contractual agreements at some point.
API levels and versions

The easiest way to integrate is to use one of these API levels:

  • simple-v1-extensible for simple integrations
  • advanced-v1-extensible if you need to provide or get back advanced parameters (e.g. for invoice payments)
  • enterprise-v1-extensible for in-depth information on transaction routing etc.

The simple level may not be enough if you need to provide further details about the customer and/or purchased products. For example invoice payments need addresses and products for billing. This information can also be used for risk management purposes. If billing and shipping addresses are different, for example, some invoice providers may restrict the usage of invoice payment.

A recommended way of using the API levels is to use the simple level in daily operations, if possible, to generate minimum data volume. But in case of investigations of (GET) an existing CHARGE object, you need enterprise level to access additional information about routing and used providers.

The -extensible suffix indicates that API replies may provide additional attributes, and API calls may accept additional (always optional) attributes in the future. No parameter will be renamed or change it's meaning. Therefore, this would only require implementation on your side that does not break when additional (unknown) fields are provided. On the other hand, this gives you access to additional features immediately without dealing with versioning information again.

In case you cannot implement a robust way concerning future extensions, you may request static API versions that will never change. These are provided on request, please contact us directly in this case.

If ever parameters were renamed a new API version would be introduced, e.g. simple-v2-extensible. Switching versions is therefore completely under your control.

Sandbox and Live differences

The Sandbox and Live environment APIs are generally the same. However, there are two subtle technical differences which we made to allow for certain testing and demonstration scenarios:

CORS support

The Sandbox environment will generally allow Cross-origin resource sharing (CORS), by providing the following additional HTTP headers in the reply >>

The Live environment only allows CORS  for the very few Client Payment API calls (see above in section Authentication and the API Console). Other than that CORS will not return the aforementioned headers. Therefore a LIST Request from a browser for example will not be possible.

As long as you do not try to circumvent the rules from the Basic Authentication and try to initiate server-to-server calls from a browser, there is nothing to worry about and you will see no difference between Sandbox and Live environment APIs.

ELV Validator

For the payment network ELV (German "Lastschrift") the validation API will be more relaxed in Sandbox, in order to enable you to test payment data from your payment provider. But with special bank codes and account numbers you can also provoke a negative response to also test this case.

Other payment networks are not affected by this because their validation rules are more formalized.

HTTP Headers for CORS
Access-Control-Allow-Origin:  *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept, Authorization

Web Content Display

DEMO

This is a simple demo of a dynamically created payment page using optile's AJAX Integration.

  • Try changing the Country and see how it adapts payment methods and language to suit
  • Smart Network Switch enables auto-detection of credit card brands based on the number entered
  • Live validation performs validity checks while typing
  • Switch to mobile version loads the mobile optimized checkout and gives you an impression on how it would look like on a smartphone
  • In real life you can...
    • ...apply your own custom styling,
    • ...change the payment method configurations with a click,
    • ...and much more.

Web Content Display

Integration Scenarios

optile's Open Payment Gateway (OPG) provides you with various features on both the backend and the frontend levels. In that respect, we offer you different backend integration scenarios as well as frontend checkout scenarios.

The backend integration scenarios are clustered into 2 groups: Simple and Advanced Integrations.

The simple integration scenarios include the following integration types as displayed in the diagrams below:

Integration Scenario Origin of the Payment Page Destination of Payment Details PCI Requirement
Simple Integration
Hosted Payment Page redirect URL from optile optile / OPG SAQ A
Selective Native with AJAX Payment Page is generated by the merchant server using optile's AJAX Library + iFrame by optile optile / OPG SAQ A
Display Native with AJAX Merchant Server using optile's AJAX Library optile / OPG SAQ A-EP

On the other hand, the advanced integration scenarios include the following integration types as displayed in the diagrams below:

Integration Scenario Origin of the Payment Page Destination of Payment Details PCI Requirements
Advanced Integration
Selective Native Payment Page is generated by the merchant server + iFrame by optile optile / OPG

SAQ A

Display Native The merchant server generates the payment page optile / OPG SAQ A-EP
Pure Native The merchant server generates the payment page Merchant Server SAQ D
Pure Native with Client Side Encryption The merchant server generates the payment page optile / OPG SAQ A-EP

 

Web Content Display

Integration Scenarios Comparison

The Payment Gateway provides a lot of flexibility to merchants by allowing multiple ways to integrate the frontend part of the payment processes (as opposed to the backend interactions that naturally follow a standard way). These integration scenarios have different strengths concerning aspects like initial integration effort, conversion, user experience and security certification requirements.

In general we recommend the AJAX Integration. It provides a very good user experience with minimum implementation effort, and can be combined with the Selective Native integration to minimize PCI requirements on your side. However, for some specific merchant requirements a different integration scenario may make better sense. For integration with mobile devices or any other devices that do not rely on web browser rendering (e.g., Smart TVs) we offer special mobile integration scenarios.

Visualization

Integration Scenarios Taxonomy

Comparison of Features and Implementation Effort
  Hosted Selective Native via AJAX Selective Native Display Native via AJAX Display Native Pure Native with CSE Pure Native
PCI DSS              
Required SAQ A A A A-EP A-EP A-EP D


Features

             
Payment Page generation on optile side browser browser or server side browser browser (or other client) or server side server side server side
Resulting view redirect or include in iFrame native HTML with partial iFrames native HTML with partial iFrames native HTML native HTML or other UI native HTML or other UI native HTML or other UI
Splitting method selection from details entering possible? yes yes yes yes yes yes yes
In-page Account Validations yes yes yes yes yes yes yes
User Experience good very good very good very good perfect perfect perfect
Payment Details Submission to OPG to OPG to OPG to OPG to OPG to OPG to merchant server


Integration Effort

             
Method LIST Rendering auto auto implement auto implement implement implement
In-page Account Validations auto auto (configurable) implement partly, web service provided auto
(configurable)
implement, web service provided implement, web service provided implement, web service provided
CHARGE Submission auto auto implement auto implement implement implement
Result Processing and Redirection auto auto implement auto implement, indicator provided implement, indicator provided implement, indicator provided
Internationalisation auto auto auto auto implement, texts provided implement, texts provided implement, texts provided
Styling default CSS, override recommended style of shop, CSS override for partial iFrames recommended style of shop, CSS override for partial iFrames recommended style of shop, example CSS provided style of shop style of shop style of shop

Web Content Display

Simple Integrations

Web Content Display

Hosted

In Hosted integration scenario the OPG creates a fully hosted HTML payment checkout page for you when you submit the LIST Request. You redirect your customer there, or put it into an iFrame on your page. In any case you can provide your own CSS stylesheet.

This means lowest implementation effort for you, but of course also limited flexibility.

This integration scenario requires the easy to achieve and light PCI compliance standard, the SAQ A. Here you can download the SAQ A requirements. All the requirements have to be implemented and confirmed by signing the self-assessment questionnaire (SAQ). The signed SAQ is also your "attestation of compliance (AoC)", which may be requested from you by your acquiring bank or PSP. If you have any questions or need any assistance please do not hesitate to contact us, we are glad to help.

Note: If you plan not to offer any credit card payments, then you do not have to do anything regarding PCI requirements.

This is how it works in detail:

1. You initialize the payment from your backend (LIST Request). Set the parameter style.client to RESPONSIVE to get the most recent version of the hosted payment page (v2). It features a full responsive design and high-resolution payment method logos. The legacy versions (v1) can be accessed with the parameter values DESKTOP, PHONE, or AUTO (default). Based on the given information OPG generates a web page with all possible payment methods that can be used to pay this particular transaction.

2. As a reply you get a URL to this generated page.
Example Reply

{
  "redirect": {
    "method": "GET",
    "url": "https://api.oscato.com/paymentpage/checkout-auto.html?listId=e909b8f7-97fd-463e-9069-313632a9b8cc",
    "suppressIFrame": false
  },
  "interaction": {
    "reason": "PENDING",
    "code": "PROCEED"
  },
  "resultInfo": "Pending, you have to check the status later",
  "links": {
    "self": "https://api.oscato.com/api/lists/e909b8f7-97fd-463e-9069-313632a9b8cc"
  }
}

Hosted

In Hosted integration scenario the OPG creates a fully hosted HTML payment checkout page for you when you submit the LIST Request. You redirect your customer there, or put it into an iFrame on your page. In any case you can provide your own CSS stylesheet.

This means lowest implementation effort for you, but of course also limited flexibility.

This integration scenario requires the easy to achieve and light PCI compliance standard, the SAQ A. Here you can download the SAQ A requirements. All the requirements have to be implemented and confirmed by signing the self-assessment questionnaire (SAQ). The signed SAQ is also your "attestation of compliance (AoC)", which may be requested from you by your acquiring bank or PSP. If you have any questions or need any assistance please do not hesitate to contact us, we are glad to help.

Note: If you plan not to offer any credit card payments, then you do not have to do anything regarding PCI requirements.

Please sign in to view further details of this article. Login

Web Content Display

Selective Native with AJAX

Selective Native can be either implemented by using our AJAX Library or as a native solution. In both cases, the logic behind the implementation is the same, with the difference that a native integration requires the development of your own JavaScript code while a so-called AJAX integration uses a library provided by optile.

Here we give you an overview of how our AJAX library communicates with the OPG and especially the Selective Native iFrames. Please use the session "AJAX library Integration" as a reference to our AJAX library.

optile's AJAX Integration Library enables you to have a seamless integration of the OPG payment checkout into your own websites, with minimum implementation effort.

Essentially the JavaScript library takes over a major part of the communication with optile's OPG and creates the actual user interface for checking out. You can read about the general communication flow with OPG in our Getting Started Overview. In the AJAX integration scenario you only need the initial LIST Request implemented in your server system and a Notification Listener.

A Selective Native with AJAX integration requires only PCI DSS SAQ A compliance, here you can download the PCI DSS SAQ A requirements. All requirements have to be implemented and confirmed by signing the self-assessment questionnaire (SAQ). The signed SAQ is also your "attestation of compliance (AoC)", which may in the future be requested from you by your acquiring bank. If you have any questions or need any assistance please do not hesitate to contact us, we are glad to help.

Selective Native is designed to provide superior security for credit and debit cards in the payment page, so that you only need to be PCI A compliant, as opposed to PCI A-EP, which requires substantially more effort. At the same time we keep integration as invasive as possible, so that you have maximum control over the page's look & feel to present the payment page conversion-optimal with your corporate design.

Selective Native can be implemented natively on your side or combined with our own AJAX Library. So if you are using our AJAX library you will not have any extra implementation effort, simply change the integration parameter in the LIST Request to SELECTIVE_NATIVE. For Hosted Integration Selective Native will not be neccessary because the whole hosted page already comes from a PCI certified optile domain.

Technical Concept

Selective Native replaces those parts on the payment page with iFrames where neccessary. That means that all credit and debit card forms will be in small iFrames that come from a fully PCI certified optile domain. The card data that the user enters there cannot be read from the surrounding page. Still, all other parts of the page are yours with the corresponding visual style. Even the small iFrame forms can be styled by providing a CSS file.

This is how the form inside the iFrame would be embedded into the payment page:

Here we show you how to handle the Selective Native iFrames on a high level. You should use our AJAX Library Integration as a reference case you want to implement this part on your own.

Communication Flow

Here is a conceptual overview of the client-server and inter-frame communication messages when our AJAX library is used.

You initialize the payment from your backend (LIST Request).

  1. The long ID of the generated method LIST is passed back to the customer's browser with the full list of methods and all resources (images, HTML input forms, etc). At this moment you hand the long ID over to our AJAX Integration JavaScript library and specify the HTML container element.
  2. The JavaScript library will now build the whole payment selection form inside the given HTML container element. This way it is fully integrated into your website.
  3. Your customer can now submit his payment details and will be redirected to next page (your success or cancel page, or an external page like PayPal). Your backend will receive a status notification about the payment result in any case.

Note: This approach uses client-side payment page generation. However, if you implement this yourself, you could also generate it on the server side. For more information on how to build this Scenario, please go to the AJAX Integration section.

Selective Native with AJAX

Selective Native can be either implemented by using our AJAX Library or as a native solution. In both cases, the logic behind the implementation is the same, with the difference that a native integration requires the development of your own JavaScript code while a so-called AJAX integration uses a library provided by optile.

Here we give you an overview of how our AJAX library communicates with the OPG and especially the Selective Native iFrames. Please use the session "AJAX library Integration" as a reference to our AJAX library.

optile's AJAX Integration Library enables you to have a seamless integration of the OPG payment checkout into your own websites, with minimum implementation effort.

Essentially the JavaScript library takes over a major part of the communication with optile's OPG and creates the actual user interface for checking out. You can read about the general communication flow with OPG in our Getting Started Overview. In the AJAX integration scenario you only need the initial LIST Request implemented in your server system and a Notification Listener.

A Selective Native with AJAX integration requires only PCI DSS SAQ A compliance, here you can download the PCI DSS SAQ A requirements. All requirements have to be implemented and confirmed by signing the self-assessment questionnaire (SAQ). The signed SAQ is also your "attestation of compliance (AoC)", which may in the future be requested from you by your acquiring bank. If you have any questions or need any assistance please do not hesitate to contact us, we are glad to help.

Please sign in to view further details of this article. Login

Web Content Display

Display Native with AJAX

Here we give you an overview of how our AJAX library communicates with the OPG in the context of a Display Native integration. Please use the session "AJAX library Integration" as a reference in case you cannot use our AJAX library and you need to implement this part on your own.

optile's AJAX Integration Library enables you to have a seamless integration of the OPG payment checkout into your own websites, with minimum implementation effort.

Essentially the JavaScript library takes over a major part of the communication with optile's OPG and creates the actual user interface for checking out. You can read about the general communication flow with OPG in our Getting Started Overview. In the AJAX integration scenario you only need the initial LIST Request implemented in your server system and a Notification Listener.

If you plan to offer credit card payments to your customers and any of your website elements will process cardholder data, you need to ensure that you are compliant with all the PCI DSS SAQ A-EP requirements. Here you can download the PCI DSS SAQ A-EP requirements. They have to be implemented and confirmed by signing the self-assessment questionnaire (SAQ). The signed SAQ is also your "attestation of compliance (AoC)", which may in the future be requested from you by your acquiring bank. If you have any questions or need any assistance please do not hesitate to contact us, we are glad to help.

Here is how the communication in this scenario looks like:

You initialize the payment from your backend (LIST Request).

  1. The ID of the generated method LIST is passed back to the customer's browser where you hand it over to our AJAX Integration JavaScript library and specify the HTML container element.
  2. The JavaScript library will now get the full list of methods and all resources (images, HTML input forms, etc) automatically and build the whole payment selection form inside the given HTML container element. This way it is fully integrated into your website.
  3. Your customer can now submit his payment details and will be redirected to next page (your success or cancel page, or an external page like PayPal). Your backend will receive a status notification about the payment result in any case.

For more information on how to build this Scenario, please go to the AJAX Integration section.

Display Native with AJAX

Here we give you an overview of how our AJAX library communicates with the OPG in the context of a Display Native integration. Please use the session "AJAX library Integration" as a reference in case you cannot use our AJAX library and you need to implement this part on your own.

optile's AJAX Integration Library enables you to have a seamless integration of the OPG payment checkout into your own websites, with minimum implementation effort.

Essentially the JavaScript library takes over a major part of the communication with optile's OPG and creates the actual user interface for checking out. You can read about the general communication flow with OPG in our Getting Started Overview. In the AJAX integration scenario you only need the initial LIST Request implemented in your server system and a Notification Listener.

If you plan to offer credit card payments to your customers and any of your website elements will process cardholder data, you need to ensure that you are compliant with all the PCI DSS SAQ A-EP requirements. Here you can download the PCI DSS SAQ A-EP requirements. They have to be implemented and confirmed by signing the self-assessment questionnaire (SAQ). The signed SAQ is also your "attestation of compliance (AoC)", which may in the future be requested from you by your acquiring bank. If you have any questions or need any assistance please do not hesitate to contact us, we are glad to help.

Please sign in to view further details of this article. Login

Web Content Display

Advanced Integrations

Web Content Display

Selective Native

Selective Native can be either implemented as a native solution or by using our AJAX Library. In both cases, the logic behind the implementation is the same, with the difference that a native integration requires the development of your own JavaScript code while a so-called AJAX integration uses a library provided by optile.

If you want to get an overview about Selective Native, please head to Selective Native with AJAX, which contains a general explanation of the integration scenario.

For a detailed explanation on how to implement Selective Native, please go to Selective Native Integration.

Selective Native

Selective Native can be either implemented as a native solution or by using our AJAX Library. In both cases, the logic behind the implementation is the same, with the difference that a native integration requires the development of your own JavaScript code while a so-called AJAX integration uses a library provided by optile.

If you want to get an overview about Selective Native, please head to Selective Native with AJAX, which contains a general explanation of the integration scenario.

For a detailed explanation on how to implement Selective Native, please go to Selective Native Integration.

Please sign in to view further details of this article. Login

Web Content Display

Display Native

The native integration means that you build the payment checkout page yourself based on the information provided by the LIST response, on your server side. This way you have full control and seamless integration into your pages. Note, that from a user experience standpoint you can achieve similar results through the AJAX Integration with even less implementation effort.

In native scenarios you have the choice of sending your customers submitted payment data to your own servers first, instead of having it sent directly to OPG. This depends on whether you want to see sensitive payment data and if you are allowed to do so by PCI DSS standards.

In the Display Native integration sensitive data goes directly to OPG, and never passes through your server systems. This scenario requires that the merchant is compliant with all the SAQ A-EP requirements. Here you can download the SAQ A-EP requirements.

These requirements have to be checked, signed, and submitted for revision if needed. If you have any questions or need any assistance please do not hesitate to contact us.

In addition there is a variation of the "Display Native" integration, intended for user interfaces without web browser rendering (e.g. native mobile apps), the Half-Native Integration.

Display Native Integration

  1. You initialize the payment from your backend (LIST Request) and based on the provided information, OPG replies with a JSON structure containing all possible payment methods that can be used to pay this particular transaction (LIST Response). With every network, there also comes an HTML snippet representing the corresponding form where the customer needs to fill in their payment account details (e.g. credit card number etc).
     
  2. With this information you can build your own payment page. Your implementation should not be aware of the payment networks in advance. Everything should be fetched and generated at runtime. This way you can activate additional payment networks by configuration only (i.e., without changing your implementation).
     
  3. The payment account details are then submitted directly to OPG via the CHARGE Request. Since your server does not touch the sensitive payment account details, you do not have to be PCI compliant.
Notes

Redirect Networks such as PayPal, Sofortüberweisung, etc. do not require payment account details in advance. The corresponding form and the subsequent CHARGE request will be empty in this case. Instead the redirect URL will point to the external page provided by that network (e.g., the PayPal login screen). After the customer has completed this step, they will be redirected to your system again. For you this is transparent. You do not need to care for those networks in your implementation explicitly (see also the details on the CHARGE Request). In this scenario the Status Notification is important because the CHARGE reply goes directly back to the client and not to the Merchant's server system.

Continue reading how to analyze the LIST Response.

Localized Forms

If you wish to implement optile's localized forms snippets returned from the original List response, please refer to the Localized Forms section for details.

Display Native

The native integration means that you build the payment checkout page yourself based on the information provided by the LIST response, on your server side. This way you have full control and seamless integration into your pages. Note, that from a user experience standpoint you can achieve similar results through the AJAX Integration with even less implementation effort.

In native scenarios you have the choice of sending your customers submitted payment data to your own servers first, instead of having it sent directly to OPG. This depends on whether you want to see sensitive payment data and if you are allowed to do so by PCI DSS standards.

In the Display Native integration sensitive data goes directly to OPG, and never passes through your server systems. This scenario requires that the merchant is compliant with all the SAQ A-EP requirements. Here you can download the SAQ A-EP requirements.

These requirements have to be checked, signed, and submitted for revision if needed. If you have any questions or need any assistance please do not hesitate to contact us.

Please sign in to view further details of this article. Login

Web Content Display

Pure Native

The native integration means that you build the payment checkout page yourself based on the information provided by the LIST response, on your server side. This way you have full control and seamless integration into your pages.

In native scenarios you have the choice of sending your customers submitted payment data to your own servers first, instead of having it sent directly to OPG. This depends on whether you want to see sensitive payment data and if you are allowed to do so by PCI DSS standards.

Pure Native Integration lets you pass sensitive data through your servers in which you process cardholder data by yourself. This scenario requires PCI SAQ D compliance for the merchant.

These requirements have to be checked, signed, and submitted for revision if needed. If you have any questions or need any assistance please do not hesitate to contact us.

Pure Native Integration

For the LIST Request and payment page rendering, this scenario is like the "Display Native" Scenario.

However, from the payment checkout page the sensitive payment account details first go to your own servers, where they could be stored or analyzed by your own custom logic. From there, the CHARGE Request is then submitted to OPG.

Note that by credit card industry standards, you are only allowed to process credit card details on your servers if you are certified by the corresponding PCI DSS levels. This not only concerns storage of data, but also in-memory processing.

Continue reading how to analyze the LIST Response.

Localized Forms

If you wish to implement optile's localized forms snippets returned from the original List response, please refer to the Localized Forms section for details.

Pure Native

The native integration means that you build the payment checkout page yourself based on the information provided by the LIST response, on your server side. This way you have full control and seamless integration into your pages.

In native scenarios you have the choice of sending your customers submitted payment data to your own servers first, instead of having it sent directly to OPG. This depends on whether you want to see sensitive payment data and if you are allowed to do so by PCI DSS standards.

Pure Native Integration lets you pass sensitive data through your servers in which you process cardholder data by yourself. This scenario requires PCI SAQ D compliance for the merchant.

These requirements have to be checked, signed, and submitted for revision if needed. If you have any questions or need any assistance please do not hesitate to contact us.

Please sign in to view further details of this article. Login

Web Content Display

Pure Native with CSE

The Pure Native with Client Side Encryption has a very similar flow to a Pure Native scenario, but with an important difference in that payment data is encrypted by the client (web browser or application) and sent to the OPG, so your servers have no access to it. This means that this scenario requires only SAQ A-EP requirements, instead of PCI D as in a Pure Native integration. These requirements have to be checked, signed, and submitted for revision if needed. If you have any questions or need any assistance please do not hesitate to contact us.

The native integration means that you build the payment checkout page yourself based on the information provided by the LIST response, on your server side. This way you have full control and seamless integration into your pages.

Process Flow of Client Side Encryption

optile will provide you with a public key for encryption ahead of time, which you should store. The software-client of the user (e.g. web page in browser, but possibly also mobile clients) will use this key later on during the process.

The payment process is initialized with the LIST Request. You can build the payment page server side or client side, just like the other integration scenarios. However, in case of Client Side Encryption optile's AJAX library is not well suited for building the client side payment page, since it would submit payment data directly to the OPG instead of your custom endpoint. If you want to use it anyway, you can request a development version of the library, which you can adjust to your needs.

To make this flow compatible with the PCI A-EP level of compliance, when the user enters their payment account data (e.g. card data, but also SEPA IBAN or others), the data must be encrypted by the client so that only optile can decrypt it. For that, this flow uses the public key provided to you and the algorithms and data structures described below. Optionally, the timestamp of encryption and/or the ID of the LIST session can be used for encryption, in order to assure that the card data is being used in the context of this specific payment session.

For web contexts, optile will provide a JavaScript library providing a function that handles the encryption for you. Your client can subsequently send the encrypted data anywhere to your systems. As your server systems will not be able to decrypt the data without having access to optile's private key, this flow requires only PCI A-EP certification instead of PCI D. Your system will then send the encrypted account data to the OPG via the CHARGE Request (in the context of the corresponding LIST session).

In this scenario there will be a synchronous response to your server systems with all relevant information (in addition the OPG will send a Status Notification that your server systems would need in other integration scenarios, but is not so important here, because we are already using reliable server-to-server communication). In a web context, your systems then typically respond to the client with an HTTP redirect depending on the transaction result.

Here is a visualization of the process described above:

  1. The LIST Request and payment page rendering are very similar to a Pure Native implementation.
  2. However, sensitive account data are encrypted on the customer client before being sent to your servers.
  3. From there, the CHARGE Request is submited,  and the data can only be decrypted by the OPG.
  4. Your systems will receive status notifications and redirection URLs as in a standard Pure Native scenario.

Note that by credit card industry standards, you are only allowed to process credit card details on your servers if you are certified by the corresponding PCI DSS levels. This not only concerns storage of data, but also in-memory processing. Due to the nature of the Client Side Encryption, a PCI A-EQ level is required.

Continue reading how to analyse the LIST Response.

Localized Forms

If you wish to implement optile's localized forms snippets returned from the original List response, please refer to the Localized Forms section for details.

Pure Native with CSE

The Pure Native with Client Side Encryption has a very similar flow to a Pure Native scenario, but with an important difference in that payment data is encrypted by the client (web browser or application) and sent to the OPG, so your servers have no access to it. This means that this scenario requires only SAQ A-EP requirements, instead of PCI D as in a Pure Native integration. These requirements have to be checked, signed, and submitted for revision if needed. If you have any questions or need any assistance please do not hesitate to contact us.

The native integration means that you build the payment checkout page yourself based on the information provided by the LIST response, on your server side. This way you have full control and seamless integration into your pages.

Please sign in to view further details of this article. Login

Web Content Display

Mobile Integration

There are several ways to integrate the payment page into a native mobile client, such as iOS and Android based devices. The following considerations alo apply to all other devices or applications that do not rely on web browser rendering, such as smart TV apps.

The challenge of non-web devices is that the data from the LIST Response cannot be integrated directly, because the input forms for the payment methods are described in HTML. Due to the smaller screen estate for smartphones and touch interaction paradigms also additional adjustments in the user interface can be beneficial.

As a result there are 3 main approaches to mobile integration:

  • WebViews: An HTML based view is integrated into the app. It could be optile's hosted page (which is mobile responsive out of the box) or a customly designed page by the merchant. In the latter case all considerations about the web Integration Scenarios apply again.
  • Half-Native: Native forms are predefined and selected for display based on the LIST Response. This can be either based on the Display Native Scenario with Charge submission directly to OPG, or Pure Native with Charge submission to your server first.
  • Dynamic Native: A JSON representation of the required data for each payment method will be added to the LIST response, so that native forms can be built more easily (planned).

You can find a comparison here and more information about Half-Native Integration below:

Mobile Features and Implementation effort
  Half-Native WebView
with optile Hosted Page
WebView
with Merchant Hosted Page


Features

     
Payment page integration native WebView WebView
Payment user flow arbitrary 1 page arbitrary
In-page account validations yes yes yes
"Implement once" for new methods no yes yes
User experience excellent very good very good
Payment account submission to Payment Gateway
(or Merchant)
to Payment Gateway to Payment Gateway
(or Merchant)
PCI DSS certification needed by merchant SAQ A-EP
(D if submission to Merchant)
SAQ A/A-EP SAQ A-EP
(D if submission to Merchant)


Integration Effort

     
Method LIST Rendering implement auto implement, library provided
In-page Account Validations implement, web API provided auto implement, library provided
CHARGE Submission implement auto implement, library provided
Result Processing and Redirection implement auto implement, library provided
Internationalisation provided through API auto implement, library provided
Styling native shop style default CSS, override possible custom CSS

Web Content Display

Half-Native Integration

The Half-Native-Integration is typically used for devices or applications that do not rely on web browser rendering, such as native smartphone or smart TV apps. Here the data from the LIST Response cannot be integrated directly, because the input forms for the payment methods are described in HTML.

As a consequence there could be a translation on the client side from the HTML elements into native UI interaction elements. This would preserve the implement once principle, but requires a certain budget. Especially edge cases that require some additional JavaScript logic, such as interactive forms for installment plan selection are not straight-forward to translate.

Therefore, the idea of Half-Native is that you as a merchant developer prepare the "user interface snippets" that correspond to the HTML form snippets provided by the LIST Response in advance. In other words, you prepare all relevant input forms that may occur beforehand natively, e.g. in terms of the iOS or Android platform.

After your system issued a LIST Request the client will evaluate the response of the client. Then it only shows those natively prepared input forms that were selected by the Payment Gateway for this payment session.

When your customer entered the required payment data, the client typically submits it directly to the Payment Gateway via a CHARGE Request in the fashion of the Display Native Scenario. As a consequence there will be an immediate response and a Status Notification going to your server system.

A corresponding communication sequence will look like this:

Alternatively, the payment session could be initialized as Pure Native, and the CHARGE Request issued to your server systems first. This impacts your required PCI certification, though.

Separate Method Selection

Another use case for Half-Native integration is to split the method selection from the actual entering of the account data by the user, i.e. divide the common payment page into two separate steps.

In this case you could add some simple logic to show the first part of the payment page, consisting of radio buttons and the logos, and the second part of the payment page showing the logo and forms, of the previously selected payment method, with or without the possibility to still switch to another payment method.

To support this, OPG offers an easy way to store the user selection from the first part in the LIST Session object. This is especially relevant in case you want to render the second part as a Hosted Page because it will respect the selected method and show it as preselected (among the other methods).

Every method offered in a LIST Session has the attribute selected, and is also a resource with a separate endpoint. Its URL is given as the links.self attribute like this:

Example JSON Code
{
...,
  "code": "VISA",
  "selected": false,
  "links": {
    "self": "https://api.sandbox.oscato.com/api/lists/57a06162e4b0a803efa9e1d1l/VISA",
  ...
  }
...

If the user selects one method your system can issue a PUT or PATCH request to that resource to update its selected attribute like this:

Example Request

  • URL: https://api.sandbox.oscato.com/api/lists/57a06162e4b0a803efa9e1d1l/VISA
  • Method: PUT
  • Basic Authentication: Not required except for Native Scenarios

The selected status of all other methods in that LIST will become false as a consequence. So note that other attributes cannot be changed.

As an option, your system can use the URL of the corresponding LIST object to display it in a hosted fashion later (as the second part), and the selected method will be prechecked and expanded there.
Body Content
{
  "selected": true
}

Web Content Display

JSON Forms

For non-web clients (e.g. native mobile app, smart TV app, or a desktop-based CRM system) a JSON representation of input forms for payment methods and registered accounts is a better solution that enables you to build these forms natively without HTML rendering.

On Display and Pure Native integration scenarios the LIST request can be executed passing extra query parameters to return a JSON representation of the input fields instead of HTML snippets, so that such aforementioned non-web devices (not capable of HTML rendering) can still render the needed input forms.

When executing a LIST request (any variation, POST, GET or PUT), the requested URL can contain the parameter view, with options to enable or disable form representation methods.

For example, a LIST request (POST) could look like:

https://api.sandbox.oscato.com/api/lists?view=jsonForms,-htmlForms

With regards to the query parameters, the following must be respected:

  • If jsonForms is present, the JSON forms are enabled.
  • If -htmlForms is present, the HTML forms are not shown. That means: The attributes links.form and links.localizedForm are not present.
  • If there are conflicting or unknown arguments like view=jsonForms,-jsonForms or view=abc then the request will fail as invalid.
  • If there is any query parameter present other than view then it will be ignored.

If JSON forms are enabled (view=jsonForms) then the LIST response object will contain a form representation in JSON format. This means:

  • For each applicable method (network) there is a new attribute structure named localizedInputElements (not inside the links structure, but outside on the same level)
  • This structure is an array of objects, and each object represents one input field as follows:
    • name (mandatory): the name of the parameter represented by this input field (as used inside an account object in a consecutive CHARGE request)
    • label (mandatory): the localized human readable label that should be displayed with the input field
    • type (optional): represents the input type / restrictions that can be enforced by the client. The following types are allowed:
      • string (default): one line of text without special restrictions. Example: holder name
      • numeric: numbers from 0 to 9, space delimiters and dash ("-") are allowed. Example: card numbers
      • integer: only numbers from 0 to 9. Example: CVC
      • checkbox: values "true", "false" or non-existing.
      • select: a list of possible values is given in an additional options attribute (see below). Example: expiration dates.
    • options (optional, present for "select" types): an array of objects with attributes:
      • value (mandatory)
      • label (optional. If not present, value should be displayed to the user.)
  • If the form definition for a network is not present in OPG yet, an empty object will be returned.
Example of LIST response:
...,
{
  "code": "ONLINE_BANKING_CZ",
  "label": "Online Banking for Czech Republic",
  "method": "ONLINE_BANK_TRANSFER",
  "grouping": "ONLINE_BANK_TRANSFER",
  "registration": "NONE",
  "recurrence": "NONE",
  "redirect": true,
  "links": {
    "logo": "https://resources.sandbox.oscato.com/resource/network/DEMO_SK/cs_CZ/ONLINE_BANKING_CZ/logo.png",
    "self": "https://api.sandbox.oscato.com/pci/v1/5984364ccb425d1b77fc727dlijdpkm1bfr5malib51eacl3f9/ONLINE_BANKING_CZ",
    "lang": "https://resources.sandbox.oscato.com/resource/lang/DEMO_SK/cs_CZ/ONLINE_BANKING_CZ.properties",
    "operation": "https://api.sandbox.oscato.com/pci/v1/5984364ccb425d1b77fc727dlijdpkm1bfr5malib51eacl3f9/ONLINE_BANKING_CZ/charge",
    "validation": "https://api.sandbox.oscato.com/pci/v1/5984364ccb425d1b77fc727dlijdpkm1bfr5malib51eacl3f9/DEMO_SK/cs_CZ/ONLINE_BANKING_CZ/standard/validate"
  },
  "localizedInputElements": [
    {
      "name": "bic",
      "label": "Banka",
      "type": "select",
      "options": [
        {"value": "GIBACZPXXXX", "label": "?eská spo?itelna, a.s."},
        {"value": "FIOBCZPPXXX", "label": "Fio banka, a.s."},
        {"value": "KOMBCZPPXXX", "label": "Komercni banka, a.s."},
        {"value": "BREXCZPPXXX", "label": "mBank S.A., organiza?ní složka"},
        {"value": "RZBCCZPPXXX", "label": "Raiffeisenbank, a.s."},
        {"value": "ZUNOCZPPXXX", "label": "Zuno Bank AG"},
      ]
    }
  ],
  "button": "button.charge.label",
  "selected": false
},
...

JSON Forms

For non-web clients (e.g. native mobile app, smart TV app, or a desktop-based CRM system) a JSON representation of input forms for payment methods and registered accounts is a better solution that enables you to build these forms natively without HTML rendering.

On Display and Pure Native integration scenarios the LIST request can be executed passing extra query parameters to return a JSON representation of the input fields instead of HTML snippets, so that such aforementioned non-web devices (not capable of HTML rendering) can still render the needed input forms.

Please sign in to view further details of this article. Login

Web Content Display

Frontend Checkout

Web Content Display

Checkout Flow Overview

The OPG offers you greater flexibility throughout the whole checkout process. The diagram above gives you an overview of optile's Flexible Checkout Architecture. The checkout process starts in your shop and ends when you make a Charge and display the thank you page to you customer or when you dispatch the order and close the transaction with a defered charge. Here is the Full Flexible Checkout Architecture Diagram.

The checkout journey that you chose to present your customers, could take several forms:

  • Regular checkout with immediate charge - your customer arrives to the checkout page, via the regular web browser or via a remote checkout that is initiated by your Call Center, where the list of products to be purchased are displayed. The customer is then directed to the payment page. The payment page is rendered based on how you choose to handle optile's LIST Request, i.e., by either a simple or advanced integration scenarios with the OPG (for more infomation about Intergration Scenarios). On the payment page your customer enters their payment data and confirms the order. Once the customer confirms the order, the CHARGE takes place and they will be redirected the thank you page. You may choose to close the sale once you make the order ready for delivery as a defered charge.
     
  • Regular checkout with summary page  - your customer follows the same path as above, however, the customer is presented with a summary page after they ente their payment details. The summary page gives your customer the opportunity to review their order and check their delivery address and payment details before they confirm the purchase. Presenting the summary page requires a Delayed Payment Submisison (DPS) which involves caching sensitive data and involves some challenges. Your system can temporarily cache payment data via a PRESET Request. Once your customer confirms the order from the summary page, the CHARGE takes place and they will be redirected the thank you page. You may choose to close the sale once you make the order ready for delivery as a defered charge.
     
  • One Click Checkout for returning customers - You can speed up and improve the checkout experience for your return customers by directing these customers directly from the checkout page to the summary page. On the summary page you show them their registered address and payment details and then the customer just needs to confirm the order. In this process you can perform the Charge by skipping the payment page. Again, you close the sale once you make the order ready for delivery. To offer the One Click Checkout to your return customers you will need to provide your customers the option to register their account details on their initial purchase from your store.
  • Express Checkout for first-time customers -  On the checkout page you ask your customer which payment method they wish to use. If the customer chooses PayPal or Klarna the customer is then directed to  PayPal or Klarna to make the payment with their existing account. Once the customer confirms the payment details, the shipping address and payment details are sent to your shop and presented to the customer on a summary page for the customer to confirm the purchase. The Express Checkout would typically be used together with Delayed Payment Submisison (DPS).
The Interactive Checkout Flow Diagram

In the Interactive Checkout Flow Diagram, you can look at various comibations of optile's checkout flow paths. Take you time to become familiar with the check out options that are avaliable to you by clicking on the different checkout variations.

Click on this link to open the interactive diagram in a new tab. Please be patient when loading the diagram as it might take a while to load.

Web Content Display

Payment Page: LIST Request

Every (potential) payment checkout starts with a LIST Request. With this your system provides information about the purchase (especially payment amount), customer details and maybe some additional data. It authenticates by sending your optile OPG credentials via HTTP Basic Authorisation (encrypted through HTTPS of course). Therefore the LIST Request is always issued from your server-side systems, and never from a customer's browser.

A valid LIST Request creates a LIST object. It responds with the applicable payment methods (networks) for this checkout and can also be seen as a kind of payment session of the user in which he or she can do multiple CHARGE attempts.

A typical LIST Request looks like this:

  • URL: https://api.live.oscato.com/api/lists
  • Method: POST
  • Authentication:
    • Login Name: registered company code
    • Password: generated API token
  • transactionId is an alphanumeric identifier for this transaction assigned by you as a merchant.
  • country specifies which payment network selection (as previously configured in OPG) is requested. Typically it's supposed to be the origin of the customer. Country codes according to ISO 3166-1 alpha-2 are used.
  • integration defines which integration scenario the payment session is initialized for, the default value is DISPLAY_NATIVE. Valid values are: HOSTED, SELECTIVE_NATIVE, DISPLAY_NATIVE and PURE_NATIVE.
  • customer.number is an alphanumeric identifier of your customer assigned by you as a merchant.
  • payment.reference is the short text that the customers will see on their account statement.
  • style.client only for HOSTED integration scenario, if set to RESPONSIVE it will enable new version of payment page and return networks logo links for high resolution images (see also resolution property).
  • style.resolution is set to 2x to get high-resolution method logos in the response (64px height, recommended), 1x for legacy resolution (32px height).
  • callback.returnUrl is the URL the customer should be redirected to after the payment was successful, typically on the merchant's site.
  • callback.cancelUrl is where the customer should be redirected to in case he or she cancels on a redirect page (such as PayPal), or any payment attempt that was denied and is not recommended to retry (Interaction Code ABORT).

The full data model with all possible parameters can be found in our API Console.

Read about the reply in LIST Response.

Example LIST Request
{
  "transactionId": "tr101",
  "country": "DE",
  "integration": "HOSTED",
  "customer": {
    "number": "42",
    "email": "john.doe@example.com"
  },
  "payment": {
    "amount": 19.99,
    "currency": "EUR",
    "reference": "Shop 101/20-03-2017"
  },
  "style": {
    "client": "RESPONSIVE"
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
	"notificationUrl":"https://dev.oscato.com/shop/notify.html"
  } }

Specifying the Integration Scenario

You can specify the integration scenario in the LIST Request using the parameter integration. The selected scenario will impact the operation URLs in the response object. If there is no integration parameter specified, the list request will default to Display Native.

The following are valid parameters:

  • HOSTED (Hosted)
  • SELECTIVE_NATIVE (Selective Native)
  • DISPLAY_NATIVE (Display Native, default. Legacy value: NATIVE_WITHOUT_PCI)
  • PURE_NATIVE (Pure Native. Legacy value: NATIVE_WITH_PCI)
Example LIST Request with integration parameter
  • URL: https://api.live.oscato.com/api/lists
  • Method: POST
  • Authentication:
    • Login Name: registered company code
    • Password: generated API token
Duplicate Charges

As we saw, after a successful CHARGE is executed on a LIST object, the LIST will not be valid anymore. This means any other CHARGE on it will be declined with the Interaction Code ABORT and Reason DUPLICATE_OPERATION. This is to protect customers and merchants from accidentally executing duplicate payments.

In order to provide a good customer experience, however, you should detect that case (via Interaction Codes passed as GET query parameters) on the page the customer would be redirected to (indicated by the cancelUrl) and inform the customer that the payment has already took place, only the repetition was declined. Otherwise the customer may think the payment failed entirely.

Continue reading in the LIST Request Details.
Example LIST Request with Hosted Integration Scenario
 {
  "transactionId": "tr101",
  "country": "DE",
  "integration": "HOSTED",
  "customer": {
    "number": "42",
    "email": "john.doe@example.com"
  },
  "payment": {
    "amount": 19.99,
    "currency": "EUR",
    "reference": "Shop 101/20-03-2017"
  },
  "style": {
    "client": "RESPONSIVE"
  },
  "callback": {
     "returnUrl": "https://dev.oscato.com/shop/success.html",
     "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
     "notificationUrl":"https://dev.oscato.com/shop/notify.html"

  }
}
Modifying response with preselection parameter

With the preselection sub-parameters you can dynamically influence the LIST Response as follows.

  • deferral: enables Deferred Payments or Payouts
  • networks: Filters the response to:
    • REGISTERED: only accounts that were previously registered for the current customer
    • APPLICABLE: only networks that are to be entered by the customer, not registered accounts.
    • ANY (default): Both kinds
  • direction: Specifies the kind of transaction, namely:
    • CHARGE (default): A payment transaction with a subsequent CHARGE Request
    • PAYOUT: A Payout to the customer
Example
 {
...,
  "country": "DE",
  "preselection": {
    "deferral": "DEFERRED",
    "networks": "REGISTERED",
    "direction": "PAYOUT"
  },
  "customer": {
  ...

Payment Page: LIST Request

Every (potential) payment checkout starts with a LIST Request. With this your system provides information about the purchase (especially payment amount), customer details and maybe some additional data. It authenticates by sending your optile OPG credentials via HTTP Basic Authorisation (encrypted through HTTPS of course). Therefore the LIST Request is always issued from your server-side systems, and never from a customer's browser.

Please sign in to view further details of this article. Login

Web Content Display

Reusing a LIST Session

In several use cases there is no need to start a new LIST session if the current one is still valid. Furthermore, the OPG supports the update of parameters of a LIST session without need for reload.
New LIST Request vs. reading existing LIST

A valid LIST can be seen as payment session of the user. To enable payment conversion tracking through optile and profit from dynamic reactions of the payment page, we recommend not to issue LIST Requests "blindly" but use existing LIST Objects if possible.

The object is a resource hosted by OPG identified by the LIST's longId and can be requested any time again via HTTP GET like this:

https://api.live.oscato.com/api/lists/[longId of LIST]

A LIST object remains valid for executing charges until either

  • a successful or pending (!) CHARGE through this list was executed, or
  • 30 minutes have passed (this will also trigger a Status Notification), where the timer starts counting from 0 again with any CHARGE attempt.

After that the LIST object will become invalid for security reasons, that means no CHARGE will be possible anymore. In Display Native integrations a GET on an expired LIST resource will return an HTTP 404 (not found) error. In Pure Native integrations the object can be retrieved, but its Status Code will be expired.

This means for your implementation:

Use an existing LIST resource as long as it is valid. Especially if your customer reloads the payment page, do not issue a new LIST Request but re-use the existing one. Only this will enable proper conversion tracking on your payment checkout through optile. You can double check the validity through a GET request on the LIST resource (see above) and/or listen to "expired" notifications. Only if it has expired, issue a new LIST Request.

Updating a LIST Session

For some business cases it may be necessary to change the information provided in the initial LIST Request, for example if customers change the products in their shopping cart after they have been on the payment page already, but not completed the payment yet. It means that for the same "user session", an update of an existing LIST resource is required. For a new "user session", generate a new LIST as already covered earlier in this section.

LIST updates may lead to incorrectly charged amounts if your implementation is not accurate. Also, some payment networks may drop out of the LIST result when new information is given (e.g., if they only apply to a certain payment amount range). Therefore, the customer may not be able to complete the payment with an already selected network.

The update is performed REST-style by sending an HTTP PUT to an existing LIST resource. The data structures payment, products and customer can be replaced as a whole. Other mandatory fields still have to be provided but cannot be changed.

Example Request for LIST Session Update
  • URL: https://api.live.oscato.com/api/lists/ce3eec14-e186-4b7c-94a1-fde802412e69
  • Method: PUT
  • Authentication:
    • Login Name: DEMO
    • Password: BAtXa7yubR8ipuT

Note that LIST session updates can only be performed from the server side system ("backend") and it needs your payment authentication credentials. After performing a LIST update it may be necessary to reflect resulting changes in the customer client (e.g., browser). Therefore the LIST result should be read from the client again by passing it on from your server system, or by directly retrieving the LIST object from the Payment Gateway again, and showing the updated payment page. Also notice that the JSON structure is basically the same for a LIST request or update.

Example JSON Code
 {
    "transactionId": "tr101",
    "country": "DE",
    "customer": {
        "number": "42"
    },
    "payment": {
        "amount": 22.22,
        "currency": "EUR",
        "reference": "Shop 101/20-03-2017"
    }
}
Making a Method checked by default

A LIST also holds information about which of the contained Methods should be checked when the payment page is loaded. In the LIST Response, each object in networks.applicable and accounts, representing a payment method ("network"), has a boolean flag selected. If set to true this method should be displayed with a checked radio button and expanded form. optile's Hosted payment page and AJAX library respect this value.

You can modify the flag by sending a PUT request to the method resource. Its URL is given explicitly in the self attribute within the method object.

Example Request for Default Checking

  • URL: https://api.sandbox.oscato.com/api/lists/57bab64ee4b03ec79899332el/VISA
  • Method: PUT
  • Authentication: Not required (except for Pure Native integration)

As a consequence the selected property of all other methods in the list will become false. Note that other properties of a method cannot be changed through this API.

By default the selected attributes of all methods will be false, and we recommend to preselect the first method, as our AJAX library and Hosted Payment Page do.

Code
{
  "selected": true
}

Reusing a LIST Session

In several use cases there is no need to start a new LIST session if the current one is still valid. Furthermore, the OPG supports the update of parameters of a LIST session without need for reload.

Please sign in to view further details of this article. Login

Web Content Display

Extended LIST Request

In some cases it is necessary to provide further details about the customer and/or purchased products. Especially Invoice payments need addresses and products for billing. Most information can also be used for risk management purposes. If billing and shipping addresses are different, for example, some invoice providers may restrict the usage of invoice payment.

Currently OPG accepts details in the form laid out as in the right pane >>

Products

The given products will be shown to the customer in some networks, e.g. PayPal and Invoices.

product.amount reflects the price with respect to quantity. Therefore a quantity of 2 and amount of 25.00 means that a single product cost 12.50.

quantity defaults to 1.

Client Info

The parameter clientInfo is optional as is every sub-attribute within. However, if you provide any part of the object, but not userAgent or acceptHeader, defaults will be used for these attributes if empty, namely:

  • userAgent: Mozilla/5.0
  • acceptHeader: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8

These are widely accepted values. But just in case a PSP should use them for additional logic like risk management, we recommend to set these attributes to the real values from the customer's original HTTP request.

Customer

Note that any of the customer fields are optional, but either customer.number or customer.email have to be provided. This allows for basic identification that can be used by some providers for risk management purposes. We recommend to always provide customer.number, because some providers require this. So the risk is that if you don't send it and then change the provider it could suddenly break.

Phone numbers can be passed either by providing all three fields, countryCode, areaCode and subscriberNumber, or by providing a single unstructuredNumber.
You may provide an additional name structure in the billing section. But the general name defined as child of customer should be enough in typical cases.

customerScore is an optional rating of the customer's trustworthyness from 0 to 1000 (1000 is fully trusted) which can influence the employment of risk checks such as 3D Secure, the requirement for a verification code (CVV/CVC) for registered cards, and others in the future, if the provider supports it. The rating values can be customized, but in a standard configuration a value below 300 enforces a 3D Secure check, a value above 700 disables it, and values in between leave the decision to the provider in accordance to the agreed defaults. Currently this is only supported by WorldPay.

Extended LIST Request Example
 {
  "transactionId": "tr101",
  "country": "DE",
  "integration": "PURE_NATIVE",
  "payment": {
    "amount": 34.90,
    "currency": "EUR",
    "reference": "Shop 101/20-03-13"
  },
  "products": [{
    "code": "B003X6UEXQ",
    "name": "Tron Legacy BluRay",
    "quantity": 2,
    "amount": 25.00
  },{
    "code": "C003X6U523",
    "name": "The Lawnmower Man DVD",
    "quantity": 3,
    "amount": 9.90
  }],	
  "clientInfo": {
    "ip": "00.00.111.2",
    "ipv6": "0000:0000:0011:0011:1122:1122:0101:0101",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/54.0",
    "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8"
  },
  "customerScore": 250,
  "customer": {
    "number": "002345",
    "email": "john.doe@example.com",
    "birthday": "2001-12-31T00:00:00.000Z",
    "name": {
      "title": "Prof.",
      "firstName": "John",
      "middleName": "",
      "lastName": "Doe",
      "maidenName": ""
    },
    "addresses": {
      "billing": {
        "street": "Downing Street",
        "houseNumber": "10",
        "zip": "80333",
        "city": "München",
        "state": "Bayern",
        "country": "DE"
       },
      "shipping": {
        "name": {
          "firstName": "John",
          "lastName": "Doe"
        },			
        "street": "Baker Street",
        "houseNumber": "221b",
        "zip": "80333",
        "city": "München",
        "country": "DE"
      }
    },
    "phones": {
      "work": {
        "countryCode": "49",
        "areaCode": "89",
        "subscriberNumber": "106012011"
        },
      "company": {"unstructuredNumber": "(0)89 1060 120-00"},
      "home": {"unstructuredNumber": "089 5060 120-55"},
      "other": {
        "countryCode": "49",
        "areaCode": "8862",
        "subscriberNumber": "3765"
      },
      "mobile": {"unstructuredNumber": "0177 44004400"},
      "mobileSecondary": {"unstructuredNumber": "0151 88008800"},
      "fax": {"unstructuredNumber": "+49 (0)89 880088-00"}
    }
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "notificationUrl":"https://dev.oscato.com/web/acb123"
  }
}

Extended LIST Request

Please sign in to view further details of this article. Login

Web Content Display

More LIST Use Cases

Web Content Display

Delayed Payment Submission

If your customer should review and confirm their order on a separate summary page, then the customer's payment data (which was entered in a previous step) needs to be cached in the interim. Due to the sensitive nature of payment data and strict PCI DSS regulations, the issue of caching customer payment data must be handled carefully.

With Delayed Payment Submission optile does exactly that. Instead of a CHARGE request, your system can temporarily cache payment data via a PRESET request. This is different from a registration, as it is only temporarily stored to respect data privacy principles. After the customer has confirmed the order on the final summary page, your system can issue the corresponding CHARGE request (without payment data).

This will trigger either an immediate or deferred payment, depending on your configuration. In the case of a deferred payment, the payment would only be preauthorized and your system would send a final CLOSING request when the order is shipped and then the actual payment capture is triggered.

The following diagram illustrates the user journey (on the left) and how it relates to OPG API calls (on the right):

Payment Account Validation

As soon as the customer submits their payment account data to the gateway (PRESET call) it can be validated, not only for formal correctness, but also for account existence, funds availability, or additional risk checks. This way the shop can give immediate feedback to the customer in case something is wrong, and directly present alternative payment options to minimize user drop outs.

This is configurable through the backend, so please contact us regarding this. The options are:

  • NONE: No check will be executed.
  • VALIDATION (default): An optile-internal check on formal validity of the account number will be executed.
  • PROVIDER_CHECK: The internal verification (see above) will be executed first. If this is positive, a check with the provider will be executed that does not reserve the funds, if it's available. For card providers this means a zero value authentication, for other methods it can mean a dedicated risk check with customer data. If no such provider check is available it will not be executed and the transaction will be processed as usual.
  • PREAUTHORIZATION: The internal verification (see above) will be executed first. If this is positive, the corresponding funds will be reserved (preauthorized) if the method and provider allows this. If a reservation is not available, there will be a fallback to the non-reserving provider check explained above. Again, if this is not available either, the transaction will be processed as usual.

LIST Request

As illustrated in the delayed payment submission diagram, the first step in the process for a delayed payment submission is to submit a LIST Request. For Delayed Payment Submission an extra LIST parameter is required, namely the optional Boolean value presetFirst. If this is set to true optile OPG will know that the payment submission should be preset as opposed to being charged directly. Also a summaryUrl must be provided in the callback object if presetFirst is set to true. This way optile OPG can direct the customer to the desired summary page after the PRESET.

Delayed Payment Submission works with all Integration Scenarios. After the LIST response is returned the standard approach for rendering the payment methods should be followed, for example Native Integration, Selective Native, or it is rendered by the AJAX library.

LIST Request with presetFirst and summaryUrl
{
  "transactionId": "tr101",
  "integration": "SELECTIVE_NATIVE",
  "country": "DE",
  "presetFirst": true,
  "customer": {
    "number": "42",
    "email": "john.doe@example.com"
  },
  "payment": {
    "amount": 19.99,
    "currency": "EUR",
    "reference": "Shop 101/20-03-2016"
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "summaryUrl": "https://dev.oscato.com/shop/success.html",
    "notificationUrl": "https://dev.oscato.com/shop/notify.html"
  }
}

PRESET Request

When the customer enters their details on the payment page and makes a submission, there should be a PRESET request (to the operation URL) using the customer's data.

In all integration scenarios except Pure Native this will go directly from the customer's client to the OPG. It should contain the account data structure in analogy to the CHARGE request.

The AJAX library will already handle this correctly on button click.

For a Selective Native integration without the AJAX library the inter-frame communication needs to be triggered as described there, and an operation_response_event will sent to reflect the server response.

PRESET Request
 {
  "account": {
    "holderName": "test",
    "number": "4111111111111111",
    "expiryMonth": "12",
    "verificationCode": "333",
    "expiryYear": "18"
  }
}

The response of a successful PRESET call will indicate that the customer should be redirected, namely to the summary page URL that was given in the corresponding LIST request. Again, the AJAX library will hande this. When implementing a Hosted or AJAX-dependent integration scenario, you might want to also receive in the PRESET response a full masked account data to show your customer which payment card has been used. In these cases, a simple GET on the LIST session can be done (GET on its self link), it will respond the current session status and the preset account.

The operation URL of the returned object is where the subsequent CHARGE should be going to, see below.

Since the PRESET step also performs the configured validations if available (see above) the transaction could also be declined at this stage. A provider may, for example, decline to offer Invoice payments for this customer. This will be indicated by the Interaction Codes.

In most cases the customer should then be returned to the payment page, so that the existing LIST resource is reloaded and the remaining payment options are presented again. In this example, Invoice may have been removed from the list, but the customer can still select another, more secure method.

PRESET Response (Pure Native)
 {
  "links": {
    "operation": "https://api.sandbox.oscato.net/api/lists/abc123abc123abc123/charge"
  },
  "resultInfo": "Network and account are preset",
  "status": {
  "code": "preset",
  "reason": "preset"
  },
  "redirect": {
    "url": "https://dev.oscato.com/shop/success.html",
    "method": "GET",
    "parameters": [
      {"name": "shortId","value": "06598-63085"},
      {"name": "interactionReason","value": "OK"},
      {"name": "resultCode","value": "00000.11.000"},
      {"name": "longId","value": "58454da9e4b0a473f4675a96c"},
      {"name": "transactionId","value": "tr10687"},
      {"name": "interactionCode","value": "PROCEED"}
    ],
  },
  "network": "VISA",
  "maskedAccount": {
    "displayLabel": "41 *** 1111 12 | 18",
    "holderName": "test",
    "number": "41 *** 1111",
    "expiryMonth": 12,
    "expiryYear": 18
  },
  "interaction": {
  "code": "PROCEED",
  "reason": "OK"
  },
  "resultCode": "00000.11.000",
  "returnCode": {
    "name": "OK",
    "source": "GATEWAY"
  },
  "identification": {
  "longId": "abcd1234abc123",
  "shortId": "06598-63085",
  "transactionId": "tr101"
  },
  "timestamp": "2016-12-05T11:21:13.089+0000"
}

CHARGE Request

At this stage of the process the customer is now on the summary page that is generated by your shop system. Typically, this page would ask the customer to confirm the payment based on the summary presented. If the customer agrees, your server-side system should then make a CHARGE request using the operation URL returned in the PRESET response.

It looks like this: https://api.sandbox.oscato.com/api/lists/{LIST-longId}/charge

The ID to be referenced in this CHARGE URL is that of the LIST, not the PRESET resource.

As the data has already been preset on the system, no account information needs to be provided in the CHARGE Request body. In fact, only an empty JSON body {}  is provided as the request. This is also the reason why the CHARGE can (and should) go through your server-side system. There is no sensitive payment data present here.

After the CHARGE call your system should redirect the customer to the URL given in the response as redirect.url. In the success case this will be the original success URL as specified in the LIST request (the "Thank you" page).

CHARGE Response
{
  "links": {
    "payout": "https://api.sandbox.oscato.net/api/charges/58454db9e4b0a473f4675a97c/payout",
    "self": "https://api.sandbox..oscato.net/api/charges/58454db9e4b0a473f4675a97c"
  },
  "timestamp": "2016-12-05T11:21:29.729+0000",
  "operation": "CHARGE",
  "resultCode": "00000.TESTPSP.000",
  "resultInfo": "Approved",
  "pspCode": "TESTPSP",
  "returnCode": {
    "name": "OK",
    "source": "PSP"
  },
  "status": {
    "code": "charged",
    "reason": "debited"
  },
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "clearing": {
    "amount": 19.99,
    "currency": "EUR"
  },
  "identification": {
    "longId": "58454db9e4b0a473f4675a97c",
    "shortId": "15043-34925",
    "transactionId": "tr10687",
    "pspId": "VISA.DEBIT.1480889314499"
  },
  "redirect": {
    "url": "https://dev.oscato.com/shop/success.html",
    "method": "GET",
.....

Delayed Payment Submission

If your customer should review and confirm their order on a separate summary page, then the customer's payment data (which was entered in a previous step) needs to be cached in the interim. Due to the sensitive nature of payment data and strict PCI DSS regulations, the issue of caching customer payment data must be handled carefully.

With Delayed Payment Submission optile does exactly that. Instead of a CHARGE request, your system can temporarily cache payment data via a PRESET request. This is different from a registration, as it is only temporarily stored to respect data privacy principles. After the customer has confirmed the order on the final summary page, your system can issue the corresponding CHARGE request (without payment data).

This will trigger either an immediate or deferred payment, depending on your configuration. In the case of a deferred payment, the payment would only be preauthorized and your system would send a final CLOSING request when the order is shipped and then the actual payment capture is triggered.

Please sign in to view further details of this article. Login

Web Content Display

Payment Account Registration

At the time of the (initial) checkout, payment accounts (e.g., cards) can be stored with the used payment provider for future re-use (typically with provider tokens which will be managed by optile). At the same time this sensitive data will be stored (in a safe PCI compliant way) within the Payment Gateway to allow provider switching and therefore make you more independent from the individual payment providers, see Secure Storage.

We can distiguish between two kinds of registration: regular and recurring.

Regular Account Registration

In this case, if customers return to your shop, they will be presented with their previously registered payment accounts, so they do not need to re-enter all their information again. This can increase conversion especially with credit and debit cards or SEPA direct debit bank accounts. For credit cards only the verification code (CVV, CVC, etc.) still need to be entered by the customer, as per PCI DSS this it is not allowed to be stored (if the payment provider in the background accepts this, as most acquirer interfaces do, this can also be omitted by using the Dynamic Verification Code feature).

Recurring Registration

This kind of registration can be used to trigger Recurring Charges from your backend without customer interaction. This feature has to be supported by the Payment Service Provider and in any case it does not require the verification code anymore for subsequent charges.

Payment page with a registered account (regular)

Customer Agreement on Payment Page

Both kinds of registrations can be enabled by configuration. Since they need the agreement of the customer there should be corresponding checkboxes in the payment page. If registration was enabled on optile side, you just start a payment session with a regular LIST Request. In AJAX and Hosted integration scenarios the payment page will then be rendered automatically and the CHARGE Request submitted correctly, so you won't need the following information.

If your system evaluates the LIST Response itself, there will be two attributes present for each network: registration and recurrence, which correspond to the two registration types.

These attributes can have the following values, depending on the configuration:

  • NONE No checkbox should be displayed, the network is not registered
  • OPTIONAL Checkbox should be displayed and can be checked by the user
  • OPTIONAL_PRESELECTED Same as OPTIONAL, but checkbox should be pre-checked
  • FORCED No checkbox should be displayed, but the account is registered anyway
  • FORCED_DISPLAYED Same as FORCED, but a non-clickable and pre-checked checkbox should be displayed

Checkbox Rendering

In the OPTIONAL case you could include an additional checkbox next to the network form like this in the HTML source:

<input type="checkbox" id="allowRecurrenceVISA" name="allowRecurrence" value="true">
<label for="allowRecurrenceVISA">I authorize recurring charges on my account</label>

In the FORCED case you could include an additional hidden value as follows, if you have a Display Native integration and need to pass the parameter directly from the client to OPG:

<input type="hidden" name="autoRegistration" value="true">

As a result the checkboxes should look similar as displayed on the right. Note the checkboxes need to be present for each payment network seperately, because some networks do not support account registration and/or recurring charges.

LIST response with registration checkbox attributes

...,
{
  "method":"CREDIT_CARD",
  "registration":"FORCED",
  "code":"VISA",
  "label":"Visa",
  "recurrence":"FORCED_DISPLAYED",
  "links":{
    "logo":"https://api.live.oscato.com/resource/network/DEMO/de_DE/VISA/logo.gif",
    "operation":"https://api.live.oscato.com/api/lists/2885c861-fae4-4fc1-add4-a856c1012e21/VISA/charge",
    "form":"https://api.live.oscato.com/resource/form/VISA/standard.html",
    "validation":"https://api.live.oscato.com/api/pci/2885c861-fae4-4fc1-add4-a856c1012e21/DEMO/de_DE/VISA/validate",
    "localizedForm":"https://api.live.oscato.com/resource/form/DEMO/de_DE/VISA/standard.html",
    "lang":"https://api.live.oscato.com/resource/lang/DEMO/de_DE/VISA.properties"
  }
},
...

Payment page with registration checkboxes

Submitting the CHARGE

When the customer submits the payment data, the information which of those checkboxes has been checked has to be passed in the CHARGE Request. This is done through the parameters autoRegistration and allowRecurrence, which can have the values true or false (default), see example.

Again, AJAX and Hosted integration scenarios already do this for you.

CHARGE request with registration flags
{
  "account": {
    "holderName": "Walter Smith",
    "number": "4111111111111111",
    "verificationCode": "123",
    "expiryMonth": "2",
    "expiryYear": "2017"
  },
  "autoRegistration": true,
  "allowRecurrence": true
}

Receiving Registration Credentials

A CHARGE request like this will process the initial payment as usual. If the customer has not been registered yet, they will be registered at this stage together with the payment account. As a consequence the following Status Notification will be sent:

  • Concerning entity = customer: This will be sent only once to your system with both attributes, customerRegistrationPassword and customerRegistrationId. These values should be stored on your side because they will enable you to use the payment accounts of this customer from within the Secure Storage again later.
  • Concerning entity = account: This will contain payment network and accountRegistrationId which we will see again when manipulating individual registered payment accounts (as opposed to the whole customer registration). However, you usually should not store this, because you will receive and use these IDs implicitly in the context of the use cases such as Account Update and Registration Page or Setting a Preferred Payment Account.
  • Concerning entity = payment: This is the normal notification that only contains the customerRegistrationId which your system will receive for any payment of a registered customer.
For security reasons you will not be able to retrieve the full payment account data again. You can only see a masked representation of the data (e.g. 41** **** **** 1111), and you will be able to trigger subsequent charges only to your benefit. This minimizes risk of abuse through third parties.

Using a Regular Account Registration

If you enabled regular account registration (autoRegistration flag), the next time the customer does a checkout, you can submit the customerRegistrationId and -password with the next LIST Request as shown on the right (see customer.registration).

Using a Recurring Registration

If the initial CHARGE Request enabled a recurring registration (allowRecurrence flag) you will be able to trigger subsequent charges from the backend (i.e., without further customer interaction) using the customerRegistrationId and -password. Please continue with reading Recurring Charges.
LIST request for a registered customer

{
  "transactionId": "tr101",
  "country": "DE",
  "customer": {
    "number": "42",
      "email": "john.doe@example.com",
      "registration": {
        "id": "555dd649e4b086337cd4d18dq",
        "password": "h5dhgn7gd3bhlkwykxgnhrd2346nm0ew6d"
      }
  },
  "payment": {
    "amount": 19.99,
    "currency": "EUR",
    "reference": "Shop 101/20-03-2015"
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "notificationUrl":"https://dev.oscato.com/shop/notify.html"
  }
}

As a result you will get back not only networks.applicable in the LIST response, but also a list of accounts, which represent the previously registered payment accounts. This contains only regular account registrations, not accounts that were (only) registered for recurring.

These payment accounts should be displayed above the selection of payment methods. The response will provide information such as a localizedForm and displayLabel to do this in the regular fashion.

LIST response with account list
{
  ...
  "timestamp": "2015-03-21T12:57:55.762+0000",
  "operation": "LIST",
  "resultCode": "00000.11.000",
  "resultInfo": "5 applicable and 1 registered networks are found",
  ...
  "accounts": [{
     "links": {
       "operation": "https://api.sandbox.oscato.com/api/lists/555dd651e4b088681fe/accounts/555dd649e4b086337c/charge",
       "logo": "https://resources.sandbox.oscato.com/resource/network/ABC123/de_DE/VISA/logo.png",
       "form": "https://resources.sandbox.oscato.com/resource/form/VISA/registered.html",
       "localizedForm": "https://resources.sandbox.oscato.com/resource/form/ABC123/de_DE/VISA/registered.html",
       "lang": "https://resources.sandbox.oscato.com/resource/lang/ABC123/de_DE/VISA.properties"
     },
     "code": "VISA",
     "label": "VISA",
     "maskedAccount": {
       "displayLabel": "41 *** 1111    02 | 2017",
       "holderName": "Martin Tester",
       "number": "41 *** 1111",
       "expiryMonth": 2,
       "expiryYear": 2017
     }}
  ],
  "networks": {
    "applicable": [{
        "code": "VISA",
         ... }]
  }
}	

Payment Account Registration

At the time of the (initial) checkout, payment accounts (e.g., cards) can be stored with the used payment provider for future re-use (typically with provider tokens which will be managed by optile). At the same time this sensitive data will be stored (in a safe PCI compliant way) within the Payment Gateway to allow provider switching and therefore make you more independent from the individual payment providers, see Secure Storage.

Please sign in to view further details of this article. Login

Web Content Display

Account Update and Registration Page

Updating and Registering Payment Accounts is a LIST Request feature that allows customers to manage payment data associated with their accounts. The feature is initiated by the merchants on their backend and it allows the customer more control over their saved payment methods.

This functionality will allow the customer to:

  • Update registered accounts (expiration date of credit and debit cards)
  • Delete registered accounts (except the last recurring registration)
  • Register new payment accounts without first making a payment
  • Set preferred payment account (separate documentation)
The request functions in a similar fashion to the LIST Request with the following important differences.
  • A property updateOnly, which exists at the root level, must be set to true.
  • When updating a particular customer's payment methods, the customer's registration details must be included to identify the customer in question.

On the right pane is a sample LIST Request with updateOnly specified.

  • URL: https://api.sandbox.oscato.com/api/lists or https://api.live.oscato.com/api/lists
  • Method: POST
  • Authentication: Merchant Code and Token are needed
Example of Update Request
 {
  "transactionId": "tr1068735466d34",
  "country": "DE",
  "updateOnly": true,
  "customer": {
    "number": "4278",
    "email": "john.doe@example.com",
    "registration": {
      "id": "584578ebe4b0583916a67e6ee",
      "password": "UbHkTMmYhU1byjDe"
    }
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "summaryUrl": "https://dev.oscato.com/shop/success.html",
    "notificationUrl":"https://dev.oscato.com/shop/notify.html"
  }
}

Compared to a normal LIST Response there are the following differences:

Registered Accounts: Only the accounts that are allowed to be updated will be returned. If the account is not updatable it will not be shown. In the case that the payment account is updatable the operationUrl returned in the LIST Response points to an "update" instead of "charge" endpoint (for backwards compatibility with the existing integrations), e.g., "operation": "https://api.sandbox.oscato.com/pci/v1/5832ec78e4b0b0d86234c04bl/accounts/5832ebe41652164c14b86719a/update"

The associated formUrl / localizedFormUrl points to a form snippet with an expiration date and verification code, or there will be equivalent iFrame links for Selective Native.

Applicable Networks: Only payment networks with standalone-registration capability will be shown. Their operationUrl points to a "register" instead of "charge" endpoint, e.g., https://api.sandbox.oscato.com/pci/v1/5832ec78e4b0b0d86234c04bl/SEPADD/register

In any case there is a new attribute operationType in the top level of the response object, so that the client can detect that this is an Account Update Request and then handle any desired follow-on action such as displaying delete links for saved accounts.

The possible values of the operationType property are:

  • CHARGE
  • PRESET
  • PAYOUT
  • UPDATE
Below is a snippet from the LIST Response:
 {
  "links": {
    "self": "https://api.sandbox.oscato.com/pci/v1/588f0d4d16526507caceb575lbi1tm58fp1vt9asq425f3u9i3",
    "customer": "https://api.sandbox.oscato.com/api/customers/5889b7ab1652e1e7030f7ae8u"
  },
  "timestamp": "2017-01-30T09:54:21.835+0000",
  "operation": "LIST",
  "resultCode": "00000.11.000",
  "resultInfo": "4 applicable and 5 registered networks are found",
  "returnCode": {
    "name": "OK",
    "source": "GATEWAY"
  },
  "status": {
    "code": "listed",
    "reason": "listed"
  },
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "identification": {
    "longId": "588f0d4d16526507caceb575lbi1tm58fp1vt9asq425f3u9i3",
    "shortId": "10055-11601",
    "transactionId": "tr10687"
  },
  "accounts": [
    {
      "links": {
        "form": "https://resources.sandbox.oscato.com/resource/form/MASTERCARD/update.html",
        "logo": "https://resources.sandbox.oscato.com/resource/network/ABC123/de_DE/MASTERCARD/logo.png",
        "self": "https://api.sandbox.oscato.com/pci/v1/588f0d4d16526507caceb575lbi1tm58fp1vt9asq425f3u9i3/accounts/5889ce431652e1e7030f7b45a",
        "lang": "https://resources.sandbox.oscato.com/resource/lang/ABC123/de_DE/MASTERCARD.properties",
        "operation": "https://api.sandbox.oscato.com/pci/v1/588f0d4d16526507caceb575lbi1tm58fp1vt9asq425f3u9i3/accounts/5889ce431652e1e7030f7b45a/update",
        "localizedForm": "https://resources.sandbox.oscato.com/resource/form/ABC123/DE/de_DE/MASTERCARD/update.html",
        "validation": "https://api.sandbox.oscato.com/pci/v1/588f0d4d16526507caceb575lbi1tm58fp1vt9asq425f3u9i3/ABC123/de_DE/MASTERCARD/update/validate"
      },
      "code": "MASTERCARD",
      "label": "MasterCard",
      "maskedAccount": {
        "displayLabel": "51 *** 5100    03 | 2019",
        "holderName": "xcvbxcv",
        "number": "51 *** 5100",
        "expiryMonth": 3,
        "expiryYear": 2019
      },
      "lastSuccessfulChargeAt": "2017-01-26T11:59:59.135+0000",
      "selected": false
    }
    .....
   ]
   "networks": {
     "applicable": [{
       "code": "PAYPAL",
       "label": "PayPal",
       "method": "WALLET",
       "grouping": "WALLET",
       "registration": "OPTIONAL",
       "recurrence": "NONE",
       "redirect": true,
       "links": {
         "form": "https://resources.sandbox.oscato.com/resource/form/PAYPAL/standard.html",
         "logo": "https://resources.sandbox.oscato.com/resource/network/ABC123/de_DE/PAYPAL/logo.png",
         "self": "https://api.sandbox.oscato.com/pci/v1/588f117e16522490c20d0aaflnmhcm4cl9870ebtm1no90tsuv/PAYPAL",
         "lang": "https://resources.sandbox.oscato.com/resource/lang/ABC123/de_DE/PAYPAL.properties",
         "operation": "https://api.sandbox.oscato.com/pci/v1/588f117e16522490c20d0aaflnmhcm4cl9870ebtm1no90tsuv/PAYPAL/register",
         "localizedForm": "https://resources.sandbox.oscato.com/resource/form/ABC123/DE/de_DE/PAYPAL/standard.html",
         "validation": "https://api.sandbox.oscato.com/pci/v1/588f117e16522490c20d0aaflnmhcm4cl9870ebtm1no90tsuv/ABC123/de_DE/PAYPAL/standard/validate"
      },
      "button": "button.update.label",
      "selected": false
     },
    ....
   ]
 },
 "operationType": "UPDATE"
}

accounts are the saved payment accounts for the customer in question and networks.applicable are the payment methods available for this merchant configuration.
Integration Examples

For illustration of the Update LIST process the examples are split into different documents based on the integration type applicable.

  • Native integration uses the concept of a localised form to display the data.
  • Selective Native integrations will retrieve and display an iFrame instead of a localized form but the approach will be similar.
  • Hosted Integration will handle the Update LIST on your behalf and is the easiest to integrate with but it offers the least control.
Set Preferred Payment Account

In the context of an Update LIST the customer can also make one of his registered accounts the preferred one to use in the future, see Set preferred payment account.

Account Update and Registration Page - Native Integration

Native integration requires additional steps to update a LIST.  Below you will learn how to:

  • Register a new payment method for an existing customer
  • Update an existing registered payment method
  • Delete an existing registered network
Register a new payment method for an existing customer

Please follow the code examples on the right pane.

Step 1. Make the LIST Request passing the parameters updateOnly = true and account registration (id and password) object.

Example LIST Request
 {
  "transactionId": "tr1068735466d37",
  "country": "DE",
  "updateOnly": true,
  "customer": {
    "number": "4278",
    "email": "test.Customer@optile.net",
    "registration": {
      "id": "584578ebe4b0583916a67e6eu",
      "password": "UbHkTMmYhU1byjD5"
    }
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "summaryUrl": "https://dev.oscato.com/shop/success.html",
    "notificationUrl":"https://dev.oscato.com/shop/notify.html"
  }
}

Step 2. Read the operation links from the applicable networks section of the response.
The operation link is the location of the POST Request that will register the new method. For convenience a link to a localised form snippet will be provided. This snippet can be presented to the customer so they can input their new details.

Example LIST Response

  "networks": {
  "applicable": [{
    "code": "MASTERCARD",
    "label": "MasterCard",
    "method": "CREDIT_CARD",
    "grouping": "CREDIT_CARD",
    "registration": "OPTIONAL",
    "recurrence": "NONE",
    "redirect": false,
    "links": {
      ...
      "operation":"https://api.sandbox.oscato.com/pci/v1/58469340e4bae1b32d2fd83fl1r6ee4de1c0srn7loiieafh2e/MASTERCARD/register",
      "localizedForm":"https://resources.sandbox.oscato.com/resource/form/ABC123/DE/de_DE/MASTERCARD/update.html",
...

Step 3. After the customer enters the details of the new card. Make a POST Request to the operation URL above and register a new MasterCard to the customer based on the new details provided.


{
  "account": {
  "holderName": "test name",
  "number": "5555555555554444",
  "expiryMonth": "12",
  "verificationCode": "333",
  "expiryYear": "18"
  }
}

After the request a response similar to below will be shown


{
  "resultInfo": "Approved",
  "interaction": {
   "code": "RELOAD",
   "reason": "UPDATED"
  }
}

If another LIST Request is repeated, with the same body as in step 1, then the newly registered card will be visible in the accounts and can be presented to the customer on the front end. The Hosted and AJAX integrations will do this automatically.


....
"resultInfo": "3 applicable and 4 registered networks are found",
....
"accounts": [
  {
   "links": {
    ....
   },
"code": "MASTERCARD",
"label": "MasterCard",
"maskedAccount": {
"displayLabel": "55 *** 4444 12 | 18",
"holderName": "test",
"number": "55 *** 4444",
"expiryMonth": 12,
"expiryYear": 18
},
....

 

Register a new payment method for a new customer

Please follow the code examples on the right pane.

Step 1. Make the LIST Request passing the parameters updateOnly = true but this time without passing an account registration object.

Example LIST Request
 {
  "transactionId": "tr1068735466d37",
  "country": "DE",
  "updateOnly": true,
  "customer": {
    "number": "4278",
    "email": "test.Customer@optile.net",
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "summaryUrl": "https://dev.oscato.com/shop/success.html",
    "notificationUrl":"https://dev.oscato.com/shop/notify.html"
  }
}
Step 2. and forward: follow exactly the same steps as for a Registration of New Payment Method for Existing Customer explained earlier.
Update an existing registered payment method

In this example the expiration month and year of the registered card, in the example above, is updated.

Step 1. As always the process will start with a LIST Request. This is the same as the LIST Request in the above example and it is included here for completeness.

{
    "transactionId": "tr1068735466d37",
    "country": "DE",
    "updateOnly": true,
    "customer": {
        "number": "4278",
        "email": "test.Customer@optile.net",
        "registration": {
           "id": "584578ebe4b0583916a67e6eu",
           "password": "UbHkTMmYhU1byjD5"
          }
         },
      "callback": {
        "returnUrl": "http://somesite.com/success.html",
        "cancelUrl": "http://somesite.com/cancel.html",
        "notificationUrl": "http://somesite.com/notification.html"
    }
}

Step 2. To update the card details, select the relevant registered account from the accounts section of the LIST Response. The localized form is presented to the customer so that they can update their registered accounts details.

Note: We are querying the existing accounts here and not the applicable networks. Applicable networks are relevant for registering new accounts. Updates to card details happen at an account level.

....
"accounts":
 {
  "links":
  {
   ....
   "operation": "https://api.sandbox.oscato.com/pci/v1/5846a5f6e4b0e1b32   d2fd85alnocmstnce3hnpc030kc6n72gp/accounts/5846a0bce4b02797fa4af8b1a/   update",
   "localizedForm": "https://resources.sandbox.oscato.com/resource/form/   VINCEMCCGMBH/DE/de_DE/MASTERCARD/update.html"
}
"code": "MASTERCARD",
"label": "MasterCard",
"maskedAccount": {
   "displayLabel": "55 *** 4444 12 | 18",
   "holderName": "test",
   "number": "55 *** 4444",
   "expiryMonth": 12,
   "expiryYear": 18
   }

Step 3. Provide the localised form to the customer and call the relevant operation URL (see highlighted above) from the LIST Response. The customer then submits their updated data (See the JSON on the right pane updating the expiry date).


{
   "account": {
    "holderName": "test",
    "number": "5555555555554444",
    "expiryMonth": "3",
    "verificationCode": "333",
    "expiryYear": "20"
    }
}
This will return the following JSON

{
  "resultInfo": "Approved",
  "interaction": {
   "code": "RELOAD",
   "reason": "UPDATED"
  }
}
Doing another LIST Request for the same customer will show that the expiry date has changed

 


....
"accounts": [
{
"links": {
   ....
 },
"code": "MASTERCARD",
"label": "MasterCard",
"maskedAccount": {
"displayLabel": "55 *** 4444 03 | 20",
"holderName": "test",
"number": "55 *** 4444",
"expiryMonth": 3,
"expiryYear": 20
},
....

 

Delete an existing registered network

An existing registered payment method can be deleted provided that it is not currently being used in a recurring payment subscription.

This example closely follows the above example, except that a DELETE request is called instead of a POST and the address is slightly different (i.e., it does not contain the updated part). For completeness the relevant JSON snippets are given although they will be the same as the snippets above in some cases.

Step 1. Make a LIST Request

{
    "transactionId": "tr1068735466d37",
    "country": "DE",
    "updateOnly": true,
    "customer": {
        "number": "4278",
        "email": "test.Customer@optile.net",
        "registration": {
           "id": "584578ebe4b0583916a67e6eu",
           "password": "UbHkTMmYhU1byjD5"
          }
         },
      "callback": {
        "returnUrl": "http://somesite.com/success.html",
        "cancelUrl": "http://somesite.com/cancel.html",
        "notificationUrl": "http://somesite.com/notification.html"
    }
}

 

Step 2. In the corresponding LIST Response select the self link of the payment method to be removed. 

....
"accounts":
{
 "links":
  {
   ....
   "self": "https://api.sandbox.oscato.com/pci/v1/588f1b3016526507caceb58cltd243ska6ht4lopvqgardruh4/MASTERCARD
   ....
  }
"code": "MASTERCARD",
"label": "MasterCard",
"maskedAccount":
{
"displayLabel": "55 *** 4444 12 | 18",
"holderName": "test",
"number": "55 *** 4444",
"expiryMonth": 3,
"expiryYear":20
}

 

Step 3. Make a DELETE request on the self link of the account to remove. 

After the DELETE method is called a response stating the de-registration will be received

{
  "resultInfo": "Account registration type is updated",
   "interaction": {
   "code": "RELOAD",
   "reason": "UPDATED"
  }
}

 

Your servers will additionally receive a notification confirming that entity = account has accountStatus = deregistered.

A quick LIST Request will confirm that the registered payment method is removed from the accounts object.


"resultInfo": "3 applicable and 3 registered networks are found",

 

Account Update and Registration Page - Selective Native Integration

Selective Native integrations retrieve and display an iFrame instead of a localized form but the approach is similar to Native integration. You will need to sign to read how the Selective Native integration scenario deals with the Update LIST.

For details on handling this iFrame see the Selective Native documentation.


{
    "transactionId": "tr1068735466d37",
    "country": "DE",
    "integration": "SELECTIVE_NATIVE",
    "updateOnly": true,
    "customer": {
        "number": "4278",
        "email": "test.Customer@optile.net",
        "registration": {
           "id": "584578ebe4b0583916a67e6eu",
           "password": "UbHkTMmYhU1byjD5"
          }
         },
      "callback": {
        "returnUrl": "http://somesite.com/success.html",
        "cancelUrl": "http://somesite.com/cancel.html",
        "notificationUrl": "http://somesite.com/notification.html"
    }
}

The iFrame to display will be presented in LIST Response for each 


"accounts": [
  {
  "links": {
   ....
   "iFrame": "https://resources.sandbox.oscato.com/paymentpage/iframe.html?listId=585914bc1652e8259d578c09lb74jsr4lfom4irgg7d73qb5pt&accountId=5857c6c91652031c165ec19fa",
   "logo": "https://resources.sandbox.oscato.com/resource/network/VINCEMCCGMBH/de_DE/MASTERCARD/logo.png",
   "self": "https://api.sandbox.oscato.com/pci/v1/585914bc1652e8259d578c09lb74jsr4lfom4irgg7d73qb5pt/accounts/5857c6c91652031c165ec19fa",
....

 

To delete an account in a selective native implementation a HttpDelete request can be made to the self url from the frontend.

For more detailed information please see the Native Integration example.
Selective native integration functions in a similar fashion to the examples in Native Integration but instead of displaying a localised form, the merchant will present the customer with an iframe where card details can be edited.
Account Update and Registration Page - Hosted Integration

Hosted integration will handle the Update LIST on your behalf and is the easiest  way to integrate but it offers the least control. You will need to sign to read how the Hosted integration scenario deals with the Update LIST.


{
    "transactionId": "tr1068735466d34",
    "country": "IE",
    "integration":"HOSTED",
    "updateOnly": true,
    "customer": {
        "number": "4278",
        "email": "test.Customer@optile.net",
        "registration": {
           "id": "584578ebe4b0583916a67e6eu",
           "password": "UbHkTMmYhU1byjD5"
          }
         },
      "callback": {
        "returnUrl": "http://somesite.com/success.html",
        "cancelUrl": "http://somesite.com/cancel.html",
        "notificationUrl": "http://somesite.com/notification.html"
    }
}

 

The LIST Response will then include a redirect URL where all payment methods can be managed. See the screenshots below.

 


"redirect": {
   "url": "https://resources.lsandbox.oscato.com/paymentpage/checkout-auto.html?listId=58491623e4b086f92f55dc29lk9pdi4hdnpqq2htdn651rucd2&liveValidation=true&smartSwitch=true",
   "method": "GET",
   "suppressIFrame": false
   },
"operationType": "UPDATE"
}>
User Experience

Select the relevant payment method via the radio button and fill in the updated information and press save. To delete the payment method, select the relevant radio button, click the delete button and confirm your choice.

Add a new payment method

To add a new payment method: select add new account and fill in the relevant details. Click save.

Account Update and Registration Page

Updating and Registering Payment Accounts is a LIST Request feature that allows customers to manage payment data associated with their accounts. The feature is initiated by the merchants on their backend and it allows the customer more control over their saved payment methods.

This functionality will allow the customer to:

  • Update registered accounts (expiration date of credit and debit cards)
  • Delete registered accounts (except the last recurring registration)
  • Register new payment accounts without first making a payment
  • Set preferred payment account (separate documentation)

Please sign in to view further details of this article. Login

Web Content Display

Set Preferred Payment Account

A Recurring Charge is always triggered by specifying the registered customer through an API request, but not the registered payment account that should be used. This means OPG will select the payment account in the background. This way, you as a merchant do not have to manage registered payment accounts of your customers yourself. With the "Set Preferred" feature, your customer can specify which of their payment accounts is their preferred one. The preferred payment account would then be debited at the next Recurring Charge.

The feature can also be applied to standard account registrations.  However in this case, the preference only determines which registered account is shown at the top of the list on the payment page during the next checkout. The customer can still select another payment method.

Currently this feature can be accessed natively, AJAX library and Hosted Payment Page support will be added on request.

Integration

To allow your customers to set the preferred account, your system has to initialize an Update LIST with the parameter updateOnly: true. As in any other LIST Request, the request body can determine if recurring payment account registrations should be returned by setting the parameter channel to RECURRING. Otherwise the normal account registrations will be returned.

In any case the LIST Response will present the respective registered accounts like this example below.

LIST Response for Registered Accounts Selective Native Integration

...
  "accounts": [{
    "links": {
      "iFrame": "https://resources.sandbox.oscato.com/paymentpage/iframe.html?listId=585ab060e4b0f1217e9f4b3alr54bifbfla76esesbesj4k7ot&accountId=585a98bae4b091f43e2a0295a",
      "logo": "https://resources.sandbox.oscato.com/resource/network/DEMO_SK/de_DE/VISA/logo.png",
      "self": "https://api.sandbox.oscato.com/pci/v1/585ab060e4b0f1217e9f4b3alr54bifbfla76esesbesj4k7ot/accounts/585a98bae4b091f43e2a0295a",
      "lang": "https://resources.sandbox.oscato.com/resource/lang/DEMO_SK/de_DE/VISA.properties"
    },
    "code": "VISA",
    "label": "Visa",
    "maskedAccount": {
      "displayLabel": "40 *** 1112    08 | 2018",
      "holderName": "Jane Doe",
      "number": "40 *** 1112",
      "expiryMonth": 8,
      "expiryYear": 2018
    },
    "selected": false,
    "iFrameHeight": 35
    },
    ...
  ],
...

This list should be visualized for the user in the common way (see LIST Response, Update LIST). To make a payment account the preferred one, your system makes a simple POST request to the setpreferred endpoint of that account. The URL is the self link as given in the response plus an appended /setpreferred.

So the request for the example above would be:

  • URL: https://api.live.sandbox.oscato.com/pci/v1/585ab060e4b0f1217e9f4b3alr54bifbfla76esesbesj4k7ot/accounts/585a98bae4b091f43e2a0295a/setpreferred
  • Method: POST
  • Authentication: Not required (protected by the LIST ID)
  • Body: {}

Further details on the behavior of setpreferred

  • If the respective account was registered for both, standard registration and Recurring Charges, the preference will apply to both. This means that the next Recurring Charge request by that customer would trigger a payment with that account, and it would show up as a first entry in the payment page in the checkout flow.
  • If the preferred payment account gets deleted for one type of registration, the preference will still stay for the other type of registration.
  • If the preferred account is deleted, the account that was the preferred account before will be reset as the preferred account again. OPG-internally; the account  preferences are listed in order by the time when the accounts were designated as preferred accounts.
  • If none of the registered accounts were ever set as a preferred account, then the list is ordered by the time each account was registered, with the most recently registered account listed first.
  • If the customer adds a new payment account, the previously assigned prefered payment account will remain. This means, the new account does not automatically become the preferred account, unless there was no preferred account previously set (see above).

Set Preferred Payment Account

A Recurring Charge is always triggered by specifying the registered customer through an API request, but not the registered payment account that should be used. This means OPG will select the payment account in the background. This way, you as a merchant do not have to manage registered payment accounts of your customers yourself. With the "Set Preferred" feature, your customer can specify which of their payment accounts is their preferred one. The preferred payment account would then be debited at the next Recurring Charge.

The feature can also be applied to standard account registrations.  However in this case, the preference only determines which registered account is shown at the top of the list on the payment page during the next checkout. The customer can still select another payment method.

Please sign in to view further details of this article. Login

Web Content Display

Delete Payment Account

If you want to allow customers to remove their registered account again, the typical solution is to provide an explicit Account Update and Registration Page. However, you can also integrate this functionality into the normal Payment Page of a checkout context, or trigger it entirely from your backoffice.

To get all registered payment accounts of a customer and enable the possibility to delete them, your system sends a LIST request with the additional "allowDelete": true parameter, as shown in the example pane on the right.

Please note:

  • This feature is supported by Hosted and AJAX integrations, that will automatically render corresponding buttons, see below.
  • If you are using an Advanced integration scenario your system should trigger the account deletion in a second step after the LIST, in analogy to the description of the Account Update and Registration Page, issuing HTTP DELETE requests.
  • The account registration data registration.id and registration.password must be sent in the LIST request.
  • The allowDelete parameter can also be used to turn off the account deletion possibility on the Account Update and Registration Page by setting it to false. Otherwise account deletion will be available by default.

When using our Hosted page or AJAX library, every registered account will render an additional "Delete" button on their side, as shown in the example below. You can of course mofidy its style via your custom CSS stylesheet.

 

When a customer clicks on a delete button, the following dialog is presented:

 

The button label and user messages are localized, so if you are using the payment page for a language supported by optile, they will show correctly.

LIST Request with allowDelete


{
  "transactionId": "tr101",
  "country": "DE",
  "integration": "HOSTED",
  "allowDelete": true,
  "customer": {
    "number": "42",
    "email": "john.doe@example.com",
    "registration": {
      "id": "5a5cd871abc123409a2b4abcu",
      "password": "abc8Yqaabc123C2s"
    }
  },
  "payment": {
    "amount": 19.99,
    "currency": "EUR",
    "reference": "Shop 101/20-03-2016"
  },
  "style" : {
    "client":"RESPONSIVE"
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "notificationUrl":"https://dev.oscato.com/shop/notify.html"
  }
}

Delete Payment Account

If you want to allow customers to remove their registered account again, the typical solution is to provide an explicit Account Update and Registration Page. However, you can also integrate this functionality into the normal Payment Page of a checkout context, or trigger it entirely from your backoffice.

Please sign in to view further details of this article. Login

Web Content Display

Secure Storage

optile's Secure Storage is the internal component to hold sensitive payment account data in a double encrypted, PCI compliant way. It is used for payment account registrations and allows provider fallback. It cannot be accessed directly by the merchants, but it can be used by providing the customerRegistrationPassword in the LIST requests. This acts as one of the encryption keys of sensitive data. If, for example, there is a standard account registration with one provider (meaning the provider token is being stored and used by optile), but the provider has a downtime, then optile will use the customerRegistrationPassword that was provided by the merchant to access an alternative provider (if configured for the merchant), even if it does not have an account registration yet.

This is the reason why checkouts with registered payment accounts will work most of the time by supplying customerRegistrationId only, then existing provider registrations can be used. But to access the Secure Storage, decrypt sensitive account data and do failover routing without existing provider registrations the customerRegistrationPassword should be stored safely by your system and always supplied for payment sessions.

Secure Storage

Please sign in to view further details of this article. Login

Web Content Display

Payout Page

The Payment Gateway offers a dynamic Payout Page that works in analogy to the Payment Page. It can be used to make payments to the user and offers a convenient interactive way for the user to choose the "payment" account or network to transfer the money to. The same principles as for the payment checkout apply. The initialization happens with a LIST Request, followed by a PAYOUT Request (in contrast to a CHARGE). Entered Accounts can be registered and used (they are actually shared with payment accounts). The payout also can de deferred (requiring an additional CLOSING step from the merchant backend).

The JavaScript library of the AJAX Integration can be used to render the payout page. This results in a flow similar to the payment checkout:

The main difference is that in the LIST Request you provide the parameter preselection.direction with the value PAYOUT:

LIST Request with Payout Parameter

...
"country": "DE",
"preselection": {
  "direction": "PAYOUT"
},
"customer": {
...

This indicates that a LIST for PAYOUT (as opposed to CHARGE) is requested. As a consequence all forms and endpoints for further actions that are returned back will be coined towards a payout.

Apart from that the flow is the same. The subsequent PAYOUT Request is also structured as a CHARGE and will be handled by the JavaScript library, unless to choose to do a native integration.

Credits

After a LIST is initialized for payout by using the parameter preselection.direction = PAYOUT, any payment method returned in the list response can be employed for credit operations. The payout URL can be found in the operation parameter and it will have the following structure:

  • Sandbox: https://api.sandbox.oscato.com/api/lists/{listId}/{network}/payout
  • Live: https://api.live.oscato.com/api/lists/{listId}/{network}/payout
  • Basic Authentication: Merchant ID and Token

The credit is completed by sending a POST request to the operation URL, and sending the proper payment account in the JSON body. This process works in analogy to a charge operation in a regular LIST request.

Example of payout operation

POST to https://api.sandbox.oscato.com/api/lists/5a218abc123b512afef4f87glf4djckdjaih37abc1231n9ft9/MASTERCARD/payout
Basic Authentication
{
"autoRegistration": false,
"allowRecurrence": false,
"account": {
  "holderName": "John Doe",
  "number": "5500000000000004",
  "expiryMonth": "02",
  "expiryYear": "2019",
  "verificationCode": "555"
  }
}


Deferred Mode

The LIST for PAYOUT can also be requested in deferred mode, meaning that the customer submission of account details (the PAYOUT Request) does not yet trigger the money transfer. Instead, a consecutive CLOSING Request is needed, typically issued by the Merchant system after a staff member has reviewed the transaction. At this point the transaction will be executed through the configured providers.

For technical information on how to initialize and close deferred transactions, see Deferred Payments. The only difference for payouts is that there will be no reservation of funds on the payer's side.

Payout Page

The Payment Gateway offers a dynamic Payout Page that works in analogy to the Payment Page. It can be used to make payments to the user and offers a convenient interactive way for the user to choose the "payment" account or network to transfer the money to. The same principles as for the payment checkout apply. The initialization happens with a LIST Request, followed by a PAYOUT Request (in contrast to a CHARGE). Entered Accounts can be registered and used (they are actually shared with payment accounts). The payout also can de deferred (requiring an additional CLOSING step from the merchant backend).

Please sign in to view further details of this article. Login

Web Content Display

AJAX Library Integration

Using the AJAX Integration JavaScript library

Including the JavaScript Library:

The most recent AJAX Integration package can be downloaded here (login required): op-payment-widget-2.1.10.zip (~860 KB).

The zip file contains the following folders and files:

  • dist: The completely built and ready-to-use JavaScript and CSS files
  • example: An example HTML file in two versions, one linking the minified resources (JS & CSS) the other the development versions
  • node_modules: All node (npm) dependencies required to build the AJAX library
  • src: development source (based on node.js with the browserify addon)
  • package.json: list of build and runtime dependencies, and development scripts
  • README.md: A starting point for developers (node.js experience recommended)

The dist folder contains these files:

File  Description
op-payment-widget-2.x.x.js The readily built and readable JavaScript library.
op-payment-widget-2.x.x.min.js The minified version for production usage.
op-payment-widget.js A copy of the versioned file. Intended for optile-side hosting, we recommend merchants to use versioned files.
op-payment-widget-2.x.x.css The responsive CSS for the widget
op-payment-widget-2.x.x.min.css The minified version for production usage
op-payment-widget.css A copy of the versioned file. Intended for optile-side hosting, we recommend merchants to use versioned files.
responsive.html The HTML source of optile's hosted payment page, can be used as example to get started with development.

 

You can integrate the respective JavaScript and CSS files into an HTML page using the HTML header standard way.

Note that you also have to include the jQuery JavaScript framework yourself. If you want to support legacy browsers like Internet Explorer 6-8, Opera 12.1x or Safari 5.1+, we recommend a 1.12.x version for maximum compatibility (the latest 1.x version at the time of writing is 1.12.4).

We also recommend to set the viewport meta tag to enable the responsive UX, see example on the right.

HTML linking / including JavaScript and CSS

<head>
  <code class="language-markup"><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"></code>
  <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
  <script type="text/javascript" src="../op-payment-widget-dist/op-payment-widget-2.1.18.min.js"></script>
  <code class="language-markup"><link rel="stylesheet" type="text/css" href="../op-payment-widget-dist/op-payment-widget-2.1.18.min.css"></code>
  <!-- ... -->
</head>

Handling the LIST object ID

The LIST Request needs to be initiated from your backend, because it needs to contain your sensitive OPG credentials. These should never be processed through the customer's browser. Read about this call in our LIST Request article.

As a result a LIST object will be generated in OPG that contains all information to generate the payment checkout user interface (i.e., payment page). The only important part of the LIST Response is the link to this object (containing its ID).

On the right pane you can find an example LIST Response with the link to the object >>

LIST Response

{
  "links": {
    "self": "https://api.live.oscato.com/pci/v1/ce3eec14-e186-4b7c-94a1-fde802412e69"
  },
    ...
}

This URL to "self" or the contained LIST object ID (in this example: ce3eec14-e186-4b7c-94a1-fde802412e69) has to go back to the customer's browser and from there to the AJAX Integration Library. There are two ways of doing this:

  1. Redirect the browser to a (possibly static) HTML page that integrates the library and pass one of these LIST object identifiers as a GET parameter named listUrl or listId.
    Examples:
    http://www.ubuy.com/checkout/payment.html?listUrl=https%3A%2F%2Fapi.live.oscato.com%2Fpci%2Fv1%2Fce3eec14-e186-4b7c-94a1-fde802412e69
    http://www.ubuy.com/checkout/payment.html?listId=ce3eec14-e186-4b7c-94a1-fde802412e69
     
  2. Generate the HTML page on server side that contains the listUrl or listId parameter in the initialization call of the library. Find an example in the initialization call section below.

In order to have the payment checkout forms automatically injected into the current HTML DOM, you have to initialize the library.

You do so by specifying the HTML element you want to inject into first. Typically this is a <div> element. In the example it has the Id paymentNetworks and is referenced by jQuery syntax $('#paymentNetworks'). Then you trigger the checkoutList call from there.

An example call looks like this >>

JavaScript Initialization Call

$('#paymentNetworks').checkoutList({
  payButton: "submitBtn",
  baseUrl: "https://api.live.oscato.com/pci/v1/",
  smartSwitch: true,
  developmentMode: false });

These are the options you can provide in the call to configure and tune the payment checkout:

baseUrl String optional

The URL of the optile OPG service that will handle all the AJAX calls. It depends on the OPG version and enviroment you are using. OPG2 Live would be https://api.live.oscato.com/pci/v1/.

Not required if listUrl is used.

listId String optional

The ID of the LIST object as returned by the LIST Response. If not provided in the JavaScript call, the library will look for a GET query parameter called listId and use its value if found.

Not required if listUrl is used.

listUrl String optional

The URL to the generated LIST object as returned by the LIST response. If not provided in the JavaScript call, the library will look for a GET query parameter calles listUrl and use its value if found.

This value overrides any given listId and baseUrl parameters.

payButton String mandatory The ID of the HTML element that is the submit button. This has to be present in the HTML already.
smartSwitch Boolean optional

Boolean value to enable the "Smart Network Switch" feature. "Smart Network Switch" automatically detects the credit card brand by its card number while typing. Default is false.

For other payment networks it is meaningless.

abortFunction Function optional

Custom function to deal with ABORT interaction code of the response object. If set, it will replace the redirect defined in callback.cancelUrl.

Attention: even if an abortFunction is set, it is still required to have a callback.cancelUrl in place. This is to guarantee a proper response case the custom function fails to execute.

proceedFunction Function optional

Custom function to deal with PROCEED interaction code of the response object. If set, it will replace the redirect defined in callback.returnUrl and callback.summaryUrl. Note that this function replaces two possible redirections (return on success and summary page), so you have to act on the OPG response object to construct a proper replacement for a success or summary.

Attention: even if a proceedFunction is set, it is still required to have a callback.returnUrl and callback.summaryUrl in place. This is to guarantee a proper response case the custom function fails to execute.

Furthermore, intrinsic redirect networks cannot have their behavior changed. When using a custom proceedFunction, you will have to process the response object to build the redirect manually.

Property
Type
M / O
Description

 

If the AJAX Integration library is correctly initialized and provided with a valid listId it will fetch all resources needed to build the payment forms from OPG automatically and inject it into the current HTML DOM.
Note that a generated LIST object expires after 30 minutes. Also it will only allow one successful Charge. See LIST Request for details.

The mobile version of the AJAX integration library depends on a special structure of the HTML file, which is due to the underlying jQuery Mobile framework. Start from using the provided sample file, or use Hosted Integration instead
Finalize your payment checkout page

Some hints to finalize your payment checkout page:

  • To adapt the styling to your needs, we suggest to edit the (un-minified) CSS stylesheet provided in the beginning of this section.
  • Make sure the provided icon hint.png is properly referenced and shows as a question mark icon next to the verification code input of credit cards, as well as the other icons in the desktop variant.
  • Use the development version of the library, which is available for enterprise merchants, to do your own advanced customizations of behavior and generated markup structure.
  • Further Payment Flow
  • After the users' choice of payment method is complete they will be automatically redirected (returnUrl / cancelURL / external PSP page) or get a response from your custom functions. In the case the browser goes to an external page for payment, they will still in the end be directed to the given returnURL or cancelURL.

Your backend will get a secure asynchronous notification about the current transaction status, which your system should listen to. See Status Notification for additional information.

Example HTML

<!DOCTYPE html>
<html>
<head>
  <title>Hosted Payment Page</title>
  <meta charset="utf-8">
  <script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <script type="text/javascript" src="op-payment-widget-2.0.0.min.js"></script>
  <link rel="stylesheet" type="text/css" href="op-payment-widget-2.0.0.min.css">
  <script type="text/javascript">
    function initPaymentPage() {
      var dict = {};
      $('#paymentNetworks').checkoutList({
        payButton: "submitBtn",
        baseUrl: "https://api.live.oscato.com/pci/v1/",
        abortFunction: function() {
          console.log("Error")
        },
        proceedFunction: function() {
          console.log("Success")
        }
}); }
// Initialize the payment page
      $(document).ready(function() {
        initPaymentPage(); });
  </script>
</head>
<body>
  <div id="paymentNetworks">
  </div>
  <button id="submitBtn" type="button"></button>
</body>
</html> 
Native Form Rendering

If you wish to implement natively the optile's localized forms snippets returned from the original LIST Response, please refer to the Native Form Rendering article for details.

AJAX Library Integration

Please sign in to view further details of this article. Login

Web Content Display

Display & Pure Native Integration

Web Content Display

LIST Response

After submitting a LIST Request you will receive the LIST response.

  • If you chose AJAX Integration, you will only be interested in the link.self return parameter (and status information to check if it worked).
  • If you use Hosted Integration you will get a very simplistic response and only be interested in the redirect return parameter (see there).
  • Only if you use Native Integration you will want to analyze the list of available networks for this transaction in order to build the checkout payment page. Read the details linked below to see how.
The networks that are available are contained as an array in the response parameter networks.applicable. If you have registered payment accounts (e.g., credit card) from a customer these will be contained in accounts (as masked data).

If you use Pure Native integration the response will contain a few extra attributes as you can see below. The idea is that this advanced data will only be handled by merchants' server systems, whereas the Display Native data (above) could safely be passed to a browser to render the page in the frontend.

Display the payment networks

For every payment network, all resources that are needed to display and charge it will be provided. With these resources, you can easily generate your individual payment page within the frame of your corporate design, which is seen by your customer.
The important links are as follows:

  • localizedForm: Links to a HTML form snippet detailing what information is required from the customer to charge this network (e.g., credit card number). Labels are in the language according to the LIST Request's country or style.language parameters. The input fields provided depend heavily on the network. Their name attributes already correspond to the parameter names required for the consecutive CHARGE. Only the ${formId} placeholder in "id" attributes needs to be replaced before displaying the form, which was designed to avoid potential conflicts with existing elements on the page.
  • operation: This is the OPG URL where the information entered into the form should be submitted to. It is individual per network. Note that for Pure Native scenarios you would submit to your own server first, and from there to the OPG. For Display Native scenarios the submission comes directly from the browser. We recommend an AJAX request instead of form submission for this.
  • logo: URL of a logo that can be displayed for this network
  • validation: The custom validation service we provide for this network. The form data can be posted here asynchronously to receive live feedback whether the information is considered valid.

With this data, you create the payment checkout page (most likely but not necessarily in HTML) dynamically and per transaction. Do not hard code payment network forms to keep the power of the implement once principle. When the page is built, deliver it to the client (i.e., the browser), which displays it to your customer.

Visualization (red are parameters or resources to fetch, green calls to execute):

Example LIST Response for Display Native integration
 {
  "links": {
    "self": "https://api.sandbox.oscato.com/api/lists/abcd1234abcd1234abcd1234abcd1234"},
  "timestamp": "2017-07-13T08:09:18.788+0000",
  "operation": "LIST",
  "resultCode": "00000.11.000",
  "resultInfo": "1 applicable and 0 registered networks are found",
  "returnCode": {"name": "OK", "source": "GATEWAY"},
  "status": {"code": "listed", "reason": "listed"},
  "interaction": {"code": "PROCEED", "reason": "OK"},
  "identification": {
    "longId": "abcd1234abcd1234abcd1234abcd1234",
    "shortId": "abcde-12345",
    "transactionId": "id000001"},
  "networks": {
    "applicable": [{
      "code": "MASTERCARD",
      "label": "MasterCard",
      "method": "CREDIT_CARD",
      "grouping": "CREDIT_CARD",
      "registration": "OPTIONAL",
      "recurrence": "NONE",
      "redirect": false,
      "links": {
        "form": "https://resources.sandbox.oscato.com/resource/form/MASTERCARD/standard.html",
        "logo": "https://resources.sandbox.oscato.com/resource/network/ABC123/en_EN/MASTERCARD/logo2x.png",
        "self": "https://api.sandbox.oscato.com/api/lists/abcd1234abcd1234abcd1234abcd1234/MASTERCARD",
        "lang": "https://resources.sandbox.oscato.com/resource/lang/ABC123/en_EN/MASTERCARD.properties",
        "operation": "https://api.sandbox.oscato.com/api/lists/abcd1234abcd1234abcd1234abcd1234/MASTERCARD/charge",
        "localizedForm": "https://resources.sandbox.oscato.com/resource/form/ABC123/DE/en_EN/MASTERCARD/standard.html",
        "validation": "https://api.sandbox.oscato.com/pci/v1/abcd1234abcd1234abcd1234abcd1234/ABC123/en_EN/MASTERCARD/standard/validate"
      },
      "button": "button.charge.label",
      "selected": false
    }]
  },
  "operationType": "CHARGE"
}

LIST Response

After submitting a LIST Request you will receive the LIST response.

  • If you chose AJAX Integration, you will only be interested in the link.self return parameter (and status information to check if it worked).
  • If you use Hosted Integration you will get a very simplistic response and only be interested in the redirect return parameter (see there).
  • Only if you use Native Integration you will want to analyze the list of available networks for this transaction in order to build the checkout payment page. Read the details linked below to see how.

Please sign in to view further details of this article. Login

Web Content Display

Native Form Rendering

In native implementations and non-PCI applicable payment networks in Selective Native implementations, the LIST Responses will contain localized form snippets that can be used to integrate into your payment page.

Once you sign in you will be able to see the overview of how to do this for the Native and Selective Native integration scenarios.

In native implementations and non-PCI applicable payment networks in Selective Native implementations, the LIST Responses will contain localized form snippets that can be used to integrate into your payment page.

Below is an overview of how to do this for the Native and Selective Native integration scenarios.

Getting snippets from OPG

In order to retrieve the relevant localised form snippets your system would make a LIST request specifying the integration type and country, see right.

Example LIST Request
{
  "transactionId": "tr10687",
  "country": "GB",
  "integration": "SELECTIVE_NATIVE",
  "updateOnly": false,
  "customer": {
    "number": "11",
    "email": "john.doe@example.com",
    "registration": {
      "id": "586e73261652031c165ed473u",
      "password": "1Xz5NpCk7Comh737"
    }
  },
  "payment": {
    "amount": 19.99,
    "currency": "EUR",
    "reference": "tesRef1234"
  },
  "callback": {
    "returnUrl": "https://myReturnUrl.com/pending.html",
    "cancelUrl": "https://myReturnUrl.com/cancel.html",
    "notificationUrl": "https://myReturnUrl.com/notification.html"
  }
}

The LIST Response will contain a list of applicable networks that each contain information about the configured payment method. Excluding credit cards in a selective native integration, the network information will contain a series of links, which will allow the integrating developer to present the payment option on the frontend.

The most important link to consider at this stage is the localised form. This is the form content that can be presented to the end customer so that their payment details can be captured. As the LIST Request contains a country element, these form snippets will already be translated to the appropriate language.
Other links that will be used during the process will be the validation link for validation, operation link for the charge, logo for display purposes. You can also refer to activate methods-frontend integration for using the self-link for reloading the form Activate Request, however, this example will not be concerned with it.

See the example from the associated LIST Response excerpt for SEPADD:

Example LIST Response excerpt for SEPADD
{
  "links": {
    "self": "https://api.sandbox.oscato.com/pci/v1/58c1768a1652684dd6a48a80lrf6p4m7omoivilf2vsp5hcg0g",
    "customer": "https://api.sandbox.oscato.com/api/customers/586e73261652031c165ed472u"
  },
  "timestamp": "2017-03-09T15:36:42.941+0000",
  "operation": "LIST",
  "resultCode": "00000.11.000",
  "resultInfo": "7 applicable and 2 registered networks are found",
  "returnCode": {
    "name": "OK",
    "source": "GATEWAY"
  },
  ...
  "networks": {
    "applicable": [
    ...,
    {
      "code": "SEPADD",
      "label": "SEPA",
      "method": "DIRECT_DEBIT",
      "grouping": "DIRECT_DEBIT",
      "registration": "OPTIONAL",
      "recurrence": "NONE",
      "redirect": false,
      "links": {
        "form": "https://resources.sandbox.oscato.com/resource/form/SEPADD/standard.html",
        "logo": "https://resources.sandbox.oscato.com/resource/network/MERCHANTXYZ/de_DE/SEPADD/logo.png",
        "self": "https://api.sandbox.oscato.com/pci/v1/58c1768a1652684dd6a48a80lrf6p4m7omoivilf2vsp5hcg0g/SEPADD",
        "lang": "https://resources.sandbox.oscato.com/resource/lang/MERCHANTXYZ/de_DE/SEPADD.properties",
        "operation": "https://api.sandbox.oscato.com/pci/v1/58c1768a1652684dd6a48a80lrf6p4m7omoivilf2vsp5hcg0g/SEPADD/charge",
        "localizedForm": "https://resources.sandbox.oscato.com/resource/form/MERCHANTXYZ/DE/de_DE/SEPADD/standard.html",
        "validation": "https://api.sandbox.oscato.com/pci/v1/58c1768a1652684dd6a48a80lrf6p4m7omoivilf2vsp5hcg0g/MERCHANTXYZ/de_DE/SEPADD/standard/validate"
      },
      "button": "button.charge.label",
      "selected": false
    }],
  },
  "operationType": "CHARGE"
}

To view the form snippet as is, simply copy the localizedForm URL and paste it into a browser. The result will look something like this:

If you view the source of this URL, you will see that it is not a complete HTML page but only the inner contents of a form. Note also that there are placeholders present in the form of {form-id} and these will be used later to identify the form and input snippet. This is covered in a later section in this document.

HTML Code of the Form

<fieldset class="account">
  <div id="${formId}-row1" class="row row1">
    <div class="col col1"><label for="${formId}-iban">IBAN</label></div>
    <div class="col col2"><input id="${formId}-iban" type="text" name="iban" class="text iban" autocomplete="off"></div>
    <div class="col col3"><span id="${formId}-iban-message" class="message"></span></div>
  </div>
  <div id="${formId}-row2" class="row row2">
    <div class="col col1"><label for="${formId}-bic">BIC</label></div>
    <div class="col col2"><input id="${formId}-bic" type="text" name="bic" class="text bic" autocomplete="off"></div>
    <div class="col col3"><span id="${formId}-bic-message" class="message"></span></div>
  </div>
  <div id="${formId}-row3" class="row row3">
    <div class="col col1"><label for="${formId}-holderName">Account holder</label></div>
    <div class="col col2"><input id="${formId}-holderName" type="text" name="holderName" class="text holderName" autocomplete="off"></div>
    <div class="col col3"><span id="${formId}-holderName-message" class="message"></span></div>
  </div>
</fieldset>

Presenting the forms on screen

Developers who have chosen a Native/Selective Native integration method will have total control about where they would like to present the form snippets. What follows is only to serve as an illustration of how to do this and you are free to implement this on the front end as you wish.
After retrieving the LIST Response the associated payment networks should be presented on the front end programmatically so that methods can be added removed on the merchant configuration portal without requiring changes in the integrated site's payment front end.

In this simple example, all payment methods in a radio button list are displayed. When the radio button is selected some JavaScript will fire and the associated paymentInputPlaceholder div, which contains the localised form snippet, will be displayed. Some information from the LIST Response data values in these HTML controls are also populated, so that they can be accessed later in the process. In this example, one pay button that is used to make the selected payment request and it is placed beneath the radio buttons.

Example of Form Snippet Implementation

<!-- Loop through the applicable networks returned in the LIST Response.
The below uses MVC with HTML5 but you are free to implement this as you wish this is for ILLUSTRATION ONLY!
-->

foreach (var network in Model?.ApplicableNetworks?.OrderBy(x => x.label))

{
  <!-- Div to hold the title of the payment method and a radio button group to allow this be selected-->
  <div class="PaymentItem row" style="border:0px solid black;">
    <div class="col-xs-9 PaymentHeaderItem">
      <div class="col-xs-3" style="vertical-align:middle;">
        <span>
          <input type="radio" name=paymentNetworks
            data-recurrence="@network.recurrence"
            data-networkMethod="@network.method"
            value="@network.code.Replace(" ", "")" />
          <img src="@network.links.logo" />
        </span>
      </div>
      <div class="col-xs-6" style="vertical-align:middle;">
        @network.label
      </div>
    </div>
    <!-- The placeholder that will be displayed when the associated radio button is selected -->
    <div class="paymentInputPlaceholder" id="@network.code.Replace(" ", "")">
      <div class="col-xs-9 paymentTitle">
        @{
          // These are variables associated with displaying the 'register for later' checkbox
          bool registrationPossible = network.registration.ToLower() != "none";//none means the network does not support registration
          bool displayEnabled = network.registration.ToLower() != "forced";// forced means the backend is configured to always register this payment option, no user selection allowed
          bool registrationOptionalChecked = network.registration.ToLower() == "optional_preselected";
          bool checkedValue = (displayEnabled == true || registrationOptionalChecked == true);
          }

        <!-- Display the check box if it is a method that supports registration and the user is logged in -->
        @if (User.Identity.IsAuthenticated && registrationPossible)
        {
          <div style="vertical-align:text-bottom">
            <label style="vertical-align:bottom">
              <input type="checkbox"
                id="@(network.code.Replace(" ", "") + "Register")"
                value=@checkedValue
                enabled=@displayEnabled >
              @Resource.RegisterPaymentMethod <!--Local Resource containing 'Register this paymnet method' text-->
            </label>
          </div>
        }

        <!-- As this sample uses a selective native integration there may be credit cards that we
        need to display in a frame as opposed to a form to avoid being in PCI scope -->
        @if (network.method.Equals("credit_card", StringComparison.OrdinalIgnoreCase))
        {
          <iframe id="@(network.code.Replace(" ","")+"Frame")" frameborder="0" seamless=""
            src="@network.links.iFrame" height="@(network.iFrameHeight+10)"
            style="width:90%; overflow:hidden;  border:0px groove black"></iframe>
        } else {
		
        <!-- Display the contents of the localised form here. I have built a form around the snippet
		but that may not be totally necessary and is up to the implementing party to design this as they wish.
		Important points to note though is that I'm noting the validation, self and operation links form the
		LIST Response here for future use in my jquery/JavaScript
        -->

          <form id="@(String.Format("{0}{1}",network.code.Replace(" ",""),"Form"))"
            action="@network.links.operation" method="post"
            class="formSnippet"
            data-snippetId="@(String.Format("{0}{1}", network.code, "Snippet"))"
            data-listSelf="@network.links.self"
            data-validationUrl="@network.links.validation">
            <div class="optileHtmlSnippet"
              id="@(String.Format("{0}{1}", network.code, "Snippet"))"
              data-code="@(network.code.Replace(" ",""))"
              data-src="@network.links.localizedForm" >
            </div>
          </form>
        }
      </div>
    </div>
  </div>
}

<!-- Submit button for all payment options -->
<div class="row" style="padding-top:10px; float: left;">
  <button class="submitBtn btn btn-primary" value="Pay">@Resource.Pay</button>
</div>

Populating form snippets

As mentioned previously in this article, the localised form snippets contain placeholders to identify the associated form. Before these snippets can be properly utilised these snippets must be replaced with the relevant value.
To do this you must inject the name of the payment method into the localised form on the frontend. There are different approaches to accomplishing this, however, in this example you simply place all localised forms inside a div named ‘optileHtmlSnippet' and then on the document load calling function, replace all form name placeholders with the form name. The function opTemplateEngine in this example is available in the following JavaScript file ‘template-engine.min.js', should you wish to use it.

JavaScript Code to Load HTML Snippets into Placeholders

// Load htmlSnippets into placeholders
$(".optileHtmlSnippet").each(function () {
  /* Get the custom attribute from the div that contains the address of the localised
  form returned in the LIST Response */
  var src = $(this).attr("data-src");
  var currentElement = $(this);
  $.get(src, function (response) {
    var code = currentElement.attr("data-code");
    /* Load the form snippet into the div with the placeholders replaced
    The opTemplateEngine is another JavaScript file that contains this logic */
    var endHtmlSnippet = opTemplateEngine(response, {formId:code});
    // Set the current elements html to the html where placeholders have been replaced
    currentElement.html(endHtmlSnippet);
  });
});

After this step is applied, the form snippet will now have the placeholders replaced. Please see the example below for SepaDD.

Before:

	<div id="${formId}-row1" class="row row1">

	   <div class="col col1"><label for="${formId}-iban">IBAN</label></div>

	   <div class="col col2"><input id="${formId}-iban" type="text" name="iban" class="text iban" autocomplete="off"></div>

	   <div class="col col3"><span id="${formId}-iban-message" class="message"></span></div>

	</div>

After:

	<div id="SEPADD-row1" class="row row1">

	   <div class="col col1"><label for="SEPADD-iban">IBAN</label></div>

	   <div class="col col2"><input id="SEPADD-iban" type="text" name="iban" class="text iban" autocomplete="off"></div>

	   <div class="col col3"><span id="SEPADD-iban-message" class="message"></span></div>

	</div>
Displaying Registration checkboxes

If you wish to display checkboxes to the user, so that they can specify the payment method that should be saved for future use, you must render this on the frontend outside the form snippet.
In this example, a checkbox is rendered to handle this. Before rendering the checkbox and setting the desired value, the original LIST Response should be checked for each payment method to see if registration is supported, as some payment methods do not support registration.

The value in the LIST Response that illustrate this is the Registration property of the applicable network.

Example LIST Response
{
...
  "code": "SEPADD",
  "label": "SEPA",
  "method": "DIRECT_DEBIT",
  "grouping": "DIRECT_DEBIT",
  "registration": "OPTIONAL",
  "recurrence": "NONE",
  "redirect": false,
...
}

The possible values of this registration value can be seen in the console API but can also be summarised as:

  • NONE – Registration is not supported.
  • OPTIONAL – Registration may be selected.
  • FORCED - Registration must be selected but not displayed.
  • OPTIONAL_PRESELECTED – Registration is optional but defaults to selected.
  • FORCED_DISPLAYED – Registration must be selected and displayed

In the frontend some logic must be in place to decide if the checkbox is rendered or not.

Example Logic for Frontend

@{
  // These are variables associated with displaying the 'register for later' checkbox

  bool registrationPossible = network.registration.ToLower() != "none";//none means the network does not support registration

  // forced means the backend is configured to always register this payment option, no user selection allowed

  bool displayEnabled = network.registration.ToLower() != "forced" && network.registration.ToLower() != "forced_displayed";
  bool registrationOptionalChecked = network.registration.ToLower() == "optional_preselected";
  bool checkedValue = (displayEnabled == true || registrationOptionalChecked == true);
}
<!-- Display the check box if it is a method that supports registration and the user is logged in -->


@if (User.Identity.IsAuthenticated && registrationPossible) {
  <div style="vertical-align:text-bottom">
    <label style="vertical-align:bottom">
      <input type="checkbox"
        id="@(network.code.Replace(" ", "") + "Register")"
        value=@checkedValue

        enabled=@displayEnabled>
    @ Resource.RegisterPaymentMethod
	<!--Local Resource containing 'Register this payment method' text-->
    </label>
  </div>
}

This information can then be retrieved on the Charge and included as part of the CHARGE Request.

Example Code

//Get register value
var registerCheckbox = $('input[name=paymentNetworks]:checked').val() + "Register";
var allowPaymentRegistration = $('#' + registerCheckbox).prop('checked');

Display Recurring charges checkboxes

This uses the same approach as above, but instead use the recurrence property in the LIST Response to drive the logic.

Validation

There was a validation link in the original LIST Response for each applicable payment method . In this example, this information is loaded as a data value attribute in the snippet div.

On form submit, a jQuery function is needed to perform validation and should be implemented if the selected payment method is not an iFrame. Refer to Selective Native for iFrame validation in a Selective Native integration.

In this example, the implementation of the localised form validation is simply an ajax call to validate the information contained in the selected form snippet. If there are errors, they will be rendered at the appropriate place in the form. Once again, please note that this is only an example for illustration purposes you are free to implement this any way you like.

Example JavaScript Code for Validation

var validationPassed = validateFormInput(validationUrl, data, formSnippetId);
// Use the validation URL from the LIST Response to validate the submitted form data
function validateFormInput(validationUrl, data, formId) {
  // if there is no data to validate then mark it as passed
  if(data == null) {
    return true;
  }

  var jsonString = (JSON.stringify(data))
  var result = null;
  $.ajax({
    url: validationUrl,
    async: false, // forcing the validation to fire before continuing with form processing
    type: 'post',
    contentType: "application/json; charset=utf-8",
    dataType: 'json',
    data: jsonString,
    success: function (response) {
      result = response.valid;
      if(!response.valid) {
      // Loop through each field's validation response
        $.each(response.messages, function(formInput) {
          var snippetInputId = "#" + formId + "-" + formInput + "-message";
          if(response.messages[formInput].type.toLowerCase() == "error") {
            /* Display this error in the relevant place - the message placeholder will
            always be '${formId}-{inputFieldName}-message' */
            $(snippetInputId).text(response.messages[formInput].message);
            $(snippetInputId).css({ "color": 'red'});
          } else {
            $(snippetInputId).text("");
          }
        });
      }
    },
    error: function (response) {
      console.log("FAILURE trying to run validation : " + JSON.stringify(response));
      result = false;
    }
  });
  return result;
}

It may be worth looking at the underlying validation request and response that this sample code generates. The validation request will look different depending on the selected payment method, however, in the case of SEPADD as shown in this example, it will serialise to something similar to what is below. Z's are inserted in the iban to simulate what one will see in the LIST Response if there is an error.

"{"iban":"DE89370400440532013000","bic":"ZZZPBNKDEFFZZZ","holderName":"Jane Doe"}"

The response to the above request will be something similar to the code opposite>>

Example JSON Response

{
  "valid": false,
  "messages": {
    "holderName": {
      "type": "INFO",
      "message": "Valid"
    },
    "iban": {
      "type": "ERROR",
      "message": "Invalid IBAN!"
    },
    "bic": {
      "type": "INFO",
      "message": "Valid"
    }
  }
}

The important thing to note is that there will be a valid object at the root level and then information about each field that was checked and whether the validation was passed or not. This information can then be used to render a meaningful error message to the user on the front end.

Charge

Assuming the validation passed the next step and will be able to make the CHARGE. This can be accomplished via a request to the operation URL returned in the original LIST Request. In this example, the operation URL was saved as a data property in display div.

The CHARGE will always need an account object. This information can be retrieved from the localised form via jQuery/JavaScript. See the opposite sample for illustration.

Example JavaScript Code

var radioButton = $('input[name=paymentNetworks]:checked').val();
var radioButtonClass = $('input[name=paymentNetworks]:checked').attr("data-networkMethod");
if (radioButtonClass.toLowerCase() === "credit_card" || radioButtonClass.toLowerCase() === "frame") {
  var frameToPostToName = $('input[name=paymentNetworks]:checked').val() + "Frame";
  var frameToPostTo = document.getElementById(frameToPostToName).contentWindow;

  // Make post to frame
  frameToPostTo.postMessage({ "type": "payment_action", "request": { "allowRecurrence": allowRecurringPayment, "autoRegistration": allowPaymentRegistration } }, opg_origin);
} else {
  // All non credit cards handled here
  var formSnippetId = $('input[name=paymentNetworks]:checked').val();
  var formToPostToName = $('input[name=paymentNetworks]:checked').val() + "Form";
  var formId = '#'+formToPostToName;
  var actionUrl = $(formId).attr("action");
  var validationUrl = $(formId).attr("data-validationUrl");
  var listSelf = $(formId).attr("data-listSelf");
  var snippetId = $(formId).attr("data-snippetId");
  var data = cleanData($(this).serializeFormJSON($(formId).serializeArray()));

  // Make a validation call and only proceed if it passes, the display of errors will be handled in the validateFormInput method
  var validationPassed = validateFormInput(validationUrl, data, formSnippetId);

  if(validationPassed) {
  // Assume there is a form snippet rendered for this payment option
  // if there isnt the post data will simply be empty
  var postRequest = {};
  postRequest.account = data;
  postRequest.allowRecurrence = allowRecurringPayment;
  postRequest.autoRegistration = allowPaymentRegistration;
  var jsonString = (JSON.stringify(postRequest))

$.ajax({
    url: actionUrl,
    type: 'post',
    contentType: "application/json; charset=utf-8",
    dataType: 'json',
    data: jsonString,
    success: function (response) {
        if(response['resultInfo']) {
            if(response['interaction']['code'].toLowerCase() == "proceed"
            || response['interaction']['code'].toLowerCase() == "reload") {
                // The result of a charge can be a redirect of type GET or POST.
                // and may or may not contain parameters
                if(response['redirect'] != null) {
                    if(response['redirect']['method'].toLowerCase() == "get") {
//Redirect to provided redirect url and provide any params
                        var parameters = response["redirect"]["parameters"];
                        var redirectUrl = response['redirect']['url'];
                        if(parameters != null) {
                            redirectUrl = redirectUrl+"?"+jQuery.param(parameters);
                        }
                        window.location.href = redirectUrl;
                    } else {
                        //Make a post using redirect parameters as input
                        var postData = keyPairToJson(response["redirect"]["parameters"]);
                        $.redirectPost(response['redirect']['url'], postData);
                    }
                } else if(response['interaction']['code'].toLowerCase() == "reload") {
                    var elementToUpdate = $('#' + snippetId);
                    var srcToLoad = "";
                    var formData = null;
                    var formToPostToName = $('input[name=paymentNetworks]:checked').val() + "Form";
                    $.get(listSelf, function (response) {
                        // set new form action url
                        $('#'+formToPostToName).attr('action', response.links.operation);
                        // set new form validation url
                        $('#'+formToPostToName).attr('data-validationUrl', response.links.validation);
                        srcToLoad = response.links.localizedForm; // get form source
                        formData = response.formData; // get form data
                        $(".submitBtn").prop("disabled", false); //enable pay button again

                        // Load localised activated form
                        $.get(srcToLoad, function (response) {
                            var formToPostToName = $('input[name=paymentNetworks]:checked').val() + "Form";
                            var selectedForm = '#'+formToPostToName;
                            var snippetId = $(selectedForm).attr("data-snippetId");
                            var elementToUpdate = $('#' + snippetId);
                            var code = elementToUpdate.attr("data-code");

                            // Load the form snippet into the div
                            var htmlToInjectIntoSnippet = opTemplateEngine(response, {formId:code});

                            // Find the name of the postcreate function to call. This will always be in the fieldset of the injected localised form if it is present
                            var postCreateFunctionName = $('#' + code +"-fieldset").attr("postCreate");
                            if(postCreateFunctionName != null) {
                                // manually inject the postcreate function call with the formData from the response
                                htmlToInjectIntoSnippet = htmlToInjectIntoSnippet.replace("<script>","<script> "+ postCreateFunctionName +"("+JSON.stringify(formData)+");");
                            }
                            elementToUpdate.html(htmlToInjectIntoSnippet);
                        });
                    });
                }
            } else {
                //show error
                $("#paymentError").text(response['resultInfo']);
                $("#paymentError").show();
            }
        }
    },
    error: function (response) {
        $("#paymentError").text(response['resultInfo']);
        $("#paymentError").show();
    }
   });
  }
}
});

On success, the response can be analysed and the desired actions performed. In most cases this will be a redirect to a summary page, but in the case of activate networks some other actions may be required.

Redirect methods in Selective Native

Redirect methods will also return localised forms from the LIST Request. They can be rendered in a similar fashion to standard localised forms. If the implementation is properly ‘implement once' than no extra work will be needed to render these payment methods.

The only real extra step required is at the frontend step, which handles the CHARGE event.

An extra piece of logic can be inserted, to detect if the response is a redirect and then to make the associated GET or POST Request. See the JavaScript example above.

Presenting saved payment methods

The same approach can be used for displaying saved payment methods, these being the registered methods returned in the LIST Response.

Native Form Rendering

In native implementations and non-PCI applicable payment networks in Selective Native implementations, the LIST Responses will contain localized form snippets that can be used to integrate into your payment page.

Once you sign in you will be able to see the overview of how to do this for the Native and Selective Native integration scenarios.

Please sign in to view further details of this article. Login

Web Content Display

CHARGE Request

The CHARGE Request triggers the actual payment, which was initialized through the preceeding LIST Request. This can be issued from browsers/other clients or servers, depending on the integration scenario. The CHARGE Request submits the customer's payment details (AKA account data). As an option it can contain flags, if the account data should be stored in OPG's Secure Storage, e.g. for Recurring Registration or re-usable Account Registration. All the other data (e.g., amount) the OPG will take from the related LIST Request (which is required before a CHARGE).

You only need to implement the Frontend CHARGE Request yourself in Native Integration scenarios.

The customer's sensitive payment account data originates from the customer's client. That's why we call it a Frontend CHARGE (as opposed to triggering a Recurring Charge which would be a Backend Charge). Due to PCI regulations the sensitive data takes different paths, depending on the Native Integration scenario in place:

Display Native: The data is transferred from the payment checkout page in the customer's client (e.g., browser) directly to the OPG. Your server side systems never get in touch with the data, and therefore don't have to be PCI certified.

Pure Native: The data is transferred from the payment checkout page to your own server side systems. From there it is submitted to OPG (server to server). This way your system may store the data itself. In case of credit cards, your system needs to fulfill certain PCI DSS standards and get certified.

The endpoint for the CHARGE Request is given as operation attribute for the method in question in the LIST Response.

Example Frontend CHARGE Request
  • URL: https://api.sandbox.oscato.com/api/lists/ce3eec14-e186-4b7c-94a1-fde802412e69/VISA/charge
  • Basic Authentication: ABC123:BAtXa7yubR8ipuT
  • Method: POST
  • Headers
    • Content Type: application/vnd.optile.payment.enterprise-v1-extensible+json
    • Accept: application/vnd.optile.payment.enterprise-v1-extensible+json
Example of Account Data
 {
  "account": {
    "holderName": "John Doe",
    "number": "4111111111111111",
    "verificationCode": "123",
    "expiryMonth": "12",
    "expiryYear": "2021"
  }
}

JSON CHARGE Request Body
In some cases (like redirect networks without an inpage form such as PayPal) no data is submitted during the CHARGE Request. However, you still need to supply an empty JSON object {}, not an empty request body.
In Display Native scenarios you do not authenticate the CHARGE Request to avoid having your credentials in the browser. The call is protected by the token identifying the LIST resource (AKA "longId" or "LIST ID"). It is randomly generated and valid for 30 minutes.
Handling the CHARGE Response

The CHARGE Response is returned to the system that issued the request. This is often the customer client (e.g., browser), in Pure Native scenarios it is typically the merchant backend. At the same time a Status Notification is sent from the OPG to the merchant backend (as specified in the notificationUrl), containing the same status information. It can be used as a reliable source of status information for the merchant. The CHARGE reply on the other hand should be evaluated in terms of feedback to the customer and how to direct them further.

Masked Account data

After a successful charge request, the response body will contain also a masked account used for the charge, which can be used to provide to the end customer a better summary of the payment process. The data can be found inside the maskedAccount parameter in the response body. On the right pane we present an example for illustration.

It is important to notice that when using client-side charges (by using our AJAX library, for example) the masked account data will not be sent on the response.

Example of Successful Charge

Header

HTTP/1.1 200 OK
Content-Type: application/vnd.optile.payment.simple-v1-extensible+json; charset=utf-8
Content-Length: <length>

JSON
{
  "links": {
    "payout": "https://api.sandbox.oscato.com/api/charges/59f756bfa6cd3d345d2d39a3c/payout",
    "self": "https://api.sandbox.oscato.com/api/charges/59f756bfa6cd3d345d2d39a3c"
  },
  "timestamp": "2017-10-30T16:43:43.723+0000",
  "operation": "CHARGE",
  "resultCode": "00000.TESTPSP.000",
  "resultInfo": "Approved",
  "pspCode": "TESTPSP",
  "returnCode": {
    "name": "OK",
    "source": "PSP"
  },
  "status": {
    "code": "charged",
    "reason": "debited"
  },
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "clearing": {
    "amount": 450.00,
    "currency": "EUR"
  },
  "identification": {
    "longId": "59f756bfa6cd3d345d2d39a3c",
    "shortId": "14052-58040",
    "transactionId": "id_h0017",
    "pspId": "VISA.DEBIT.1509106088565"
  },
  "redirect": {
    "url": "http://localhost:3000/html/success.html",
    "method": "GET",
    "parameters": [
      {"name": "shortId", "value": "14052-58040"},
      {"name": "interactionReason", "value": "OK"},
      {"name": "resultCode", "value": "00000.TESTPSP.000"},
      {"name": "longId", "value": "59f756bfa6cd3d345d2d39a3c"},
      {"name": "transactionId", "value": "id_h0017"},
      {"name": "interactionCode", "value": "PROCEED"},
      {"name": "amount", "value": "450.00"},
      {"name": "reference", "value": "sandbox testing"},
      {"name": "currency", "value": "EUR"}]
  },
  "customer": {
    "number": "69",
    "email": "john.doe@example.com",
      "name": {
        "firstName": "John",
        "lastName": "Doe"
      }
  },
  "network": "VISA",
  "maskedAccount": {
    "displayLabel": "41 *** 1111    02 | 2020",
    "holderName": "John Doe",
    "number": "41 *** 1111",
    "expiryMonth": 2,
    "expiryYear": 2020
  }
}

Redirect after Success

A typical successful CHARGE response looks like this:

If the request is accepted and the Interaction Code in the response indicates PROCEED, the response will contain the redirect structure with information a to where the user should be redirected. Only in Pure Native scenarios if you did not provide the callbacks in the LIST Request, then you have to generate the redirect in your backend yourself.

There are two different reasons for redirection after a successful request:

  1. Payment was successfully completed. In this case the redirect will lead to merchants success page.
  2. Payment was initiated, but additional information is required from customer, e.g. 3D secure code for Visa or MasterCard, or authentication and confirmation at the site of a redirect network such as PayPal or Sofort. In this case the redirect will lead to the acquirer or PSP web site to continue the interaction with the customer.

Regardless of the reason, the task of your system is simply to redirect the customer's browser according to the information provided in the redirect section.

The key-value pairs provided in the parameters section should be attached as GET-Parameters to the given url. This enables the following page to display additional information about the payment status. For example, it may provide data for the remittance account in case of invoice or prepaid payment networks (see Status Notifications for a list of possible keys related to remittance accounts).

Especially for Hosted Integrations in an iFrame, the suppressIFrame flag indicates whether the redirect should happen in the top frame of the browser (true), hence suppressing a potential iFrame. This is required for explicit redirect methods such as PayPal or redirects to one of your pages. Therefore, it should be the default, as it is in optile's hosted page and AJAX library. Only if false is explicitly given, should the redirect  be in the current frame. This can be useful for hosted white label pages by third-party providers.

The bottom response parameters timestamp, operation, resultCode, and identification are intended for enterprise merchants only, you may not need them.

Retry Payment

If there was a potentially recoverable error during payment the following Interaction Codes may appear in the response:

  • TRY_OTHER_NETWORK
  • TRY_OTHER_ACCOUNT
  • RETRY

In this case no redirect section is contained in the CHARGE response >>

In this case you should inform the customer about the failed payment. Depending on the Interaction Code the customer should be asked to select another payment method or provide corrected account information.

  • TRY_OTHER_NETWORK Re-read the LIST object and render the payment page again accordingly, because probably the used network is not available anymore.
  • TRY_OTHER_ACCOUNT  A different payment account should be requested from the customer (it can be the same method, e.g., Visa credit card, but a different account number would be expected). The LIST Object has not changed.
  • RETRY There is some other problem that may require updated account details or to retry this later. The LIST Object has not changed.
Example of Retry Payment Response
 {
  "info": "Invalid holder name",
  "interaction": {
    "code": "RETRY",
    "reason": "UNKNOWN"
  }
}

Localized Error Messages

When integrating our services natively, localized messages can be exhibited by mapping the interaction codes returned by OPG with their respective values provided by our live environment in a resource JSON file:

https://resources.live.nightly.oscato.net/resource/lang/MERCHANT_CODE/language/paymentpage.json

In this URL, two parameters need to be adapted:

  • MERCHANT_CODE: your Merchant Code
  • language: a language code as defined by ISO 3166-1 alpha-2.

The resource file lists the interaction codes and reasons with their related descriptions as organized in the table Possible Interaction Code Values, plus translation for other page elements such as button labels and titles. An extract of the file from https://resources.live.nightly.oscato.net/resource/lang/DEMO_SK/en/paymentpage.json is shown in the right pane for example.

We are continuously working to provide more languages in these resource files, but case a specific language is still not available, OPG will automatically fallback to English.

Extract of Interaction Codes from JSON resource file

{
...
  "button.delete.label": "Delete",
  "button.charge.label": "Pay",
...
  "interaction.RETRY.ACCOUNT_NOT_ACTIVATED": "The account / card seems to be not activated yet. Please activate it or try a different one.",
  "interaction.RETRY.EXCEEDS_LIMIT": "The account exceeded its limit. Please use a different one.",
  "interaction.RETRY.EXPIRED_SESSION": "The payment session has expired. Please go back and return to this step.",
...
}

Reload to Proceed

For some methods with a multi-step flow, e.g. Installment, the Interaction Code RELOAD will be returned. Similar to TRY_OTHER_NETWORK the LIST should be reloaded in this case and displayed again. See ACTIVATE Request for background information.

Redirect to Abort

In some cases (duplicate payment, system failure, fraud detection, session expiration, etc.) the response will advise to interrupt payment process via Interaction Code ABORT.

This will be complemented with a redirect to merchant's Cancel Page, if the cancelUrl parameter was given in the LIST Request.

Similar to successful payment processing if a redirect section is found in the response, you should simply redirect the customer's browser accordingly.

If the reason was a duplicate payment (interaction reason DUPLICATE_OPERATION), i.e., a Charge on a List object after there was already a successful Charge on that List. We recommend that you add a hint for the customer on the Cancel Page, saying that the payment was already done, and only the repetition failed. Otherwise the customer may think the entire payment was denied.

Example of Interrupted Payment Response
 {
  "info": "Allowable retries exceeded",
  "interaction": {
    "code": "ABORT",
    "reason": "FRAUD"
  },
  "redirect": {
    "url": "https://dev.oscato.com/shop/cancel.html",
    "method": "GET",
    "parameters": [
      {"name": "transactionId", "value": "tr101"},
      {"name": "returnCode", "value": "FAILED"},
      {"name": "interactionCode", "value": "ABORT"},
      {"name": "interactionReason", "value": "FRAUD"},
      {"name": "referenceId", "value": "aa1aa-1bb-123-aac-abc"},
      {"name": "longId", "value": "aa1aa-1bb-123-aac-abc"},
      {"name": "shortId", "value": "14335-64676"}
    ],
    "suppressIFrame": false
  }
}

CHARGE Request

The CHARGE Request triggers the actual payment, which was initialized through the preceeding LIST Request. This can be issued from browsers/other clients or servers, depending on the integration scenario. The CHARGE Request submits the customer's payment details (AKA account data). As an option it can contain flags, if the account data should be stored in OPG's Secure Storage, e.g. for Recurring Registration or re-usable Account Registration. All the other data (e.g., amount) the OPG will take from the related LIST Request (which is required before a CHARGE).

Please sign in to view further details of this article. Login

Web Content Display

Validation API

Validation API can be used to validate the payment information entered by the user during checkout. It could also be used for "live validation", i.e. you can validate user input while the user is typing. For that, send the validation request with the data that the user has already entered. This is relevant for Native integrations.

The validation response contains user-friendly messages that should be displayed in front of the input fields , for example, "Correct", "Invalid expiration year", "Missing card number" etc. The messages appear in the language that was specified in the LIST Request.

You can get the validation API endpoint from the LIST Response. The endpoint is unique for each of the payment networks returned.

Example JSON LIST Request

{
  "networks": {
    "applicable": [{
      "method": "CREDIT_CARD"
      "code": "VISA"
      ...
      "links": {
        ...
        "validation": "https://api.sandbox.oscato.com/api/pci/0a15894e-732c-4afb-a6ec-2edd7be4edb8/DEMO/de_DE/VISA/validate"
        ...
      }
    },
    ...
  ],
  ...
}
Validation Request Example
  • URL: https://sandbox.oscato.com/api/pci/0a15894e-732c-4afb-a6ec-2edd7be4edb8/DEMO/de_DE/VISA/validate
  • Method: PUT
  • Basic Authentication:
    • Login Name: UBUY
    • Password: BBtXa7yubR8ipuT
  • Headers:
    • Acceptapplication/vnd.optile.payment.simple-v1-extensible+json
    • Content-Typeapplication/vnd.optile.payment.simple-v1-extensible+json
JSON Request Content
Example JSON Request Content

{
  "holderName": "Jane Doe",
  "expiryYear": "2019",
  "expiryMonth": "3",
  "verificationCode": "123",
  "number": "4111111111111111"
}

The parameter names to send are equal to the input field names of the HTML payment form snippets linked in the LIST Response. For example, the payment form snippet for Visa looks like this (look at the name attribute):

Payment Snippet for Visa

<input id="VISA-number" type="text" name="number" class="text number" autocomplete="off">
<select id="VISA-expiryMonth" name="expiryMonth" class="select expiryMonth">
<select id="VISA-expiryYear" name="expiryYear" class="select expiryYear">
<input id="VISA-verificationCode" type="text" name="verificationCode" class="text verificationCode" autocomplete="off">
<input id="VISA-holderName" type="text" name="holderName" class="text holderName" autocomplete="off">

Commonly used parameter names are (this is not complete list and may change with new payment networks):

  • holderName
  • number
  • expiryMonth
  • expiryYear
  • verificationCode
  • bic
  • iban
Validation Response examples Success

Validation passed

HTTP 200 OK
"valid": true is only returned if all parameters are valid
Valid Response

{
  "valid": true,
  "messages": {...}
}

If the entered values do not pass validation

Empty field value

HTTP 200 OK
Invalid Values

{
  "valid": false,
  "messages": {
    "expiryYear": {
      "message": "Please enter year of expiration"
      "type": "ERROR"
    },
    ...
  }
}



Invalid field value

HTTP 200 OK

{
  "valid": false,
  "messages": {
    "holderName": {
      "message": "Card Holder Invalid!"
      "type": "ERROR"
    },
    ...
}

If your request is malformed

Invalid format of JSON in the request

HTTP 500
Invalid Format of JSON in the Request

{
  "interaction": {
    "reason": "SYSTEM_FAILURE"
    "code": "ABORT"
  },
  "resultInfo": "Internal error: Unexpected character [...]"
}
{

HTTP 500

{
  "interaction": {
    "reason": "SYSTEM_FAILURE"
    "code": "ABORT"
  },
  "resultInfo": "Internal error: Unrecognized field [...]"
}

Validation API

Validation API can be used to validate the payment information entered by the user during checkout. It could also be used for "live validation", i.e. you can validate user input while the user is typing. For that, send the validation request with the data that the user has already entered. This is relevant for Native integrations.

Please sign in to view further details of this article. Login

Web Content Display

Activate Request

For some payment methods with a multi-step flow, most of all instalments, the LIST Response will return the endpoint for an ACTIVATE Request instead of the CHARGE Request. With that, your system will provide a first set of data. Based on this, the LIST object will be updated, and will now include a new input form for the user. It should be reloaded and displayed. The actual CHARGE endpoint will also be contained and should be called as a second step now.

If a method uses the Activation flow and you do not rely on the optile's AJAX or Hosted Integration to take care of it, your implementation should detect this case as follows.

The initial handling of the payment page stays as is. The provided form will be shown to the customer, the entered data submitted to the operation endpoint given in the LIST Response.

If the method uses the Activation Flow you will notice that the endpoint ends in activate instead of charge, but you do not need to detect that in your implementation. The part your system should pay attention to will come in the response.

If the customer can proceed with the checkout, the response will be something like >>

Activation Response

{
  "resultInfo": "Calculation performed successfully.",
    "interaction": {
      "code":"RELOAD",
      "reason":"ACTIVATED"
    }
}

The Interaction Code RELOAD tells your system to reload the LIST Object (via GET on the LIST Resource) and generate the payment page again with its content. The provided form of the activated network has now changed and will request additional information from the customer.

In order to not confuse the customer, the selected flag for this method will now be true, indicating that this method should be preselected and expanded when generating the payment page again.

From there the regular CHARGE process applies again: The form content gets submitted to the operation endpoint given in the LIST Object (which will now end in charge), and the response should be evaluated.

Example of Payolution Installments SEPA:
Step 1: LIST Request

URL: https://api.sandbox.oscato.com/api/lists

Example SEPA Installments LIST Request

{
  "integration" : "DISPLAY_NATIVE",
  "transactionId" : "76jknb5qh39rt4r2vqqoeitte91",
  "country" : "DE",
  "callback" : {
    "returnUrl" : "https://dev.oscato.com/shop/success.html",
    "cancelUrl" : "https://dev.oscato.com/shop/cancel.html",
    "notificationUrl" : "https://dev.oscato.com/shop/notify.html"
  },
  "customer" : {
    "number" : "012345",
    "email" : "whitelist-test@payolution.com",
    "name": {
      "firstName":"Markus",
      "lastName" :"Mustermann"
    },
    "addresses": {
      "billing":{
        "street": "Schlossstraße",
        "houseNumber":"26",
        "city":"Berlin",
        "zip":"12163",
        "country":"DE"
      }
    }
  },
  "clientInfo":{
    "ip":"127.0.0.1"
  },
  "payment" : {
    "reference" : "shop 3490/20-05-14",
    "amount" : 500,
    "currency" : "EUR",
    "invoiceId" : "1110-234-918735",
    "longReference" : {
      "essential" : "Shop #3490 ",
      "extended" : "Thank you for your purchanse!",
      "verbose" : "Support at +49 89 3330303"
    }
  }
}

Expected Response

{
  "links": {
    "self": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l"
  },
  "timestamp": "2016-11-14T10:41:04.919+0000",
  "operation": "LIST",
  "resultCode": "00000.11.000",
  "resultInfo": "1 applicable and 0 registered networks are found",
  "returnCode": {
    "name": "OK",
    "source": "GATEWAY"
  },
  "status": {
    "code": "listed",
    "reason": "listed"
  },
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "identification": {
    "longId": "582994c0e4b0b0d86230c524l",
    "shortId": "15738-35982",
    "transactionId": "76jknb5qh39rt4r2vqqoeitte91"
  },
  "networks": {
    "applicable": [{
      "code": "INSTALLMENT_SEPA",
      "label": "Kauf auf Raten",
      "method": "DIRECT_DEBIT",
      "grouping": "DIRECT_DEBIT",
      "registration": "NONE",
      "recurrence": "NONE",
      "redirect": false,
      "links": {
        "form": "https://resources.sandbox.oscato.com/resource/form/INSTALLMENT_SEPA/standard.html",
        "logo": "https://resources.sandbox.oscato.com/resource/network/MOEBELIX_AT/de_DE/INSTALLMENT_SEPA/logo.png",
        "self": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/INSTALLMENT_SEPA",
        "lang": "https://resources.sandbox.oscato.com/resource/lang/MOEBELIX_AT/de_DE/INSTALLMENT_SEPA.properties",
        "operation": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/INSTALLMENT_SEPA/activate",
        "localizedForm": "https://resources.sandbox.oscato.com/resource/form/MOEBELIX_AT/DE/de_DE/INSTALLMENT_SEPA/standard.html",
        "validation": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/MOEBELIX_AT/de_DE/INSTALLMENT_SEPA/standard/validate"
      },
      "button": "button.activate.label",
      "selected": false
    }]
  }
}
Step 2: Use the Activation URL (operation URL in the LIST Response)

URL: https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/INSTALLMENT_SEPA/activate

Method: POST

Example Activation Request

{
"account" : {
  "customerBirthDay" : "1",
  "customerBirthYear" : "1991",
  "customerBirthMonth" : "1",
  "optIn" : "true"
  }
}

Expected Activation Response

{
  "resultInfo": "Calculation performed successfully.",
  "interaction": {
    "code": "RELOAD",
    "reason": "ACTIVATED"
  }
}

Step 3: Reload LIST

URL: link.self (you find that link in the LIST Response)

Example: https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l

Method: GET which return the Installment Plans

Example Reload List

{
  "links": {
    "self": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l"
  },
  "resultInfo": "1 applicable and 0 registered networks are found",
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "networks": {
    "applicable": [{
      "code": "INSTALLMENT_SEPA",
      "label": "Kauf auf Raten",
      "method": "DIRECT_DEBIT",
      "grouping": "DIRECT_DEBIT",
      "registration": "NONE",
      "recurrence": "NONE",
      "redirect": false,
      "links": {
        "form": "https://resources.sandbox.oscato.com/resource/form/INSTALLMENT_SEPA/activated.html",
        "logo": "https://resources.sandbox.oscato.com/resource/network/MOEBELIX_AT/de_DE/INSTALLMENT_SEPA/logo.png",
        "self": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/INSTALLMENT_SEPA",
        "lang": "https://resources.sandbox.oscato.com/resource/lang/MOEBELIX_AT/de_DE/INSTALLMENT_SEPA.properties",
        "operation": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/INSTALLMENT_SEPA/charge",
        "localizedForm": "https://resources.sandbox.oscato.com/resource/form/MOEBELIX_AT/DE/de_DE/INSTALLMENT_SEPA/activated.html",
        "validation": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/MOEBELIX_AT/de_DE/INSTALLMENT_SEPA/activated/validate"
      },
      "button": "button.charge.label",
      "selected": true,
      "formData": {
        "installments": {
          "originalPayment": {
            "amount": 500,
            "currency": "EUR"
          },
          "plans": [{
            "id": "c363bb5d-f831-4c98-8482-cdbc8abc00a4",
            "schedule": [{
              "amount": 167.84,
              "date": "2016-12-04T23:00:00.000+0000"
            },{
              "amount": 167.84,
              "date": "2017-01-04T23:00:00.000+0000"
            },{
              "amount": 167.84,
              "date": "2017-02-04T23:00:00.000+0000"
            }],
           "currency": "EUR",
           "installmentFee": 0,
           "totalAmount": 503.52,
           "nominalInterestRate": 4.95,
           "effectiveInterestRate": 5.05,
           "creditInformationUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d0PcuR2eVe5q/CreditInformation.pdf",
           "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d15t21a5zw8r/TermsAndConditions.pdf",
           "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d2t7hcATneYD/DataPrivacyConsent.pdf"
         },{
         "id": "c03e403e-a1c0-4082-8dcd-42399e5665ea",
         "schedule": [{
           "amount": 84.43,
           "date": "2016-12-04T23:00:00.000+0000"
         },{
           "amount": 84.43,
           "date": "2017-01-04T23:00:00.000+0000"
         },{
           "amount": 84.43,
           "date": "2017-02-04T23:00:00.000+0000"
         },{
           "amount": 84.43,
           "date": "2017-03-04T23:00:00.000+0000"
         },{
           "amount": 84.43,
           "date": "2017-04-04T22:00:00.000+0000"
         },{
           "amount": 84.43,
           "date": "2017-05-04T22:00:00.000+0000"
         }],
         "currency": "EUR",
         "installmentFee": 0,
         "totalAmount": 506.58,
         "nominalInterestRate": 4.95,
         "effectiveInterestRate": 5.06,
         "creditInformationUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d3iBeZYNpTI5/CreditInformation.pdf",
         "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d4k3JJ3ilyEp/TermsAndConditions.pdf",
         "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d5PIp6I9jORR/DataPrivacyConsent.pdf"
         },{
         "id": "4fda7671-8565-4dc8-9105-2c2a54fadfbe",
         "schedule": [{
           "amount": 56.63,
           "date": "2016-12-04T23:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-01-04T23:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-02-04T23:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-03-04T23:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-04-04T22:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-05-04T22:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-06-04T22:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-07-04T22:00:00.000+0000"
         },{
           "amount": 56.63,
           "date": "2017-08-04T22:00:00.000+0000"
         }],
         "currency": "EUR",
         "installmentFee": 0,
         "totalAmount": 509.67,
         "nominalInterestRate": 4.95,
         "effectiveInterestRate": 5.05,
         "creditInformationUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d6bWXLcTWp5Q/CreditInformation.pdf",
         "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d7zXd7FoIceb/TermsAndConditions.pdf",
         "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d89Jj4fIYI72/DataPrivacyConsent.pdf"
       },{
         "id": "17ee461d-8e1d-4f8f-b1d2-95ff3ad24e91",
         "schedule": [{
           "amount": 42.74,
           "date": "2016-12-04T23:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-01-04T23:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-02-04T23:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-03-04T23:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-04-04T22:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-05-04T22:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-06-04T22:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-07-04T22:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-08-04T22:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-09-04T22:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-10-04T22:00:00.000+0000"
         },{
           "amount": 42.74,
           "date": "2017-11-04T23:00:00.000+0000"
         }],
         "currency": "EUR",
         "installmentFee": 0,
         "totalAmount": 512.88,
         "nominalInterestRate": 4.95,
         "effectiveInterestRate": 5.08,
         "creditInformationUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6d9ETOlzIfSMw/CreditInformation.pdf",
         "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6daYpicMFJ0eA/TermsAndConditions.pdf",
         "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/MOEBELIX_AT/PAYOLUTION/582994d8c3a614600a9bb6dbV4AgV5fise/DataPrivacyConsent.pdf"
         }]
        }
      }
    }]
  }
}
Step 4: CHARGE Request

URL: https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/INSTALLMENT_SEPA/charge (use the operation URL from the Reloaded LIST in Step3)

Method: POST

CHARGE Request Example >>

You need to choose the planID of the desired Installment Plan in Step 3.
Example CHARGE Request

{
  "account" : {
    "installmentPlanId" : "c03e403e-a1c0-4082-8dcd-42399e5665ea",
    "holderName" : "Jane Doe",
    "bankCode" : "PBNKDEFF",
    "iban" : "DE89370400440532013000"
  }
}
Handling Activate networks in selective Native/Native integration

If one chooses to implement Sepa Instalments in a Selective Native or Native implementation, then there is a small amount of effort required to render the process on the front end.

After the initial LIST Request is made with Selective Native or Native as the implementation parameter the LIST Response  will contain a series of applicable networks each with an associated localized form (or frame if it is selective native and a credit card network).  These html snippets (or iframes in selective native) should then be used to render the front end presented to the customer for each payment network.

These localised forms will contain {form-id} placeholders that need to be replaced with the network.code (highlighted in fig 1) value of the payment network. This can be accomplished easily using JavaScript. See the section 'Populating form snippets' in the Localized Form document for a simple approach to illustrate this. Also ‘network code' and ‘self' link should be saved as data attributes in the html element displaying the localised form as they will be needed later in the sepa-installment process.

After this replacement happens a form  asking the customer to enter his/her date of birth will be displayed. If the year of birth field is empty it means that the JavaScript in the html snippet didn't execute and you should recheck your placeholder injection.

On submit the front end should make a call to the operation url returned in the previous LIST Response (illustrated earlier in this article). Opposite is some sample javascript to illustate this submit process.

Example JarvaScript Submission Process

// .... Other code here.....
var data = $(this).serializeFormJSON($(formId).serializeArray());

var postRequest = {};
postRequest.account = data;

// Note the optIn checkbox saves as ‘on' rather than true but request expects a boolean
if(postRequest.account.optIn != null)
 postRequest.account.optIn = true;

var jsonString = (JSON.stringify(postRequest))

$.ajax({
  url: actionUrl, // the operation link for this network from original LIST
  type: 'post',
  contentType: "application/json; charset=utf-8",
  dataType: 'json',
  data: jsonString,
  success: function (response)
  {
  // .... Other code here.....



//******* Serialise a form's values *******

$.fn.serializeFormJSON = function (a) {
  var o = {};
  //var a = this.serializeArray();
  $.each(a, function () {
    if (o[this.name]) {
    if (!o[this.name].push) {
      o[this.name] = [o[this.name]];
    }
      o[this.name].push(this.value || '');
    } else {
      o[this.name] = this.value || '';
        }
    });
    return o;
};

On the call-back the response should be checked to see if it was successful. If the response was successful it will prompt that the form should be reloaded. This can be accomplished by using the self link for the payment network returned in the original response (see example above).

If it was unsuccessful then this information can be displayed to the user.

After the reload ((*) in JavaScript sample opposite) the form will now be in an activated state and the operation from the new RELOAD response will be the end CHARGE URL (see sample JSON earlier in this section). This can be used for the end submit action for the next form request. The ACTIVATION (reload) response will also contain a series of instalments that need to be used to populate dropdown values in the new localised form html snippet.

Repeat the {form-id} replacement process to load the network code into the localised form snippet and additionally at this stage, because the activated SEPA-Instalment form needs the drop down of potential rates to be populated and handled, an additional piece of JavaScript is required ((**) in JavaScript sample opposite). This is accomplished by finding the name of the postCreate function in the form snippet that is associated with the localised snippet's fieldset. There is a placeholder for formData there that can be populated with the instalments returned by the last LIST Request ((***) in JavaScript sample opposite).

At this stage the completely rendered form snippet will be displayed on the frontend and the included JavaScript will handle the form changes.

JavaScript

$.get(listSelf, function (response) {
  // (*) Set new form action url
  submitAction = response.links.operation;  // url to submit to
  srcToLoad = response.links.localizedForm; // get form source
  formData = response.formData; // get form data

  // Load localised activated form
  $.get(srcToLoad, function (response) {
    var formToPostToName = $('input[name=paymentNetworks]:checked').val() + "Form";
    var selectedForm = '#' + formToPostToName;
    var snippetId = $(selectedForm).attr("data-snippetId");
    var elementToUpdate = $('#' + snippetId);

    // (**) Load the form snippet into the div
    var htmlToInjectIntoSnippet = opTemplateEngine(response, {formId:code});

    // Find the name of the postcreate function to call. This will always be in the fieldset of the injected localised form if it is present
    var postCreateFunctionName = $('#' + code + "-fieldset").attr("postCreate");

    if(postCreateFunctionName != null) {
      // (***) Inject the postcreate function call with the formData from the response
      htmlToInjectIntoSnippet = htmlToInjectIntoSnippet.replace("<script>", "<script> " + postCreateFunctionName + "(" + JSON.stringify(formData) + ");");
    }

    elementToUpdate.html(htmlToInjectIntoSnippet);
  });
});

On submittal of the above form it's data should be serialised and submitted as part of the CHARGE Request. The process will then be complete. See opposite for sample Javascript to handle this.

JavaScript for CHARGE Request

// Submit
var data = $(this).serializeFormJSON($(formId).serializeArray());
// ...... other code ......
var postRequest = {};
postRequest.account = data;
// ...... other code ......

var jsonString = (JSON.stringify(postRequest))

$.ajax({
  url: actionUrl,
  type: 'post',
  contentType: "application/json; charset=utf-8",
  dataType: 'json',
  data: jsonString,
  success: function (response)
  {
        // ...... handle response here ......

Activate Request

For some payment methods with a multi-step flow, most of all instalments, the LIST Response will return the endpoint for an ACTIVATE Request instead of the CHARGE Request. With that, your system will provide a first set of data. Based on this, the LIST object will be updated, and will now include a new input form for the user. It should be reloaded and displayed. The actual CHARGE endpoint will also be contained and should be called as a second step now.

Please sign in to view further details of this article. Login

Web Content Display

Selective Native Integration

This section is intended to cover a complete native implementation of the Selective integration scenario, without using any library. For instructions on how to use our library in your implementation, please go to the section AJAX Library Integration.

LIST Response

If you implement this yourself, first of all your system should be aware of the following behavior of the LIST Response in order to generate the payment page (be it client- or server-side).

For each method in accounts or networks.available that falls under the scope of PCI DSS (i.e., for credit and debit cards) the LIST Response will not provide the links form and localizedForm anymore, so that your system cannot include the HTML snippets for the corresponding forms directly, even if you forget to change the implementation.

Instead it will provide the URL to the iFrame in links.iFrame and the suggested height of the iFrame (in px) in the iFrameHeight attribute. As a result an object representing a payment method would look something like this:

Your system should place the iFrame into the payment page with these parameters >>

Example of LIST Response

...
  "networks": {
    "applicable": [{
      "code": "VISA",
      "label": "Visa",
      "method": "CREDIT_CARD",
      "grouping": "CREDIT_CARD",
      "registration": "OPTIONAL",
      "recurrence": "NONE",
      "redirect": false,
      "links": {
        "iFrame": "https://resources.live.oscato.com/paymentpage/iframe.html?listId=57c03359e4b0c50a7e8007cfl&network=VISA",
        "logo": "https://resources.live.oscato.com/resource/network/UBUY/de_DE/VISA/logo.png",
        "self": "https://api.live.oscato.com/api/lists/57c03359e4b0c50a7e8007cfl/VISA",
        "lang": "https://resources.live.oscato.com/resource/lang/UBUY/de_DE/VISA.properties"
      },
      "button": "button.charge.label",
      "selected": false,
      "iFrameHeight": 165
      },
      ...]
  },
...
Inter-Frame Communication

Web browsers will not allow direct access into the iFrames from the outside (the surrounding page). However, in the standard version of Selective Native the submit button is still outside, on the payment page. Therefore we need predefined messages that can be exchanged between the frames.

In short, the essential messages are:

  • validation_response_event Sent from the iFrame to the outer page to reflect whether there is valid account information entered so that the outer page can enable/disable the Pay button (for optimized user experience).
  • payment_action Sent from the outer page to the iFrame as soon as the Pay button is pressed, telling the iFrame to do a final validation and submit the payment operation request.
  • operation_response_event Returns the response of a payment operation request from the iFrame to the outer page.

Inter frame communication

Live Validation and Payment Button

To provide an excellent user experience Live Validation of the data entered by the user should be enabled (it is by default in the iFrames), and the Pay button should be disabled as long as the entered data is not formally valid.

This means that your page should decide whether to enable or disable the button, every time the user selects a payment method and when the payment page is generated. If the selected method has a plain form (without iFrame), which contains a <fieldset> element or it contains an iFrame form, disable the button for now (if there is data entered already do a validation right away, see below). Otherwise enable the button which is required for methods that do not require any input on this page (e.g., PayPal).

Furthermore, your page should do a Live Validation of the entered data for methods with plain forms. For example, when the user stops typing for a moment or leaves the input field. This is especially important since your payment button will be disabled in the first place in these cases. If the response signals "valid": true then the payment button should be enabled, otherwise disabled (again) and the hints shown next to the corresponding input field(s).

Inter-Frame communication comes into play if the selected method is subject of PCI and therefore provides an iFrame instead of a plain, embeddable form. By default the iFrame will do Live Validation itself and display hints accordingly in the form. Also the iFrame will send the result to the outer page in the form of an validation_response_event. Your page should listen to this message and enable/disable the payment button accordingly.

Here is some JavaScript / jQuery example code >>

Note that event.data["response"] contains the full data structure of the Live Validation Response. This means, for example, that event.data["response"]["valid"] corresponds to the valid attribute from the direct API response.

You can disable Live Validation of the iFrames by requesting them with a liveValidation=false query parameter, for example:

https://resources.live.oscato.com/paymentpage/iframe.html?listId=57c03359e4b0c50a7e8007cfl&network=VISA&liveValidation=false
If you have not implemented Live Validation in your page, you should do this to save bandwidth for your users and the OPG.
JavaScript / jQuery Example Code

// The expected origin of the iFrames:
// Differentiate between Live and Sandbox here!
var opg_origin = 'https://resources.live.oscato.com/';

// Listener for validation_response_event message:
window.addEventListener("message", function (event) {
  if (event.origin === opg_origin) {
    if (event.data["type"] === "validation_response_event") {
      var response = event.data["response"];
      if (response["valid"]) {
        // Adjust the ID of your submit button accordingly:
        $("#submitBtn").prop("disabled", false);
      } else {
        $("#submitBtn").prop("disabled", true);
      }
    }
  }
}
Method Detection (Smart Switch)

With Smart Switch your customers do not have to select their credit card brand explicitly, but it will be detected automatically.

To enable this feature with Selective Native you open the iFrame of a credit card form with the added parameters smartSwitch=true and networks (plural, not network) with a list of credit cards codes (corresponding to the credit cards of your configuration), for example:

https://resources.live.oscato.com/paymentpage/iframe.html?listId=57c03359e4b0c50a7e8007cfl&smartSwitch=true&networks=VISA,MASTERCARD,AMEX

An iFrame that is integrated like this will detect the credit card scheme of the entered number while typing and send the detection result to the parent frame in the form of a detection_response_event. It can be consumed as the other response events and has always the following structure >>

The method attribute will reflect the detected method from the list that was given as URL parameter. If none of those was detected, the value will be null.

JSON Credit Card Codes Example

{
  "type": "detection_response_event",
  "response": {
    "method":"VISA"
  }
}
Payment Execution

The payment_action message should be sent from the outer page to the iFrame when the Pay button is pressed, telling it to do a final validation (using the same call as Live Validations). If final validation succeeds, then directly submit the card data to the OPG for payment. At this point also the Pay button should be disabled, and ideally a spinner should be shown, to indicate that the user now has to wait for feedback. When the response arrives, the result will be sent as a separate message from the iFrame to the outer page again.

In case the validation fails, there will be a validation_response_event message as shown above. This should be a very rare case if you implemented the enabled / disabled  Pay button correctly. This is because the button will only be enabled if the validation succeeded already (see above). Though it could still happen, e.g., due to race conditions. In any case there is nothing to do at this point, because the Pay button should be disabled after the payment action and stay disabled. Only the updated validation hints will be shown in the iFrame.

If the validation succeeds, the iFrame will execute the payment operation (e.g., CHARGE) and the response will be sent as operation_response_event message from the iFrame to the outer page. That means on the page there should be a listener for this event, which takes the response data and reloads or redirects the user according to CHARGE Response.

Only one response event will be sent as a result of a payment_action.

Here is some JavaScript / jQuery example code you can use to get started. It is an extension of the above example code >>

For message type operation_response_event, event.data["response"] will hold the entire CHARGE Response. That means you can get the Interaction Code with event.data["response"]["interaction"]["code"], or the potential redirect URL with event.data["response"]["redirect"]["url"] and so forth.

With this data at hand all that is left to do is to react on the response, as described under CHARGE Request.

Advanced Use Cases

Specific Actions:

In addition to the payment_action message also these messages can be sent to the iFrame:

  • validation_action Will trigger an explicit Validation of the payment account data currently present in the form and will cause a validation_response_event as soon as the validation was completed (see above).
  • operation_action Will trigger the payment operation directly (i.e., without extra validation) with the currently entered payment account data and this will cause an operation_response_event as soon as the operation was completed (see above). This could be used instead of the payment_action if the iFrame does Live Validation in order to avoid the delay of one extra validation.

Since the already described payment_action combines these two actions, it can therefore possibly result in the two different response events.

Action IDs

In principle all requests are subject to race conditions. Therefore your page can assign IDs to actions that will be returned with the corresponding response event. This way your implementation could detect messages that overtook other messages.

You can set and read this ID in the attribute action_id, so you could:

selected_iframe.postMessage({"type": "validation_action", "action_id": "42"}, opg_origin);

You can access the value in the response event through event.data["action_id"] and thereby match the response to its original request.

If your implementation does not do repeated action requests, this would not be neccessary.

Example JavaScript Code

// The expected origin of the iFrames:
// Differentiate between Live and Sandbox here!
var opg_origin = 'https://resources.live.oscato.com/';

// Sending the opg_submit message on button click:
// Replace "#submitBtn" with the actual ID of your submit button here!
$("#submitBtn").onclick = function() {
  // Get iFrame for the currently selected radio button. Only works for non-grouped forms:
  selected_iframe = $("#paymentNetworks input[type=radio][name=paymentType]:checked ~ .formContainer iframe").contentWindow;
  selected_iframe.postMessage({"type": "payment_action"}, opg_origin);
  // Disable Pay button and show a spinner to indicate to the user that this may take a while...
}

window.addEventListener("message", function (event) {
  if (event.origin === opg_origin) {
    // Listener for operation_response_event message:
    if (event.data["type"] === "operation_response_event") {
      var response = event.data["response"];
      if (response["interaction"]["code"] == "PROCEED" || response["interaction"]["code"] == "ABORT") {
        // Continue with redirecting
        // ...
      } else {
        // Continue with reloading and displaying error message
        // ...
      }

    // Now the validation listener from above follows:
    } else if (event.data["type"] === "validation_response_event") {
      var response = event.data["response"];
      if (response["valid"]) {
        // Adjust the ID of your submit button accordingly:
        $("#submitBtn").prop("disabled", false);
      } else {
        $("#submitBtn").prop("disabled", true);
      }
    }
  }
});
Styling and translating frames

The frame snippets presented to the user can be styled and translated. To do this simply pass in the desired language and cssOverride URL in the style attribute in the original LIST Request. Afterwards the frame will have its contents translated and the style applied. See the screenshot below for a simple example where the frame has been translated to French and has been styled to have a dark gray background and heavy bold text.

Example CSS

"style":
{
  "language": "fr_FR",
  "cssOverride": "https://ADDRESS_HERE/CSS_FILE_NAME.css",
},

The css file in this example simply contains the following:

body
{
  background-color: darkgray;
  font-weight: 900;
}

Implementing Payment Methods outside the PCI Scope

If you wish to use Selective Native to implement other payments methods (other than Credit Cards) then you may want to use optile's localized forms snippets returned from the original LIST Response. You can learn more about implemeting these localized forms.

Implementing Recurring Charge and Payment Registration for Selective Native Frames

As the frame that handles the payment does not contain checkboxes for registering payments or allowing an input payment method to be used in recurring payments these will have to be handled outside the frame.

The checkbox will have to be rendered after the frame and then on submit the values of these checkboxes can be used to in the frame's post message request to specify if this payment method is to be registered or used for recurring charges. In the example opposite the values allowRecurringPayment and allowPaymentRegistration will have been retrieved from the checkboxes via JavaScript.

Please see the section in localised forms documentation titled displaying registration checkboxes for a more complete overview of this topic.

JavaScript Code

// make post to frame
frameToPostTo.postMessage({
  "type": "payment_action",
  "request": {
    "allowRecurrence": allowRecurringPayment,
    "autoRegistration": allowPaymentRegistration }},
  opg_origin);

Selective Native Integration

This section is intended to cover a complete native implementation of the Selective integration scenario, without using any library. For instructions on how to use our library in your implementation, please go to the section AJAX Library Integration.

Please sign in to view further details of this article. Login

Web Content Display

Client Side Encryption

Here we present in detail the integration process of Client Side Encryption into your services. For an introductory view of our Client Side Encryption flow, please head to Integration Scenarios session, Pure Native with CSE.

OPG Integration

Integration package content

The integration packages are available as zip files here:

Inside it, next to the root files with development meta information, you will find the following folders:

  • demo: contains an html file you can view locally to interactively test the encryption of custom account data with public keys (see below). There is no server/OPG interaction here.
  • dist: contains the actual distributable encryption library in ready-to-use minified format:
    • op-client-side-encryption1.x.y.min.js The versioned filename which we recommend to use in order to easily keep track of version changes.
    • op-client-side-encryption.min.js A copy without versioning in its file name to represent the latest version. Could be used for on-the-fly upgrades of the library, which requires more careful management.
  • src: the development source files
LIST Request

For the LIST Request, please use the following integration parameter, as for the Pure Native integration scenario:

"integration": "PURE_NATIVE"

If you submit encrypted account data using any other integration scenario (including the default) you will receive an error saying: "Unrecognized JSON property 'encryptedAccount'…"

Get the Payload

Once the user has entered the payment account data, the client is expected to build a JSON object from it and then encrypt it. The attribute names contained in this object are the same as the input field names used in the equivalent HTML form from optile's form-based API. In other words, the object should have the same attributes that are used in the optile account object used for CHARGE Requests.

The most common attributes for Charges are:

  • number
  • holderName
  • verificationCode
  • expiryMonth
  • expiryYear
  • IBAN
  • BIC

This payload should be encrypted as described on the side panel.

Card Account Data Example Object

{
  "holderName": "John Doe",
  "number": "5500000000000004",
  "verificationCode": "123",
  "expiryMonth": "12",
  "expiryYear": "2022"
}

Encrypt with the optile JavaScript Library

The minified JavaScript encryption library can be included in your web page, either by directly loading it in a <script> tag, or through require or import. In technical terms, the library provides an asynchronous API to encrypt user data according to the standards mentioned below.

The library exports the function: opEncrypt(accountPayload, publicKey, [timestamp], [listId])

This function returns a Promise Object (also called a "thenable"), which resolves to the encrypted string through its callback. This string is the encrypted data structure that you can send through your server to the OPG. We chose this implementation path to make the library compatible for a wide variety of use-cases, including server side use and advanced client usage scenarios that profit from an asynchronous programming style.

Input Parameters
  • accountPayload: the JavaScript object (not a string) with any of the attributes available in the optile account object used for CHARGE Requests
  • publicKey: the public key in JSON Web Key (JWK) format (as JavaScript object), which you received from optile previously.
  • timestamp (optional): the timestamp of the encryption. If it is not given or given as null, the current client time is used as default and added to the payload. Input format is ISO, e.g. "2017-09-26T08:41:01.859Z".
  • listId (optional): the longId of the OPG LIST session on which the Charge would be executed. listId is an optional parameter, and will therefore also not be included into the payload, if it is not given.
Return Value

The function returns a Promise instance which resolves to a string containing the JSON Web Encryption (JWE) encoded account data. This string is the data that can be passed on to the OPG.

Example Usage

function submitCard(timestamp, listId) {
  // listId needs to identify the LIST session to be used for this transaction
  // timestamp is used to identify the encryption time
  opEncrypt(
    {
      "holderName":       document.getElementById("holderName").value,
      "number":           document.getElementById("number").value,
      "verificationCode": document.getElementById("verificationCode").value,
      "expiryMonth":      document.getElementById("expiryMonth").value,
      "expiryYear":       document.getElementById("expiryYear").value
    },
    {
      "kty": "RSA",
      "n": "2UEvEj1-cUxF5ri-pXUhHIn-QNxiz6B4lWWvnK-RqZrMQQ_VSYiUfgkosydIp4-zrKzI5PbkWar1dYo3PcAfkZn1ZNTdxC4sMb3TEWJmbKZHh9C6fD4YsY6euTrSBKMC-aa1a7r0nUEzFQ6-7bKAfoOQKkrvIq6ecbTlcqNOAJX6aFJJ1bWmp7gTtG4ncYgtf_Q8nszgSMbe8hiIly4nwYwAxtdjxuOypcEx7I350VdCzTz-eN0rAnclT_-cv8P8J-JkS3yJVUlWeKaGeTtZB5-ZJHpDEUpOb9yc_NHKuxj5L9A-FemVUq606tBTG92yQU711Crf03CQ8-jbZyudkNYVQ",
      "e": "AQAB"
    },
    timestamp,
    listId
  ).then((encrypted_payload) => {
      // encrypted_payload contains the data to be sent to your server.
      // Send via asynchronous HTTP, for example,
      // or as a form submit with a hidden field "optile_encrypted":
      document.getElementById("optile_encrypted").value = encrypted_payload;
      document.getElementById("sendform").submit();
  }).catch((error) => {
      // handle errors may encountered during encryption
      console.log(error);
  });
}

Server Side CHARGE Request

Your server in turn sends the payment account data in an (authenticated) CHARGE Request to the OPG. The parameter to hold that data string is called encryptedAccount (which replaces the account object of a regular CHARGE Request). Note, that registration flags are still given in an unencrypted way.

The LIST session for that CHARGE transaction needs to correspond to the listId used during encryption. For security reasons the encrypted card data will not work with any other LIST sessions. The response from the OPG will be the same as with an unencrypted CHARGE Request.

Please make sure that you never send unencrypted card data to your server systems.

Example CHARGE Request Body

{
  "encryptedAccount": "VGhpcyBpcyB0aGUgZW5jcnlwdGVkIGFjY291bnQgZGF0YSBpbi...",
  "allowRecurrence": true
}


Encryption Details

Here are additional details, for example in case you want to approach building your own encryption client. But you won't need the following information if you just want to use the JavaScript encryption library provided by optile.

The encrypted content is transmitted as a RFC7516 JWE (JSON Web Encryption) data structure in JWE Compact Serialization format. All of the user's input (see above) is encoded in key/value pairs in the encrypted JWE JSON payload. optile only supports AES256-GCM with RSA-OAEP as the encryption scheme. Therefore, the JOSE header will always look like this:

{ "alg": "RSA-OAEP", "enc": "A256GCM" }

It's base64 representation will accordingly always be:

eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ

As specified by RFC7516...

  • the JOSE header,
  • the RSA-OAEP encrypted symmetric content encryption key,
  • the randomly chosen encryption initialization vector,
  • the AES256-GCM encrypted payload JSON object literal with the above JOSE header passed into the encryption operation as "additional authenticated data",
  • and the resulting AES256-GCM authentication tag output…

…are each base64 encoded and concatenated using a "." character as separator. The resulting string is the one that must be sent to your server and then passed on to the OPG.

Client Side Encryption

Here we present in detail the integration process of Client Side Encryption into your services. For an introductory view of our Client Side Encryption flow, please head to Integration Scenarios session, Pure Native with CSE.

Please sign in to view further details of this article. Login

Web Content Display

Backend Use Cases

Web Content Display

Refunds & Cancelations

Successfully processed Charges can, generally, be refunded up to 6 months after they have been issued (the conditions of PSPs may vary). Partial and multiple refunds are possible with the OPG, if they are also supported by the PSP. If the Charge is in the status pending / processing_scheduled it can be canceled instead of refunded, which has different implications, see end of this chapter.

After a CHARGE Request was completed, you have a transaction that can be refunded by issuing a POST request its payout URL, which references its longId. The following example will show how it is done.

Payout requests generally only require a payment data structure including the amount that is to be refunded. With some PSPs you may also be able to submit an empty payout request translating to a full refund. However, with other PSPs this does not work with partial refunds that may have been issued beforehand, therefore, we do not recommend this. You are on the safe side if you always specify the amount to be refunded.

In some cases it may be necessary to specify which products are refunded (e.g., if you use invoice payments). To do that you can specify a products array after the payment structure, similar to the product information you provide in an extended LIST Request. It is important to note that with most PSPs you will get an error if you try to refund products that were not specified during the initial checkout.

First partial Refund example

Suppose the initial checkout Charge had an amount of 19.99 € and got the longId value 26d5b179-a3b5-4aa3-ad98-3074b41e7d2b. From that you build the payout URL and post an amount less than the original amount (partial refund) as follows:

Example Request
  • URL: https://api.live.oscato.com/api/charges/26d5b179-a3b5-4aa3-ad98-3074b41e7d2b/payout
  • Basic Authentication: UBUY:BBtXa7yubR8ipuT
  • Method: POST
Example Partial Refund Request
{
  "payment": {
    "amount": 5.00,
    "currency":"EUR",
    "reference":"Refund 472"
  }
}
Example Response
{
  "interaction":{
    "reason":"OK",
    "code":"PROCEED"
  },
  "resultInfo":"Approved",
  "links":{
    "self":"https://api.live.oscato.com/api/payouts/fced7bd9-5489-4466-988c-83d2548a075a"
  }
}

Note that in Pure Native integrations you will get a more elaborate response like:

{
  "links": {
    "self": "https://api.live.oscato.com/api/payouts/54aea1bae4b005fbaf09f5f4o"
  },
  "timestamp": "2015-01-08T15:26:51.838+0000",
  "operation": "PAYOUT",
  "resultCode": "00000.WIRECARD.0",
  "resultInfo": "Approved",
  "status": {
    "code": "paid_out",
    "reason": "refund_credited"
  },
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "clearing": {
    "amount": 5,
    "currency": "EUR"
  },
  "identification": {
    "longId": "54aea1bae4b005fbaf09f5f4o",
    "transactionId": "tr101",
    "providerId": "C979816142073082263267"
  }
}
Second, remaining Refund

We issue a second refund that covers the remainder of the Charge amount. After that the customer will be fully refunded.

Example Request
  • URL: https://api.live.oscato.com/api/charges/26d5b179-a3b5-4aa3-ad98-3074b41e7d2b/payout
  • Basic Authentication: UBUY:BBtXa7yubR8ipuT
  • Method: POST

If your PSP does not support partial or multiple refunds for a one payment transaction, you should get an error like: "Multi-refund is not supported".

Example Remaining Refund Request
{
  "payment": {
    "amount": 14.99,
    "currency": "EUR",
    "reference": "Refund 473"
  }
}
Example Response
{
  "interaction":{
    "reason":"OK",
    "code":"PROCEED"
  },
  "resultInfo":"Approved",
  "links":{
    "self":"https://api.live.oscato.com/api/payouts/bef25df3-0d24-412c-805c-fd686821ef6e"
  }
}
Third, exceeding Refund

If your refund amount exceeds the originally charged amount, you will get an error from the OPG. To demonstrate, we issue a third "partial" refund on the same Charge, that was already fully refunded.

Example Request
  • URL: https://oscato.com/api/charges/26d5b179-a3b5-4aa3-ad98-3074b41e7d2b/payout
  • Basic Authentication: UBUY:BBtXa7yubR8ipuT
  • Method: POST

In the case you need to create an 'exceeding Refund' and your PSP supports it, the validation on the OPG should be turned off. Please contact us in this case.

Example Exceeding Refund Request
{
  "payment": {
    "amount": 20.00,
    "currency":"EUR",
    "reference": "Refund 474"
  }
}
Example Response
{
  "links": {
    "self": "https://api.live.oscato.com/api/payouts/54aea1dce4b005fbaf09f5f5o"
  },
  "timestamp": "2015-01-08T15:27:24.854+0000",
  "operation": "PAYOUT",
  "resultCode": "50100.11.000",
  "resultInfo": "Effective balance of charge process is less than requested payout amount",
  "status": {
    "code": "failed",
    "reason": "refund_failed"
  },
  "interaction": {
    "code": "RETRY",
    "reason": "UNKNOWN"
  },
  "identification": {
    "longId": "54aea1dce4b005fbaf09f5f5o",
    "transactionId": "tr101"
  }
}
Include refunded Products

Some PSPs require that you also list the products which are to be refunded. Just make sure that the product.code and amount (with respect to quantity) of the refunded products match with those from the original CHARGE Request. If the Payment Gateway finds a product with the same code but the amount does not match, it will return an error.

Example Request
  • URL: https://api.live.oscato.com/api/charges/26d5b179-a3b5-4aa3-ad98-3074b41e7d2b/payout
  • Basic Authentication: UBUY:BBtXa7yubR8ipuT
  • Method: POST

The products list behaves exactly as in extended LIST Requests. Therefore the quantity is optional and defaults to 1, and the amount is the sum after considering the quantity.

The response and behavior in respect to partial ('multi') refunds is equivalent to those from simple Refund scenarios.

Example Refund with Product List
{
  "payment": {
    "amount": 22.40,
    "currency": "EUR",
    "reference": "Refund 202/01"
  },
  "products": [{
    "code": "B003X6UEXQ",
    "name": "Tron Legacy BluRay",
    "quantity": 1,
    "amount": 12.50
  },{
    "code": "C003X6U523",
    "name": "The Lawnmower Man DVD",
    "quantity": 1,
    "amount": 9.90
  }]
}

Cancelation

Refunds can be applied if a Charge has been processed by the provider. However, there are situations where a Charge is queued on the provider side (or optile side) before it gets processed. The reason for this is often a provider-internal batch processing schedule. In this situation the provider typically allows to cancel this transaction. In optile's status space such a transaction will have the Status Code pending and the Status Reason processing_scheduled.

Canceling such a transaction means that it will not be processed by the provider, therefore typically no processing fees will apply, and the end customer will not see any related transaction on their account statements (as opposed to refunds where a debit and a credit will typically be visible). In most cases a cancelation can only be done completely. If you want to return a partial amount, you can wait until the Charge was processed and then do a partial refund instead.

To request the cancelation send an HTTP DELETE request (without a body) to the CHARGE resource (as accessible by its links.self URL).

Example Request

  • URL: https://api.live.oscato.com/api/charges/26d5b179-a3b5-4aa3-ad98-3074b41e7d2b
  • Basic Authentication: UBUY:BBtXa7yubR8ipuT
  • Method: DELETE

A successful cancelation will return an HTTP 2xx return code. Otherwise it means it failed.

A cancelation can fail if, for example, the transaction was already locked by the provider because it's about to be processed. The best strategy in such a situation is to wait until the payment was processed, and then issue a normal refund.

Note that this cancelation works similar to the cancelation of a Deferred Charge, but the underlying situation / status of the transaction is different.

Refunds & Cancelations

Successfully processed Charges can, generally, be refunded up to 6 months after they have been issued (the conditions of PSPs may vary). Partial and multiple refunds are possible with the OPG, if they are also supported by the PSP. If the Charge is in the status pending / processing_scheduled it can be canceled instead of refunded, which has different implications, see end of this chapter.

After a CHARGE Request was completed, you have a transaction that can be refunded by issuing a POST request its payout URL, which references its longId. The following example will show how it is done.

Please sign in to view further details of this article. Login

Web Content Display

Recurring Charges

If you want to charge your customer repeatedly, without requiring the customer to reorder, you can trigger so-called Recurring Charges from your backend. As a prerequisite you need the customer's agreement, a registered customer with at least one registered payment account, and to register the credentials in the Secure Storage component of the Payment Gateway. How to prepare this is described in Payment Account Registration.

In all integration scenarios you will receive the customerRegistrationId and customerRegistrationPassword via Status Notification when you register a customer for the first time (by registering their first payment account).

The customerRegistrationPassword will only be sent ONCE by a notification with entity=customer by which it should be stored. However, the customerRegistrationId is still sent with entity=payment.

Trigger Recurring Charges from your Backend

If a customer has payment accounts registered for recurring charges, you can trigger those recurring charges by posting to:
/api/customers/<customerRegistrationId>/charge

You do not have to specify the channel, it is set to RECURRING by default for this type of call.

Provide the password via customer.registration.password. Registration ID is passed via URL path and is not required in this scenario.

Example Request

URL: https://api.live.oscato.com/api/customers/aff7a069-b77a-4023-b5ae-ad4f48596ce4/charge

  • Basic Authentication: UBUY/BBtXa7yubR8ipuT:
  • Method: POST
Notifications and recurring payments
  1. As mentioned above, there is an additional boolean attribute hasRecurringAccount=true|false in the notification with entity=customer. If this customer has once given the recurring mandate (via allowRecurrence=true in the CHARGE Request) and not revoked it (by removing the recurring account) hasRecurringAccount will show true, otherwise false.
    • Note: true does not guarantee the recurring charge will work (or has ever worked), it just means there was a mandate given.
  2. When there is a change in reccuring charge status, a new notification will be sent.
  • Example 1: If the customer had a registered "frontend" account, and then registers a new account for recurring charges, then there will be another notification.
  • Example 2: If the customer had already a recurring account and registers another one then there will not be a notification (because status will remain true, i.e., no change)
  1. As long as an account registration is in a pending state, it will be not affect the recurring charges. The registration state can only change once the registration was successful. This may mean a notification for a newly registered customer (with regId and regPwd) will be sent and soon afterwards another notification with updated hasRecurringAccount info may also follow.
Example Recurring Charges Request

{
  "transactionId": "S-321-012",
  "country": "DE",
  "payment": {
    "amount": 9.90,
    "currency": "EUR",
    "reference": "Your Subscription 321"
  },
  "customer": {
    "email": "john.doe@example.com",
    "registration": {
      "password": "h5dhgn7gd3bhlkwykxgnhrd2346nm0ew6v"
    }
  },
  "callback": {
    "returnUrl": "https://my.ubuy.com/shop/success.html",
    "cancelUrl": "https://my.ubuy.com/shop/cancel.html",
    "notificationUrl": "https://ubuy.com/shop/notification.html"
  }
}

Recurring Charges

If you want to charge your customer repeatedly, without requiring the customer to reorder, you can trigger so-called Recurring Charges from your backend. As a prerequisite you need the customer's agreement, a registered customer with at least one registered payment account, and to register the credentials in the Secure Storage component of the Payment Gateway. How to prepare this is described in Payment Account Registration.

Please sign in to view further details of this article. Login

Web Content Display

Automated Denial Management

If a Recurring Charge is triggered by your server system and is denied, the OPG can retry this charge via the Automated Denial Management (ADM) app. The ADM can be configured in the Merchant Portal to automatically trigger a recurring charge at specified interval. The ADM can also be configured the number times a charge should be retried. There are a number of default settings in the ADM app to help you determine the best stratergy to decrease denied charges. The ADM app can significantly reduce your denied charges and implementation efforts. Your system will still receive Notifications with full details for every charge attempt.

Case 1: A recurring Charge attempt is rejected, but scheduled for retry on the OPG
  • The Status Code will be pending and the reason code retry_scheduled.
  • The Interaction Code and reason will be PROCEED - SCHEDULED, because on merchant side no action has to be taken. The returnCode.name will indicate why the transaction was unsuccessful to allow statistical analysis.
  • The date and time of the next retry will be given in the notification, as a parameter named autoRetryAfter instead of retryAfter, but in the same format.
  • declinesCount in the notification will state the number of rejections that have occurred for this payment request yet, starting with 1.
Case 2: A retried Charge is ultimately rejected (i.e., OPG decided not to pursue any more retry attempts)
  • The Status Code will be declined and the reason code debit_declined.
  • The Interaction Code and reason will be the original codes that resulted from the final payment attempt.
  • No autoRetryAfter or retryAfter value will be returned.
  • declinesCount in the notification will state the number of rejections that have occurred for this payment request.
Case 3: A retried Charge is successful
  • The Status Code will be charged and the reason code debited, as with a normal successful Charge
  • The Interaction Code and reason will be the original codes that resulted from this payment attempt, i.e. PROCEED and OK.
  • No autoRetryAfter or retryAfter value will be returned.
  • declinesCount in the notification will state the number of rejections that have occurred for this payment request until now (and therefore in total).
Configuration

The precise retry schedules can be individually fine-tuned in their configuration depending on the Interaction Reason Code.

The defaults are:

Interaction Reason  Code              Retries schedule plan
EXCEEDS_LIMIT Retries take place on the [1st], the [15th], then the [1st] and the [15th] of the next month of the initial transaction date.
UNKNOWN

The rerty schedule is planned after these days of the initial transaction date:

[+1d] [+2d] [+3d] [+4d] [+7d]

TEMPORARY_FAILURE

The retry is scheduled after hours and days of the initial transaction time & date as follows:

[+2h] [+4h] [+6h] [+8h] [+10h] [+12h] [+16h] [+20h] [+1d] [+2d] [+3d] [+4d] [+5d]

Stopping automated Retries

In some cases it makes sense to stop the OPG from repeating charges, e.g., if payments have arrived through another channel. You can do so by sending an HTTP DELETE to the Charge resource (in OPG1: the retry entity associated with the Charge resource).

Example Request

  • URL: https://api.live.oscato.com/api/charges/efdfc6c7-a803-4f8b-8e30-ef6d9b3d6b6e
  • Basic Authentication: UBUY/BBtXa7yubR8ipuT:
  • Method: DELETE

As a reply you will get an HTTP 200 status code with an empty body. This indicates that the OPG will not repeat the scheduled charges for the referenced initial Charge any more.

This will also trigger a Status Notification with these values (among others):

  • statusCode = canceled
  • reasonCode = debit_canceled
  • interactionCode = ABORT
  • interactionReason = UNKNOWN
ADM and Failover Routing

If you dig into the logic of ADM in the context of Fallback Routing (i.e., different providers that can be used for recurring charges), you will run into some conceptual challenges, because different providers could return different decline reasons.

Here is how OPG handles a situation like this under the hood:

Let's assume a recurring CHARGE for a registered customer that has 2 registered payment accounts (VISA and MASTERCARD). Let say that VISA has two PSP registrations for recurring charges, PROVIDER1 and PROVIDER2; and MASTERCARD only one via PROVIDER1.

In the first step, the OPG will try to process via VISA card, as in this example, this network has higher priority for some reason. If the processing via PROVIDER1 fails, the OPG will analyse the result. If the failure is 'recoverable' (Result Codes like 'provider not available' or 'provider internal error') the OPG will try to process via PROVIDER2. If the error is not recoverable the OPG will skip the processing via the other route (other provider registration) of the current registered account (in this case VISA) and will try to process with another registered account (in this case MASTERCARD). The OPG will also analyse the error result code to apply this information to the denial state of the registered account. 

As an example, let us say that processing with VISA card was tried and failed for both PSP registrations. For PROVIDER1 with Result Code 'provider not available' (recoverable) and for PROVIDER2 with 'exceeds limit'  (not recoverable). OPG will calculate an interaction code for the last try (here: PROVIDER2) and use it to increase the payment account's denials counter by 1 and change the account's denial state. This will also block the payment account if its denials counter reaches its limit (system default: 10). If the payment was successful the OPG would reset the account's denial counter to 0.

After that the OPG will try to process the transaction with the other registered account (MASTERCARD). Let say this try also fails with the Result Code 'provider not available' . As before, the OPG will derive the interaction code, use it for denial management, and return it to the merchant.

Now the transaction processing failed for both registered accounts VISA with Result Code 'exceeds limit'  (second result code, coming from PROVIDER2) and MASTERCARD with 'provider not available'. The last try will be taken as final execution result. Based on this result the OPG will derive the final interaction code and use the ADM to find the suggested next retry time. As a result ADM could return: 'in 2 hours'. The OPG will increase the rejection counter for this payment process (which is seperate from the payment account mentioned before) and will schedule the retry event, via the scheduler component, in 2 hours.

After 2 hours the scheduler will fire a retry-event and we will try to process this CHARGE again. If this try also fails, the OPG will retry with the same logic again until ADM blocks the next retry and finishes this CHARGE process with actual denial handler's 'failure result interaction code'.

Automated Denial Management

If a Recurring Charge is triggered by your server system and is denied, the OPG can retry this charge via the Automated Denial Management (ADM) app. The ADM can be configured in the Merchant Portal to automatically trigger a recurring charge at specified interval. The ADM can also be configured the number times a charge should be retried. There are a number of default settings in the ADM app to help you determine the best stratergy to decrease denied charges. The ADM app can significantly reduce your denied charges and implementation efforts. Your system will still receive Notifications with full details for every charge attempt.

Please sign in to view further details of this article. Login

Web Content Display

Deferred Payments

With Deferred Payments the checkout flow happens in two separate steps. Initially, a "reservation" (preauthorization) of the payment amount is made without actually transferring it. Later, a trigger of the real transfer takes place (capture), this step is called "closing" in the optile terminology.

The reservation has a different commitment and duration depending on the payment network and/or the issuing bank. For credit cards a reservation ("preauthorization") typically lasts 30 days, whereas a successful closing of this amount is guaranteed for 10 days. For PayPal the reservation lasts 29 days although for a direct debit a successful closing is not guaranteed.

Likewise, the same process is used for invoice payments. Typically the closing is called as soon as the products are shipped out to the customer. In retail businesses this can take some days or even weeks. For Open Invoice Providers this is the signal that the payment is due whereby they should transfer it to you and start waiting for the invoice payment of the end customer.

The diagram below shows the deferred payment based on the AJAX Integration scenario:

Initialize a Deferred Payment

If a payment network supports deferrals then it needs to be configured in case you want the deferred payment to be enabled. The configuration would be done by our staff individually per merchant (within the limitations of that network).

You can enable the payment networks that are in "deferred", "non-deferred" or "any" mode, as explained below in the LIST Request, by adding the preselection.deferral parameter with one of the following values:

  • DEFERRED Only networks which support deferred payments are listed. They are set in deferred mode for subsequent charges.
  • NON_DEFERRED (default) All networks which support immediate payment collection are listed. They are set in non-deferred mode when a CHARGE Request hits them.
  • ANY All networks are returned. If they support both modes, they are returned in deferred mode.

Note: the system default is set to "non-deferred"; therefore, if a payment network is configured to be in "deferred" mode and the value is not specified in the preselection.deferral parameter in the LIST Request, then the LIST Response would not include this payment network.

Example Deferred Payment LIST Request

{
  "transactionId": "T345",
  "country": "DE",
  "integration": "PURE_NATIVE",
  "customer": {
    "number": "42",
    "email": "john.doe@example.com"
  },
  "payment": {
    "amount": 29.99,
    "currency": "EUR",
    "reference": "ubuy T345/20-08-2013"
  },
  "preselection": {
    "deferral": "DEFERRED"
  },
  "callback": {
    "returnUrl": "https://www.ubuy.com/shop/success.html",
    "cancelUrl": "https://www.ubuy.com/shop/cancel.html",
    "notificationUrl": "https://www.ubuy.com/backend/notify"
  }
}

As with a normal LIST Request you will get back all available networks together with their operation URL, which in Native Integration you interpret according to LIST Response.

It is only possible to see the status code in the PURE_NATIVE integration scenario and not with the other integration scenarios due to security reasons. You could use the PURE_NATIVE integration parameter for testing reasons yet normally you would use the integration scenario that applies to your case. 

Make the Reservation

Now you can submit the customer's account details to the operation URL of the selected network. If the network is in deferred mode, then this results in the "reservation" of the amount and a DEFERRED CHARGE object will be created. The Status Notification for this will return the statusCode = preauthorized.

This DEFERRED CHARGE could either be canceled or closed in a second step, see below. Both are actions triggered from server-side.

You can mix deferred payments with methods that can't be deferred. Your system can detect by the status code if the payment was already processed or a closing is still needed.

For security reasons, only in "Pure Native" intergration scenarios will your backend receive the required closing URL directly in the LIST reply as shown on the right side. In other cases it can be constructed, see below.

Example Deferred Payments LIST Response

{
  "interaction": {
    "reason": "OK",
    "code": "PROCEED"
  },
  "redirect": {
    "method": "GET",
    "parameters": [{
      "name": "transactionId",
      "value": "tr345"
    },
	  ...
    ],
    "url": "https://dev.oscato.com/shop/success.html",
    "suppressIFrame": false
  },
  "resultInfo": "Approved",
  "links": {
    "self": "https://api.dev.oscato.com/api/charges/06ae3329-a7ea-42aa-9bd1-52f7987f3727",
    "closing": "https://api.dev.oscato.com/api/charges/06ae3329-a7ea-42aa-9bd1-52f7987f3727/closing"
  }
}

Cancel the Reservation

Whenever your system realizes that a payment is no longer required (e.g., because you cannot deliver goods), it should cancel the (remaining) reservation. Otherwise your customer may not be able to use the blocked funds on their account until they expire (e.g., after 10 days). For some payment networks (e.g., Open Invoice methods) these requested funds may never expire, and therefore future payments may lead to rejections if high amounts are left open.

To cancel a reservation, issue an HTTP DELETE request on the DEFERRED CHARGE resource. In "Pure Native" scenarios you get the URL to "self" already with the CHARGE reply.

Generally it is constructed like this:

https://api.live.oscato.com/api/charges/[longId of DEFERRED CHARGE]

As a result the reservation will be canceled through the provider and the transaction will transition to the status code canceled / preauthorization_canceled. This will be reflected in the response, which returns the DEFERRED CHARGE object again. Note that this DEFERRED CHARGE object is not actually deleted, you can fetch its status any time later again and it remains visible in My Transactions in the portal, for example.

It is possible to close a payment partially and cancel the remaining amount. In order to do that, you would have to delete/cancel the DEFERRED CHARGE after the partial closing has been made which would automatically cancel the rest of the amount.

The cancellation will always "cancel everything that was not captured yet". It does not take parameters like an amount. Therefore all closings should be performed first, and then the cancellation (of the rest) if necessary.

This order should be in line with most merchants' workflows, especially since cancellations of preauthorizations are not time critical.

Close the Transaction

To complete (capture) the transaction and actually trigger the payment you issue a POST request from your backend to the closing URL. It can be constructed like this:

https://api.live.oscato.com/api/charges/[longId of DEFERRED CHARGE]/closing

In simple cases the request contains only an empty  JSON object {} which means that the closing will be performed on the full amount.

However, the closing can also be performed partially and multiple times. For example, this can be used if an order has to be split into different shipments. In this case, you can submit a different amount and also a list of products that are covered by this payment.

Example Closing Request

{
  "payment": {
    "amount": 10.99,
    "currency": "EUR",
    "reference": "Partial Delivery tr345/1"
  },
  "products": [{
    "code": "B003X6UEXQ",
    "name": "Tron Legacy BluRay",
    "amount": 10.99
  }]
}

A successful CLOSING operation will create a CHARGE object on optile side, which represents the actual capture of the funds. It has a differend ID than the original DEFERRED CHARGE object, and your system will receive a response and a notification about its status. If your system issues multiple partial closings, the resulting CHARGE objects will all have different IDs.

A CHARGE object in the response directly includes its own PAYOUT link. Your system should issue PAYOUTS on the ID(s) of the corresponding resulting CHARGE(s), not on the preceding DEFERRED CHARGE object.

For invoice payments a partial CLOSING is the signal to expect less money transferred, e.g., due to a return of goods by the customer.

A CLOSING operation on a DEFERRED CHARGE creates a CHARGE object for the capture. On this CHARGE object a PAYOUT can be issued to refund.
Example Closing Response

{
  "links": {
    "payout": "https://api.sandbox.oscato.com/api/charges/5955242a16525bcc727abeedc/payout",
    "self": "https://api.sandbox.oscato.com/api/charges/5955242a16525bcc727abeedc"
  },
  "timestamp": "2016-08-29T16:00:43.315+0000",
  "operation": "CLOSING",
  "resultCode": "00000.TESTPSP.000",
  "resultInfo": "Approved",
  "pspCode": "TESTPSP",
  "returnCode": {
    "name": "OK",
    "source": "PSP"
  },
  "status": {
    "code": "charged",
    "reason": "debited"
  },
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "clearing": {
   "amount": 10.99,
   "currency": "EUR"
  },
  "identification": {
    "longId": "5955242a16525bcc727abeedc",
    "shortId": "06015-18360",
    "transactionId": "T345",
    "pspId": "MASTERCARD.DEBIT.1498572745446"
  },
  "customer": {
    "number": "42",
    "email": "john.doe@example.com"
  }
}



                

Deferred Payments

With Deferred Payments the checkout flow happens in two separate steps. Initially, a "reservation" (preauthorization) of the payment amount is made without actually transferring it. Later, a trigger of the real transfer takes place (capture), this step is called "closing" in the optile terminology.

Please sign in to view further details of this article. Login

Web Content Display

Chargebacks

Chargebacks are the revocation of a payment (that was already successfully processed) without merchant involvement (as opposed to voluntary Payouts). They typically occur if a credit card holder contacts the issuing bank and declares that a debit on their card as illegal. The OPG also allows chargebacks for SEPA direct debits, if the transaction gets declined by an involved institution at a later stage (typically some days after the direct debit request).

Chargebacks are by definition asynchronous. Therefore, the OPG will send a Status Notifications to inform your system about them. This is a big simplification for you implementation, because every payment provider delivers this information differently, and often only passively, so that active polling is required.

Before an actual chargeback takes place, a payment provider can also request clarifications from the merchant or announce a scheduled chargeback while still giving the merchant a chance for intervention.

These stages are modeled and described under Status and Reason Codes. Below is an representation of their possible transitions:

Chargebacks

Chargebacks are the revocation of a payment (that was already successfully processed) without merchant involvement (as opposed to voluntary Payouts). They typically occur if a credit card holder contacts the issuing bank and declares that a debit on their card as illegal. The OPG also allows chargebacks for SEPA direct debits, if the transaction gets declined by an involved institution at a later stage (typically some days after the direct debit request).

Please sign in to view further details of this article. Login

Web Content Display

Fallback Routing

The payment gateway intelligently tries to recover failed payment attempts by falling back to different available providers or payment networks where possible.

The Fallback Routing happens in the background without interaction with the customer or merchant. It is the first attempt of recovering issues that are returned by the provider, and therefore takes place before other measures like prompting the customer with the LIST again after a failed Frontend CHARGE Request (section "Retry payment") or Automated Denial Management.

How it works

In general certain Return Codes from providers are considered recoverable errors, for example technical failures or configuration problems. Others, like stolen credit card, exist independently from the provider and are not considered recoverable in this context. See Return Codes for a full list.

If a recoverable error is detected, the payment gateway will look for an alternative provider contract that is configured to also be used to process this transaction. This means it needs to support the same parameters like selected payment network and given country.

Frontend Charges

For frontend charges with customer interaction fallback routing is straight forward. If the provider declines the transaction for a recoverable reason, the payment data as given from the customer will be used to try again with another provider immediately. If one attempt succeeds or all available routes fail, the CHARGE Response and Status Notification with the result from the last attempt will be sent to the merchant.

Backend Charges

Charges without customer interaction, i.e., Recurring Charges, are handled differently because the Payment Gateway is not allowed to store credit card verification numbers (i.e., CVC and CVV), and therefore, cannot just turn to a new provider as a fallback. From a providers' perspective it would be an initial payment attempt requiring the verification number, which cannot be provided.

Therefore the payment gateway depends on past registrations of that customer with alternative providers. In case those are present, they will be used.

If no route through available registrations succeeds, the payment gateway will fall back to alternative registered payment accounts, e.g., another credit card that is stored. If those are found the whole story will be repeated with these accounts, i.e. looking for alternative providers again.

Side Note: Asynchronous Providers

Since a direct reply with error information is required instantaneously for fallback routing, the logic does not work after an asynchronous provider or payment network is contacted. Asynchronous in this context means that only a temporal pending status is returned to the payment gateway and the final result arrives later. This is the case for providers like Adyen or Dotpay, or for redirection networks where the customer is sent to an external page.

However, if no technical connection to the asynchronous provider could be established in the first place (e.g,. due to a provider downtime), Fallback Routing will be triggered because the OPG is able to act instantly.

Fallback Routing

The payment gateway intelligently tries to recover failed payment attempts by falling back to different available providers or payment networks where possible.

The Fallback Routing happens in the background without interaction with the customer or merchant. It is the first attempt of recovering issues that are returned by the provider, and therefore takes place before other measures like prompting the customer with the LIST again after a failed Frontend CHARGE Request (section "Retry payment") or Automated Denial Management.

Please sign in to view further details of this article. Login

Web Content Display

Gambling Restrictions

The OPG supports additional requirements which are often required by merchants in the gambling area and certain wallet payment methods (e.g., PayPal).

1:1 Relationship

This feature can be enabled by our support for a specific payment method and merchant division. It will make sure that;

  • customers of this merchant division can only use one account for this payment method, and
  • no other customer of this merchant division can use the same account for this payment method.

This means that a payment transaction with the corresponding payment method will be declined by the Payment Gateway if;

  • a customer tries to pay with a method repeatedly but uses a different payment account IDs (e.g., PayPal email), or
  • a customer tries to pay with an account of that payment method which has been used by a different customer of that merchant previously.

Note: for some wallet payment methods (e.g., PayPal) the used account ID can always be changed by the customer during checkout on the web pages of the method. This means that the Payment Gateway can only decline a transaction after the customer has clicked "Pay" on the wallet page.

Examples:
  1. John pays into his gambling account using PayPal. He uses his PayPal account john_doe@supermail.com. One month later he wants to pay in again. When he comes to the PayPal page, he changes the email account ID to johnny432@mail.org. After he confirmed the payment on the PayPal page the transaction is declined by the Payment Gateway and he would be redirected to an explanation on the merchant page.
  2. Mary pays into her gambling account with her PayPal account mary123@coolmail.net. For some reasons she also has a second account at the same gambling merchant, and also there she wants to pay in with her PayPal account mary123@coolmail.net. After she confirmed the payment on the PayPal page the transaction is declined by the Payment Gateway and she would be redirected to an explanation on the merchant page.
Technical Communication

Technically the communication between your system and the Payment Gateway would look like this:

First your system gets a CHARGE Response and corresponding Status Notification with:

  • Interaction Code: PROCEED
  • Interaction Reason: PENDING

When the customer has completed the checkout on the wallet site your system will get another Status Notification. If successful there will be the usual PROCEED/OK indication. If the transaction is declined due to these configured restrictions it will contain:

  • Interaction Code: TRY_OTHER_NETWORK
  • Interaction Reason: NETWORK_FAILURE

...plus a human readable error message in the resultInfo attribute.

Questions
  • Do unsuccessful payment attempts count?

No. If a customer tries to pay with the payment method and does not succeed, they can repeat the payment with the same method again but a different account ID (e.g., PayPal email).

  • What happens if the feature gets turned off temporarily and on again later?

The used payment account IDs are only recorded as long as the feature is turned on. In other words, the feature only checks against payments in the past that were made while the feature was turned on.

Example:

The feature is turned on and John pays in (for the first time) with his PayPal account john_doe@supermail.com.

Now the feature is turned off again by the merchant.

Next, John tries a payment with his second PayPal account, johnny432@mail.org. The payment succeeds.

Also Mary (with her seperate gambling account) now makes a first time payment with her PayPal account mary123@coolmail.net, and the payment would succeed .

After that the restriction feature gets turned on again.

John now can only make payments with his PayPal account john_doe@supermail.com again (or some other method of course). johnny432@mail.org would be declined. However, if he had a second gambling account, he could use his PayPal account johnny432@mail.org to pay there.

Mary can make another payment with any PayPal account. Also anybody else could use Mary's PayPal account mary123@coolmail.net for a payment into his or her gambling account.

  • How does the feature work if there are multiple merchant divisions?

The feature can be turned on and off per division seperately. The feature will double check against all payments of all divisions where the feature is enabled.

Example:

Merchant M has 3 Divisions: D1, D2 and D3. The feature is enabled for D1 and D2, but not D3.

Mary pays with her regular PayPal account mary123@coolmail.net in D1. When she also tries to pay with this PayPal account in her (seperate) gambling account in D2, it will be declined, because PayPal account mary123@coolmail.net was used already in a different gambling account at Merchant M.

However, she can use a different PayPal account now to pay in D2, e.g. peterpoor@fastmail.com.

Note: The underlying assumption in this example is that the two seperate gambling accounts of Mary in D1 and D2 also each have a different customer.number delivered to the Payment Gateway. If it was the same, she could pay in D2 with the same PayPal account as in D1, and only with that PayPal account.

In any case, Mary can use her PayPal account from D1, mary123@coolmail.net, again to pay in D3, because there the feature is not enabled.

  • If a transcation is declined by this OPG feature, does the transaction still occur in with the wallet method e.g., PayPal?

No. Technically the Payment Gateway will never confirm the execution of the payment, so there will be no completed transaction in the wallet method account.

Web Content Display

References & Resources

Web Content Display

ID and Object Types

Every payment transaction creates a resource on optile side (REST API style). It can optionally have ID(s) assigned by the merchant, and it will get an optile generated ID. By storing the optile generated ID your system can issue future actions on that transaction. This can be a simple read (GET), but sometimes updates or cancellations are possible (PUT or DELETE). It can also be actions beyond the REST paradigm, such as a CLOSING on a DEFERRED CHARGE object. See our API Reference for a full list.

optile will always pass on the merchant assigned IDs to the payment providers, so that the merchant can access them easily also in the provider user interfaces, if required. However, this comes to limitations in case the provider requires a special format of IDs. In this case optile will act as a translator in order to fulfill the specific provider requirements. Also the provider will typically have their own ID for transactions. It will not be necessary for your system to keep track of those, but they can be used for individual investigations.

IDs and object types are rocket science, but to give you an overview on one glance we have summarized them here.

Transaction ID Types

A transaction object contains these IDs:

  • Assigned by optile (will alway be present):
    • longId The optile generated ID (uniqueness guaranteed) for consecutive operations
    • shortId An optile generated string that's rather short and "almost unique" (i.e. not guaranteed for all times) that can be used for simplified human to human communication, e.g., over the phone
  • Assigned by your system:
    • transactionId (mandatory for LIST requests) The primary, merchant-assigned ID (no uniqueness required or checked by optile)
    • invoiceId (optional) An additional merchant assigned ID, mostly used by invoice based payment methods
  • Assigned by payment providers (will not always be present):
    • pspId An ID assigned by the payment provider (if the transaction reached the provider)
    • institutionId An ID assigned by the banking institution in the background (if the transaction reached the institution and the ID is revealed by the PSP in front of it)

You will find these attributes inside the identification section of a transaction object (for authenticated server-to-server requests), except invoiceId which is inside the payment section.

Transaction Object Types

Type Created through... Allows Merchant IDs Allows followup actions
LIST LIST request

transactionId, invoiceId

Read, update, cancel, and:

On a payment page: CHARGE or PRESET or ACTIVATE

On an account update page: UPDATE, REGISTER

DEFERRED CHARGE CHARGE on a LIST (in deferred mode)

transactionId (planned), invoiceId, pspId / institutionId

Read, CLOSING, cancel
CHARGE CHARGE on a LIST,  CLOSING on a DEFERRED CHARGE or Standalone Charge

transactionId (planned), invoiceId, pspId / institutionId

Read, PAYOUT, cancel (in few statuses)
DEFERRED PAYOUT PAYOUT on a CHARGE (in deferred mode)

transactionId (planned), invoiceId, pspId / institutionId

Read, CLOSING, cancel
PAYOUT PAYOUT on a CHARGE, CLOSING on a DEFERRED PAYOUT

transactionId (planned), invoiceId, pspId / institutionId

Read
ACTIVATE ACTIVATE on a LIST (for few methods)

invoiceId, pspId / institutionId

Read. The followup CHARGE is issued on the LIST object.

Note that the operations PRESET and cancel do not create separate transaction objects, that's why there are no corresponding objects listed here. They are only modifications on existing resources.

Example transaction object part

  ...
  "identification": {
    "longId": "5a7da245148b514ac4b3946ec",
    "shortId": "04040-80938",
    "transactionId": "tr10004",
    "pspId": "VISA.DEBIT.1518007534249"
  },
  ...

Other ID and Object Types

Apart from the resources that represent payment transactions there are also other object types and IDs, most notably for customer and payment account registrations:

  • CUSTOMER objects: Are created by CHARGEs with account registration. They are identified by the customerRegistrationId. They can be used to issue Recurring Charges.
  • ACCOUNT objects: A registered customer can have multiple registered payment accounts, which are identified by their accountId. They will be used implicitly for payments with registered accounts or updates or deletions of accounts. They can be also used explicitly to set preferred accounts. Or, after a LIST with "channel": "RECURRING" there can be Recurring Charges issued directly to a registered account.

ID and Object Types

Every payment transaction creates a resource on optile side (REST API style). It can optionally have ID(s) assigned by the merchant, and it will get an optile generated ID. By storing the optile generated ID your system can issue future actions on that transaction. This can be a simple read (GET), but sometimes updates or cancellations are possible (PUT or DELETE). It can also be actions beyond the REST paradigm, such as a CLOSING on a DEFERRED CHARGE object. See our API Reference for a full list.

optile will always pass on the merchant assigned IDs to the payment providers, so that the merchant can access them easily also in the provider user interfaces, if required. However, this comes to limitations in case the provider requires a special format of IDs. In this case optile will act as a translator in order to fulfill the specific provider requirements. Also the provider will typically have their own ID for transactions. It will not be necessary for your system to keep track of those, but they can be used for individual investigations.

IDs and object types are rocket science, but to give you an overview on one glance we have summarized them here.

Please sign in to view further details of this article. Login

Web Content Display

Status Notifications

Status Notifications are messages sent from the OPG to your server system. They push information about payment status changes (and other details) as soon as they are available, so that your system is always up to date. Alternatively you can also query regularly for transaction status changes using our Report API. However, for efficiency reasons we highly recommend to read this section carefully and implement a listener for the notifications.

Technically the Notifications are normal HTTP(S) GET requests with a bunch of query parameters (as they would come from a browser). They are sent to a URL defined by the merchant, either by configuration or passing a notificationUrl parameter in the LIST Request. In other words, the OPG acts like it would request a web page from your server system and delivers the status paramters this way.

When a payment operation is triggered, there will be both, a synchronous reply to that request, and an asynchronous notification. In AJAX, Hosted and Display Native integrations the reply will arrive at the customer's client (e.g., browser), whereas the notification will directly arrive at the merchant servers. Therefore it is safe to trust the notifications, as they never go through the customer's client.

The notification is sent out by the OPG first, then immediately followed by the reply. Due to network latencies there is no guarantee that the notification will also arrive first. However, reply and notification will contain the same status information. Therefore no additional synchronization between client and server is needed for frontend payments at this point.

The client should simply react on the reply, displaying the result to the customer. The merchant backend should trust the notification (Only in Pure Native scenarios this difference is obsolete, because the reply also goes to the backend and can be used instead of the first notification).

Artificially synchronizing the client with the server after the payment to wait for the notification may lead to complications in case of a notification delay (e.g., due to network reasons). Therefore we do not recommend it.

There is one exception though: If an asynchronous PSPs is used (e.g., Adyen), the Interaction Code in the reply could be PENDING (and also a notification with the Status Code  pending will arrive). In this case the customer should be asked to wait. Typically after a few seconds (in rare cases maybe even half a minute) a new notification will arrive at the merchant server with an updated Status Code. Only for these cases there should be some kind of synchronization with the customer's client.

It is important to listen to status notifications, also after a payment is completed, using the Status Codes to note events like chargebacks.

For security reasons we recommend to implement the notification listener of your live system in a way that it only accepts notifications from OPG via IP filtering.
Status Entities

Note that a notification can concern different things as indicated by the value of the entity attribute:

  • payment: The payment transaction (relevant for successes, chargebacks, etc.)
  • customer: The customer registration (as a consequence of account registration)
  • account: The customer's account registration (network name and account registration ID, as a consequence of account registration)
  • session: The frontend payment session (relevant when deciding whether to issue a new LIST Request or update an old one)

In the simplest implementation you will only need the payment notifications. Therefore do not confuse the entities.

Regardless of whether you process a notification or not, please acknowledge the receipt always with an HTTP 200 OK. Otherwise the Payment Gateway's guaranteed message delivery will repeat them (see below), therefore putting unneccesary load on yours and our system.
Notification Parameters
Name Type Appearance Description
transactionId String 1 ID as given by the merchant. Stays the same for the whole transaction "chain", for example the initial LIST and consecutive CHARGE and CLOSING operations.
longId String 1 ID of the specific transaction object (LIST, CHARGE, DEFERRED CHARGE, PAYOUT) as assigned by OPG (uniqueness guaranteed).
shortId String 1 Short ID of the transaction as assigned by OPG. Intended for simplified support communication.
entity String 1 Data entity described by this notification. Either paymentcustomeraccount, or session. Each entity has different Status Code spaces.
statusCode String 1 The transaction's current Status Code
reasonCode String 1 Additional information about the transaction status, see Status Codes
interactionCode String 1 How your system should react, see Interaction Codes
interactionReason String 1 Additional information on the suggested reaction, see Interaction Codes
returnCodeName String 0..1 Detailed provider response in optile's unified Return Code space. Intended for detail analysis in hindsight. Return Codes are subject to change. Therefore the stable interactionCode and statusCode should be used for runtime processing instead.
returnCodeSource String 0..1 Source of the transaction outcome, in most cases the GATEWAY itself or the connected PSP behind it, see Return Codes
pspCode String 0..1 The PSP used for processing
institutionCode String 0..1 The banking institution (that may be behind the PSP) used for processing.
resultCode String 1 Combined result code containing component and qualifier, see Result Codes. We recommend to use the simpler Status and Interaction Codes for most use cases, or the unified Return Codes for detailed analysis instead.
resultInfo String 1 Textual result info to the relevant operation. If returnCodeSource = GATEWAY the message is generated by the OPG, if returnCodeSource = PSP or an institution name, the message contains the original error string sent by the PSP or institution. In most cases resultInfo will not be generated by the OPG but from a PSP or institution. Mostly intended for debugging.
customerRegistrationId String 0..1 Identifies the customer registered on OPG side. If your system provides this in future requests, the registered payment accounts of the customer can be accessed.
customerRegistrationPassword String 0..1

The merchant's key to OPG's Secure Storage space for a registered customer. It's sent only once, on new registration of the customer (with entity=customer). If provided in future requests it can be used to decrypt sensitive payment account data again, for example for performing a provider switch.

hasRecurringAccount String 0..1 Indicates if a registered customer gave a recurring mandate that is still valid, so that you know whether you can do recurring charges on that customer. This is a boolean attribute (values true or false) included in the notification with entity=customer.
network String 0..1 Code of the payment network used in processing
amount Decimal 0..1 Processed payment amount
currency String 0..1 Processed payment currency
reference String 0..1 Payment reference text used (as given by merchant)
retryAfter Datetime 0..1 Suggestion when the merchant should trigger a rejected Recurring Charge again.
autoRetryAfter Datetime 0..1 When the OPG will retry this rejected Recurring Charge again, in case ADM is enabled.
rejectionCount Integer 0..1 How often this Recurring Charge attempt has been rejected already. Starts with 1 at first rejection.
notificationId String 1 Identifier for this notification. Stays the same for repetitions of a Notification due to the guaranteed delivery. Can be used to detect duplicates. To determine the order of Notifications use timestamp.
timestamp Datetime 1 Stays the same for repetitions of a Notification due to the guaranteed delivery. Can be used to determine the order of Notifications (reception order could be broken due to due to network issues for example).
previousStatusCode String 1 Provided when the status of the transaction changed. Indicates the previous Status Code so that the precise status transition can be derived.
previousReasonCode String 1

Same as previousStatusCode, only for the Status Reason Code, see Status Codes.

Note: not all parameters will always be present since status notifications could be pushed in different cases. For example, in case an account is registered, a status notification would be pushed without the "amount" parameter since it is independent from the amount. Also, the order of parameters is not fixed.

Additional payment network dependent data

mandate data: Was introduced for SEPA network and returns information about the official mandate data that was used for a transaction.

remittanceAccount[n] data: Provide this to your customers so they can complete their payment in case of invoice or prepaid methods. Only the fields required for the payment will be provided. For example a bank account together with a reference text (aka descriptor) could be identified, where the customer should transfer their money to. There could be more than one possible remittance account (indicated by [n] below, starting with remittanceAccount[0]).

Name Type Appearance Description
mandate.reference String 0..1 Mandate reference used for this SEPA transaction. Can be different from the value suggested by the merchant if the PSP uses his own IDs.
mandate.creditorId String 0..1 Creditor ID used for this transaction. Can be different from the Merchant's ID if the PSP uses his own ID.
mandate.authentication.date String 0..1 When the mandate was issued according to the merchant.
mandate.authentication.city String 0..1 Where the mandate was issued according to the merchant.
remittanceAccount[n].networkCode String 0..1  
remittanceAccount[n].holderName String 0..1 Account holder name
remittanceAccount[n].iban String 0..1 International Bank Account Number
remittanceAccount[n].bic String 0..1 ISO 9362 (SWIFT) bank identification code
remittanceAccount[n].number String 0..1 Account number
remittanceAccount[n].bankCode String 0..1 National bank code
remittanceAccount[n].bankName String 0..1 Bank name
remittanceAccount[n].accountId String 0..1 An ID of the account that is not a number, e.g. email for PayPal accounts
remittanceAccount[n].reference String 0..1 Descriptor for the money transfer (German "Verwendungszweck")
remittanceAccount[n].comment String 0..1 A dynamic note from the provider that could contain legal information and therefore should be displayed.
remittanceAccount[n].termDays String 0..1 Number of days the customer has by contract to transfer the money (in case of invoice: after the goods were delivered).
Legacy Data

If you have not implemented the notification listener already, do not worry about these values, which are either deprecated or not fully in place, yet.

Name Type Appearance Description
returnCode String 0..1 Deprecated, use interactionCode and interactionReason instead. Don't confuse with returnCodeName.
referenceId String 0..1 Deprecated, same as longId
referredTransactionPassword String 0..1 Password for sensitive data temporary saved during current transaction

 

Example Notification URL
https://ubuy.com/listener/notifications.do?transactionId=yourTransactionID&resultCode=00000.OPTILE.000&statusCode=charged&reasonCode=debited&referenceId=427a2bc8-216f-4a89-bf15-1edf90b800b8&longId=427a2bc8-216f-4a89-bf15-1edf90b800b8&shortId=07999-56867&timestamp=2012-03-21T12:27:24.791+01:00&network=VISA&amount=29.70&currency=EUR&reference=payment_reference_from_provider&interactionCode=PROCEED&interactionReason=OK&notificationId=2255968806107622
Guaranteed Message Delivery

The delivery of notifications is guaranteed (for any interface version). This means:

  1. A notification delivery is considered successful if the target host (merchant server system) replies with an HTTP 2xx status code within a specified timeout allowance, currently 10 seconds (but may be subject to change).
  2. If a notification fails, it is repeated in progressively increasing time intervals until successful. The first repetition happens after 2 minutes, then 5, 10, 15, and further.
  3. The last delivery attempt takes place around 24 hours after the first try. If this also fails the error is considered permanent and the Payment Gateway stops repeating this notification.

Please consider the following implications of guaranteed delivery:

  1. If a notification is correctly received by a merchant server system, but the response takes longer than the OPG's timeout, the message would be regarded as failed and repeated later. Therefore the merchant backend will receive the same notification twice, i.e., a duplicate. Duplicates can be detected using the notificationId, which will stay the same across all repetitions.
  2. If a notification (e.g., conveying a PENDING Interaction Reason) fails, and a few seconds later a new notification (e.g., with OK Interaction Reason) is successfully delivered, the first one will be re-sent 2 minutes later. In the given example this means the PENDING notification would arrive after the OK message. This information, of course, is not correct anymore. Therefore the notification order should be checked based on their timestamp. For example, the timestamp of the last notification could be saved and only notifications with higher timestamp will be processed in the future.

Note: These examples are unlikely, especially example 2, but they could occur. Therefore we recommend a clean implementation regarding these cases in the long run.

Also, if some kinds of notifications are ignored by your system (e.g., with entity = session, because you do not need payment conversion tracking), please let the system still return an HTTP 200 OK, so that the guaranteed delivery does not take effect.

Status Notifications

Status Notifications are messages sent from the OPG to your server system. They push information about payment status changes (and other details) as soon as they are available, so that your system is always up to date. Alternatively you can also query regularly for transaction status changes using our Report API. However, for efficiency reasons we highly recommend to read this section carefully and implement a listener for the notifications.

Please sign in to view further details of this article. Login

Web Content Display

HTTP Request Inspector

The HTTP Request Inspector is a development tool that you can use to test the Status Notifications that are sent out by the OPG.

You can create your own listener and access it, as long as you use the same browser (authorization via cookies). You can also save the assigned token to access it from somewhere else in the future. In the listener you will see all HTTP requests that came in with all their content. You can also set how the listener should respond to requests. You could, for example, return an HTTP error code like 500 to test optile's Guaranteed Message Delivery.

 

HTTP Request Inspector

The HTTP Request Inspector is a development tool that you can use to test the Status Notifications that are sent out by the OPG.

You can create your own listener and access it, as long as you use the same browser (authorization via cookies). You can also save the assigned token to access it from somewhere else in the future. In the listener you will see all HTTP requests that came in with all their content. You can also set how the listener should respond to requests. You could, for example, return an HTTP error code like 500 to test optile's Guaranteed Message Delivery.

 

Please sign in to view further details of this article. Login

Web Content Display

Interaction, Status, & Return Codes

After an operation, the OPG provides different information in form of codes or messages that can be used by the merchant systems to understand what might be the next operation step and what is the current state of an operation. These messages should not be presented to end customers due to their technical content.

The matrix below summarizes the various responses sent by the OPG:

Code Description
Interaction Codes Informs what the frontend system should do after an operation, e.g., proceed, retry, try other method...
Status Codes Describes the current status of an operation, e.g. charged, declined, charged back...
Return Codes Unified detail representation of payment providers' responses for deeper analysis.
Result Codes Contains the payment provider's native code, if available, for further investigations.
Result Infos Text message as complement to the codes. If returnCodeSource = GATEWAY the message is generated by the OPG, if returnCodeSource = PSP or an institution name, the message contains the original error string sent by the PSP or institution. In most cases resultInfo will not be generated by the OPG but from a PSP or institution.

In the next sections you can find detailed information about all codes described above, and in which situations they should be used.

Web Content Display

Interaction Codes

Interaction Codes are recommendations for the merchant system frontend on how to proceed after a transaction. They are especially relevant after submitted CHARGE Requests because there may be ways to redirect a transaction if a problem is identified and in consequence reduce denials.

In the case of frontend payments interaction codes give information on how the end customer should proceed, and a corresponding page and message should be displayed.

In the case of backend payments (e.g., Recurring Charges or closing of Deferred Payments) they indicate the next step to be performed by the merchant system.

The whole Interaction is composed of an Interaction Code and an Interaction Reason, which provides further information inside a group of Codes.

However, Interaction Codes are not a comprehensive reflection of all the statuses a payment may have, especially concerning background events (e.g., chargebacks). This instead can be taken from the Status Codes.

The Interaction Code is a simplified interpretation of the Return Code describing the operation result, but may also take into account past events.

Possible Interaction Code Values
Code Reason Description
PROCEED  

The operation worked as expected. At the moment there is nothing to do concerning this operation.

  OK

The operation was completed successfully, for example a successfully initialized LIST or executed CHARGE. Therefore you should check the payment status now.

  PENDING

The status is still unknown. Wait for the next notification.

  SCHEDULED

Scheduled for specific point in time, not yet submitted. For example ADM retry or scheduled for batch processing.

ABORT  

The operation failed and there is no point in retrying. If a CHARGE fails like this, also alternative payment attempts in the same LIST session should not be allowed. Do not confuse this with the "aborted" status.

  NO_NETWORKS

The LIST does not have any applicabe networks (methods) or registered accounts anymore, because they were all declined. (In backend cases this would be SYSTEM_FAILURE)

  FRAUD

Fraud detected, do not allow any more Charge/Payout attempts (for frontend RISK_DETECTED may be returned instead)

  RISK_DETECTED

Blocked by risk management, it's suggested to not trust this customer.

  DUPLICATE_OPERATION

Duplicate frontend Charge on a LIST, duplicated LIST, or duplicated backend Charge declined by provider.

  INVALID_ACCOUNT

Invalid account (backend denial handling)

  CHARGEBACK

A previously successful payment was revoked by customer

  INVALID_REQUEST The request to the OPG was not valid and therefore could not be executed. There is nothing the end customer can do about it. It has to be fixed on the merchant side.
  SYSTEM_FAILURE

There is a technical issue with this operation which the end customer cannot resolve. It could be on the merchant side, for example an invalid request (that was not covered by the code above), OPG side, or provider side. If the Update of a LIST fails like this, the LIST itself may still be valid.

TRY_OTHER_NETWORK  

The customer should choose a different network (method). The previously attempted method is removed from the LIST. Reload it, so that the method will not be present anymore.

  BLOCKED

Network (AKA "method") is blocked by merchant configuration or denial handler (e.g., due to numerous chargebacks)

  NETWORK_FAILURE

Currently there is no working route for this network available or the network is down globally. This includes misconfiguration on OPG or provider side.

  INVALID_REQUEST

This method or provider needs data that is not or incorrectly provided by the request (e.g., missing billing address etc.).

  RISK_DETECTED

A restriction to (possibly more secure) methods has taken place due to suspicion of fraud .

  ADDITIONAL_NETWORKS

The system has detected more (sub-) networks the customer needs to choose from.

TRY_OTHER_ACCOUNT  

The payment account exists, but was not accepted. Offer to try another account, same network (AKA "method") is allowed. Reload the LIST so the used account will not show anymore in case it was a registered one.

  BLOCKED

Account is blocked by merchant configuration or payment provider (e.g., due to excessive retries or chargeback)

  BLACKLISTED

Account is blacklisted by external source (e.g., PSP or scoring provider)

  CUSTOMER_ABORT

The customer has chosen to abort this operation.

  INVALID_ACCOUNT

Invalid account data, account unknown, deactivated, etc.

  EXCEEDS_LIMIT

This payment account does not provide sufficient funds.

  EXPIRED_ACCOUNT

Account is expired, a different account should be used (applies to frontend payments).

RETRY  

Retry with this network, but with corrected account data (typically frontend) or at another time (typically backend).

  TRUSTED_CUSTOMER

Specific data is incorrect and a trusted customer is detected. It would be safe to give a hint what field contains an error, based on the Return Code.

  UNKNOWN_CUSTOMER

Specific data is incorrect but the customer is unknown (maybe fraud). The user should get a general message about account error without hints. Applies to frontend only, backend equivalent is DECLINED.

  ACCOUNT_NOT_ACTIVATED

Payment account exists, but needs to be activated first.

  EXPIRED_SESSION

LIST or third party payment session has expired, restart if customer is available.

  DECLINED

Account data seems correct, but payment is not accepted due to various reasons (check Return Code). Rejections and Failures (as opposed to Declines) would instead be NETWORK_FAILURE, SYSTEM_FAILURE, etc.

  EXPIRED_ACCOUNT

Account is expired. Applies to backend payments. Retry the Recurring Charge after the expiration date was updated or registered accounts were added.

  EXCEEDS_LIMIT

Account is valid but at the moment has exceeded its limits, i.e., there are insufficient funds (applies to backend operations, ADM is recommended)

  TEMPORARY_FAILURE Provider, network (AKA "method") or adapter experiences a temporary failure. Occurs mostly for backend, where a retry later is recommended. Since this is not possible in frontend, this situation would often cause a TRY_OTHER_NETWORK there.
RELOAD   The LIST object was updated based on the submitted data. Reload and display the resulting payment page again.
  ACTIVATED A method has been used that requires a multi-step flow, e.g. Installments. See ACTIVATE Request. This is not an error but expected behavior for some methods.

 

Interaction Codes

Interaction Codes are recommendations for the merchant system frontend on how to proceed after a transaction. They are especially relevant after submitted CHARGE Requests because there may be ways to redirect a transaction if a problem is identified and in consequence reduce denials.

In the case of frontend payments interaction codes give information on how the end customer should proceed, and a corresponding page and message should be displayed.

In the case of backend payments (e.g., Recurring Charges or closing of Deferred Payments) they indicate the next step to be performed by the merchant system.

Please sign in to view further details of this article. Login

Web Content Display

Status Codes

Status Codes describe the current state of an operation, they provide a basic information which your server system should listen to. They are sent in LIST and CHARGE responses as well as via Status Notifications.

The whole Status is composed of a Status Code and a Reason Code, which provides further information inside a group of Codes.

Note that a status can concern different scopes as indicated by the value of the entity attribute:

  • payment: The payment transaction (relevant for successes, chargebacks, etc.)
  • customer: The customer registration (as a consequence of account registration)
  • account: The account registration under a customer (also result of account registration)
  • session: The frontend payment session (relevant when deciding whether to issue a new LIST Request or update an old one)

Status Codes are complemented by Interaction Codes that offer recommendations on what to do next in a frontend payment session, especially to reduce declines in problematic situations.

Conceptually the status codes can be seen in a hierarchy as visualized below:

Payment Statuses

Concerning entity = payment

Status Code Reason Code Comment
charged debited Charge successful. Also applies to Closings of Deferred Charges but not Deferred Charges themselves (see below).
^ debited_partial A Charge or Closing that was successful but partially refunded.
^ payment_received Charge successful (after customer had to complete the payment seperately, such as with the Sofort Banking method)
paid_out refund_credited Payout completed. This can apply to a Refund transaction or the initial Charge when completely paid out.
^ credited ^
pending debit_requested Operation pending (e.g., because customer has been redirected to a PSP confirmation page or the PSP processes the request asynchronously). Wait for further notification.
^ refund_requested ^
  payout_requested ^
^ payment_demand_requested ^
^ payment_demanded ^
^ credit_requested ^
^ retry_scheduled A recurring payment attempt failed, but optile has scheduled a retry for the future. This status and behaviour is a part of Automated Denial Management.
^ processing_scheduled The payment request was received and is currently queued on provider or optile side with the possibility to cancel it before it gets processed (see Refunds & Cancelations).
failed debit_failed

The processing was denied (maybe not even attempted), because a technical problem is present (on provider or maybe merchant side).

Examples: Downtime, wrong request format, missing account data (assuming this is due to a faulty implementation on merchant side)

^ refund_failed ^
^ payment_demand_failed ^
^ credit_failed ^
declined debit_declined

The processing was denied, because seemingly there is no willingness or ability of the account holder to actually pay.

Examples: Insufficient Funds, Risk Management, Blacklisting, Invalid account data (assuming this is due to incorrect input from customer)

^ refund_declined ^
^ payment_demand_declined ^
^ credit_declined ^
rejected rejected

The processing was denied, because it is not allowed due to current configuration or general agreement with the provider.

Examples: Currency or Country not allowed, payment feature not enabled.
aborted debit_aborted Operation aborted by customer (do not confuse with interaction code ABORT)
^ payment_demand_aborted For example, a prepayment is not done within 3 months, or actions on redirected page not completed within 30 minutes.
charged_back charged_back Amount charged back from the merchant account due to customer complaint or dispute.
information_requested information_requested Charge disputed by customer: e.g., customer claimed a transaction cancelation directly at PSP. PSP requests information (from the merchant) about the transaction to accept or reject the claim.
dispute_closed dispute_closed DEPRECATED - Starting from OPG v2.0.6 a transaction in status information_requested can only transition to charged_back or back to its previous status (most likely charged).
^ chargeback_canceled DEPRECATED - See above.
canceled debit_canceled Operation canceled by merchant
^ refund_canceled ^
^ payment_demand_canceled ^
^ receipt_canceled ^
^ credit_canceled ^
Deferred Payment Statuses

Concerning entity = payment

The following statuses can occur for Deferred Charges or related Closings, in addition to the statuses above.

Status Code Reason Code Comment
charged closed A Deferred Charge that was completely closed. Closings themselves, however, will be marked as debited instead, see above.

^

closed_partial A Deferred Charge that was partially closed
preauthorized preauthorized Preauthorization successful. Amount is likely to be available for closing.
^ debited_partial A successful Deferred Charge has been partially closed.
pending preauthorization_requested Operation pending (e.g., because customer has been redirected to a PSP confirmation page or the PSP processes the request asynchronously). Wait for further notification.
^ preorder_issued ^
^ preorder_requested ^
^ cancelation_requested ^
failed preauthorization_failed Operation failed due to technical reasons
^ preorder_failed ^
declined preauthorization_declined Operation declined by institution
^ preorder_declined ^
aborted preauthorization_aborted Operation is aborted by customer
expired preauthorization_expired Preauthorization reference has expired
^ request_expired Request operation has expired (no valid response from PSP)
canceled preorder_canceled Operation canceled
^ preauthorization_canceled ^
Customer Statuses

Concerning entity = customer

The customerRegistrationPassword will be sent exactly once after an account registration with such a notification. customerRegistrationId will be returned for other notifications as well.

Status Code Reason Code Comment
registered registered Customer is registered
pending registration_requested Registration requested; wait for further notification

^

deregistration_requested Operation pending; wait for further notification

^

registration_cancelation_requested ^
failed registration_failed Operation failed due to technical reasons
declined registration_declined Operation declined by institution
aborted registration_aborted Operation is aborted by customer
expired registration_expired Registration reference has expired
canceled registration_canceled Operation canceled
Account Statuses

Concerning entity = account

Status Code Reason Code Comment
registered registered Account is registered
deregistered deregistered De-registration is done successfully
Payment Session Statuses

Concerning entity = session

Status Code Reason Code Comment Entity
expired list_expired An initiated List expired, i.e., its reference is no longer valid and no Charge can be executed through it anymore. session
listed listed The List is valid and a Charge can be executed. Only in List reply
pending charge_requested The List is in use, but the Charge state is unknown for now (i.e., because the customer is redirected to the PSP page to close the payment). session
rejected list_rejected The List could not be generated due to the current configuration (e.g., missing methods or providers for the requested country or currency). session
failed list_failed The List has failed due to a technical problem and no action is possible for this List. session
canceled list_canceled The List has been canceled (by the merchant) and no action is possible for this List. session
ended list_used The List has been used for payment and no action is possible for this List. session

^

ended The List is in the end-state and will be removed/deleted. session

 

Status Codes

Status Codes describe the current state of an operation, they provide a basic information which your server system should listen to. They are sent in LIST and CHARGE responses as well as via Status Notifications.

Please sign in to view further details of this article. Login

Web Content Display

Result Codes

Result Codes describe the outcome of an operation in detail. To simplify, the OPG performs a mapping of the Return Code to interpret the Interaction Codes, which we recommend to use in most cases.

A Result Code consists of three groups separated by dots:

  1. The first group is numeric and called Return Code (or formerly Standard Code). The Return Code 00000 means that no error occured during payment request processing.
  2. The second group contains alphanumerical characters and refers to a component that generated this return code. Standard components are described by three digits whereas custom components and server extensions are usually referred to by their code names.
  3. The third group is a qualifier that may contain additional information, as given by the provider. Usually the qualifier is encoded by three digits and default value is 000 if no additional information is available.

Component and qualifier are called Investigation Info and help to analyze error conditions. Result codes are complemented by Result Info messages, which contain original payment service provider information, when available.

For example:

Result Code: 00100.102.000
Return Code = 00100 - Invalid request
Component code = 102 - Merchant HTTP Gateway Listener
Qualifier = 000 - no additional information

Result Code: 45020.WIRECARD.51
Return Code = 45020 - Not sufficient funds / exceeds limit
Component code = WIRECARD - Wirecard PSP adapter
Qualifier = 51 - Insufficient funds or credit limit exceeded. (Wirecard error code)

Web Content Display

Return Codes

Return Codes are a unified representation of all Payment Service Providers' responses concerning a payment transaction. As such, Return Codes are low-level information that can be used for detailed analysis, especially of denied payments.

From the low-level Return Codes the higher-level Status Codes and Interaction Codes are derived, which were designed for easier handling in day-to-day use cases.

The Return Codes are represented by the following attributes, which are available in CHARGE responses and Status Notifications:
  • returnCode: numerical representation, shown as part of the Result Code.
  • returnCodeName: human readable representation, see table below.
  • returnCodeSource: indicates where in the chain the response was generated. Together with the pspCode and institutionCode this should make clear, which organization should be contacted in case of transaction specific questions. Its value can be either of:
    • GATEWAY (Payment Gateway, first level)
    • PSP (Connected payment service provider, second level)
    • INSTITUTION (The banking institution that may be behind the payment service provider)

The table below includes all Return Codes of the Payment Gateway with their numbers, names, descriptions and if they are considered recoverable in the context of Fallback Routing.

Number Code Name Recoverable Description
0 OK   Approved
1 OK_PENDING   Pending, you have to check the status later
2 OK_SCHEDULED_FOR_BATCH   Pending, you have to check the status later
5 OK_TEST_MODE   OK / Production level test mode
11 ABORTED_BY_CUSTOMER   Aborted, operation is aborted by customer
14 CANCELED   Canceled, operation is canceled
15 CHARGEDBACK   Charged back, charge back is received
16 IN_DISPUTE   Dispute process has been initialized
17 OPERATION_REQUEST_EXPIRED   Requested operation is expired
10050 OPERATION_NOT_SUPPORTED x Operation is not supported
10100 WORKFLOW_TEMPLATE_NOT_FOUND   No workflow for operation
10103 INVALID_TRANSACTION_STATE   Operation is invalid for current process state
10105 DUPLICATED_TRANSACTION   Same transaction has been already submitted
11010 TRANSACTION_IN_USE   Transaction is blocked by other request
11013 TERMINAL_IN_USE x Terminal is locked by other request
10520 MAX_REQUESTS_OCCURRED x Transaction is rejected because of heavy load from one host
10530 INSTITUTION_NOT_SUPPORTED x Institution is not supported
10531 INVALID_INSTITUTION x Institution is unknown
10532 CONTACT_INSTITUTION   Contact institution
11000 SERVICE_ERROR x Error occurs during request processing
11005 THIRD_PARTY_SERVICE_ERROR x Error from third party service on provider side
11010 CURRENCY_CONVERTER_ERROR x Currency converter service error
11011 CURRENCY_CONVERTER_INVALID_RATE x Currency converter - invalid currency rate
11012 CURRENCY_CONVERTER_MISSING_RATE x Currency converter - missing currency rate
11020 ADAPTER_NOT_AVAILABLE x Provider adapter is not available
11021 ADAPTER_COMMUNICATION_ERROR x Communication error with adapter
11025 ADAPTER_ERROR x An error in adapter
12000 REQUEST_ERROR x Adapter can not create a valid request for communication with target service, so no service communication took place
12010 COMMUNICATION_ERROR x Communication error with target service because of socket connect timeout, read timeout or IOException
12015 TEMPORARY_UNAVAILABLE x Payment service temporary unavailable
13000 RESPONSE_ERROR   Cannot parse or understand provided response
13010 API_VERSION_ERROR x Service API version is not compatible with version used by a service-client
13050 INVALID_REQUEST x The request has wrong or in an unexpected format, or it is not accpted by a reason like 'cannot process empty request', 'missing signature', 'no action type found in request' and so on
20100 INVALID_CONFIGURATION x Configuration is invalid, no detail information given
20150 INVALID_PROVIDER_CONTRACT x Provider configuration is invalid
20151 INVALID_PROVIDER_CREDENTIALS x Invalid provider credentials
20152 MISSING_PROVIDER_CREDENTIALS x Missing provider credentials
20160 NO_ROUTE_FOR_NETWORK x No route to provider
20161 NO_NETWORK_BY_PROVIDER x No network by provider
20162 NOT_ALLOWED x Requested action is not allowed by contract
20163 AMOUNT_NOT_ALLOWED x Requested amount is not allowed by contract
20164 COUNTRY_NOT_ALLOWED x Country is not allowed by contract
20165 CURRENCY_NOT_ALLOWED x Currency is not allowed by contract
20180 METHOD_NOT_SUPPORTED x Requested method is not supported
20200 MERCHANT_UNKNOWN   Merchant is not known on OPG side
30000 INVALID_REFERENCE x Invalid transaction- or other unspecified- reference
30001 INVALID_CUSTOMER_REGISTRATION_REFERENCE x Invalid customer registration reference
30002 INVALID_ACCOUNT_REGISTRATION_REFERENCE x Invalid payment account registration reference
30003 MISSING_REFERENCE x Missing transaction- or other unspecified- reference
30004 EXPIRED_REFERENCE x Expired transaction- or other unspecified- reference
30005 USED_REFERENCE x Used transaction- or other unspecified- reference
30006 MISSING_CUSTOMER_REGISTRATION_REFERENCE x MIssing customer registration reference
30007 MISSING_ACCOUNT_REGISTRATION_REFERENCE x Missing payment account registration reference
30008 CANCELED_REFERENCE x Canceled (voided or invalidated) transaction- or other unspecified- reference
30009 CANCELED_ACCOUNT_REGISTRATION_REFERENCE x Canceled (voided or invalidated) payment account registration reference
30010 INVALID_CUSTOMER_REGISTRATION x Invalid data in customer registration
30011 INVALID_REGISTERED_ACCOUNT x Invalid data in registered account
45000 DECLINED x Declined
45010 INVALID_ACCOUNT   Invalid card or account
45011 EXPIRED_ACCOUNT   Expired card or account
45012 RESTRICTED_ACCOUNT   Restricted card or account
45013 INCOMPLETE_ACCOUNT   Incomplete account, some attribute missing
45014 LOCKED_ACCOUNT   Account is locked
45015 TEST_ACCOUNT   Test account
45016 NOT_ACTIVATED_ACCOUNT   Not activated account
45017 LOST_OR_STOLEN_CARD   Lost or stolen card
45018 PICK_UP_CARD   The card is requested by an issuer to be retrieved
45020 NON_SUFFICIENT_FUNDS   Not sufficient funds / exceeds limit
45025 ACCOUNT_SURPASSED_LIMIT   The account exceeds limit (daily limit, weekly limit, amount of transactions count, amount of single transaction and so on)
45100 TRANSACTION_EXCEEDS_LIMIT   Transaction's amount is above limit
45300 SECURITY_VIOLATION x Security violation
45340 ALLOWABLE_VERIFICATION_TRIES_EXCEEDED   Allowable retries exceeded
45341 NOT_AUTHENTICATED_ACCOUNT   Password or pin/verification code does not match
45400 RISK_MANAGEMENT_VIOLATION x Declined by risk management system
45405 RISK_VELOCITY_CHECK x Declined by velocity check
45406 RISK_REPEATED_REVERSALS x Declined because of often payment reversals from customer side
45407 RISK_AVS_CHECK x Declined by Address Verification System
45408 RISK_SUSPECTED_FRAUD   Suspected fraud
45409 RISK_BLACKLIST   Account or customer is blacklisted
50000 VALIDATION_ERROR x Data (not necessarily account-related) does not pass the validation logic, feedback is without specific information
50005 INVALID_DATA x Invalid data not necessarily account-related
50010 INVALID_BANK_CODE   Invalid bank code
50011 INVALID_BANK_NAME   Invalid bank name
50012 INVALID_IBAN   Invalid IBAN
50013 INVALID_BIC   Invalid BIC
50015 INVALID_ACCOUNT_NUMBER   Invalid account number
50016 INVALID_HOLDER_NAME   Invalid holder name
50017 INVALID_BANK_LOCATION   Invalid bank location
50018 INVALID_BANK_LOCATION_ID   Invalid bank location ID
50030 INVALID_COUNTRY   Invalid country
50050 INVALID_EXPIRY_MONTH   Invalid expiry month
50051 INVALID_EXPIRY_YEAR   Invalid expiry year
50052 INVALID_EXPIRY_DATE   Invalid expiry date
50053 INVALID_VERIFICATION_CODE   Invalid verification code
50070 INVALID_LOGIN   Invalid login
50080 INVALID_PASSWORD   Invalid password
50081 INVALID_AUTHENTICATION_DATA   Invalid 3d secure or other authentication data
50095 INVALID_EMAIL   Invalid email
50100 INVALID_AMOUNT_FORMAT   Invalid amount format
50105 INVALID_URL_FORMAT   Invalid URL format
50120 INVALID_CURRENCY_FORMAT   Invalid currency format
50130 INVALID_REFERENCE_TEXT   Invalid reference text
50170 INVALID_BILLING_ADDRESS   Invalid billing address
50190 INVALID_SHIPPING_ADDRESS   Invalid shipping address
50300 INVALID_PRODUCT_INFO   Invalid product info
51005 MISSING_DATA x Missing data (not necessarily account-related), no details given
51009 MISSING_ACCOUNT   No account information provided
51010 MISSING_BANK_CODE   Missing bank code
51011 MISSING_BANK_NAME   Missing bank name
51012 MISSING_IBAN   Missing IBAN
51013 MISSING_BIC   Missing BIC
51015 MISSING_ACCOUNT_NUMBER   Missing account number
51016 MISSING_HOLDER_NAME   Missing holder name
51017 MISSING_BANK_LOCATION   Missing bank location
51018 MISSING_BANK_LOCATION_ID   Missing bank location ID
51030 MISSING_COUNTRY   Missing country
51050 MISSING_EXPIRY_MONTH   Missing expiry month
51051 MISSING_EXPIRY_YEAR   Missing expiry year
51052 MISSING_EXPIRY_DATE   Missing expiry date
51053 MISSING_VERIFICATION_CODE   Missing verification code
51070 MISSING_LOGIN   Missing login
51080 MISSING_PASSWORD   Missing password
51081 MISSING_AUTHENTICATION_DATA   Missing 3d secure or other authentication data
51095 MISSING_EMAIL   Missing email address
51100 MISSING_AMOUNT   Missing amount
51120 MISSING_CURRENCY   Missing currency
51130 MISSING_REFERENCE_TEXT   Missing reference text
51170 MISSING_BILLING_ADDRESS   Missing billing address
51190 MISSING_SHIPPING_ADDRESS   Missing shipping address
51300 MISSING_PRODUCT_INFO   Missing product (shopping cart) info
99999 UNKNOWN x Result code is unknown

 

Return Codes

Return Codes are a unified representation of all Payment Service Providers' responses concerning a payment transaction. As such, Return Codes are low-level information that can be used for detailed analysis, especially of denied payments.

From the low-level Return Codes the higher-level Status Codes and Interaction Codes are derived, which were designed for easier handling in day-to-day use cases.

Please sign in to view further details of this article. Login

Web Content Display

Test Accounts & Magic Numbers

Web Content Display

Test Accounts

There is a full scale testing suite provided by optile to cover edge and corner cases, triggered by payment amounts, see Magic Numbers.

Apart from that you can use these straight forward account numbers for some of your adapters in place, including the optile "dummy" adapter (not to be confused with the "Test Adapter" mentioned above).

Test Account Numbers Credit Cards
Payment Service Provider VISA MasterCard American Express Diner's Club Discover Maestro
Adyen Holder name: any
Expiry date: 06 / 2016
CVV: 737
Number: 4111 1111 1111 1111
Holder name: any
Expiry date: 06 / 2016
CVC: 737
Number: 5555 5555 5555 4444
Holder name: any
Expiry date: 06 / 2016
CID: 7373
Number: 3700 0000 0000 002
Holder name: any
Expiry date: 06 / 2016
CVV2: 737
Number: 3600 6666 3333 44
Holder name: any
Expiry date: 06 / 2016
CID: 737
Number: 6011 6011 6011 6611
Holder name: any
Expiry date: 06 / 2016
CVC: 737
Number: 6731 0123 4567 8906
Authorize.Net Holder name: any
Expiry date: any date in the future
CVV: any 3-digit number
Number: 4007000000027
  Holder name: any
Expiry date: any date in the future
CID: any valid 4-digit number
Number: 370000000000002
Holder name: any
Expiry date: any date in the future
CVV2: any valid 3-digit number
Number: 38000000000006
Holder name: any
Expiry date: any date in the future
CID: any 3-digit number
Number: 6011000000000012
 
Concardis Holder name: any
Expiry date: 12 / 18
CVV: 147
Number.: 4149 0115 0000 0147

Holder name: any
Expiry date: 12 / 18
CVV: 003
Number.:
5232 0500 0001 0003

       
eMerchantPay "holderName": any,
"number": 4111111111111111,
"expiryMonth": 1,
"expiryYear": 2017,
"verificationCode": "123"
"holderName": any,
"number": "5500000000000004",
"expiryMonth": 1,
"expiryYear": 2017,
"verificationCode": "123"
       
Ingenico Holder name: any, min. 3 chars
Expiry date: any date in the future
CVV: any 3-digit number
Number e.g.:
4111 1111 1111 1111
Holder name: any, min. 3 chars
Expiry date: any date in the future
CVV: any 3-digit number
Number e.g.:
5544444444444444
       
optile Dummy Adapter - TestPSP Holder name: any, min. 3 chars
Expiry date: any date in the future
CVV: any 3-digit number
Numbers e.g.:
4111 1111 1111 1111
4012 8888 8888 1881

Holder name: any, min. 3 chars
Expiry date: any date in the future
CVC: any valid 3-digit number
Numbers e.g.:
5500 0000 0000 0004
5544 4444 4444 4444
5555 5555 5555 4444

5102 8819 1749 4147 ->
generates Account Exceeds Limit (45020) RETRY

Holder name: any, min. 3 chars
Expiry date: any date in the future
CVV: any 3-digit number
Numbers e.g.:
3400 0000 0000 009
3700 0000 0000 002
Holder name: any, min. 3 chars
Expiry date: any date in the future
CVV: any 3-digit number
Number: 3000 0000 0000 04
older name: any, min. 3 chars
Expiry date: any date in the future
CVV: any 3-digit number
Number: 6011 0000 0000 0004
 
Secure Trading

Holder name: any
Expiry date: any
CVV: any
Number.: 4111110000000211
(authorization)

Number.: 4111110000000112 (decline)

Holder name: any
Expiry date: any
CVV: any
Number.: 5100000000000511
(authorization)

Number.: 5100000000000412 (decline)

       
Six Holder name: any
Expiry date: 12 2017
CVV: 596
Number: 4761739090000088
Holder name: any
Expiry date: 12 2025
CVV: 123
Number: 5413330089600010
       
Telecash/IPG Holder name: any
Expiry date: 10 2020
CVV: 123
Number: 4035874000424977
Holder name: any
Expiry date: 10 2020
CVV: 123
Number: 5426064000424979
       
Wirecard Holder name: any
Expiry date: any date in the future
CVV: any 3-digit number
Number: 4200000000000000
Holder name: any
Expiry date: any date in the future
CVC: any 3-digit number
Number: 5500000000000000
Holder name: any
Expiry date: any date in the future
CID: any valid 4-digit number
Number: 370000000000000
Holder name: any
Expiry date: any date in the future
CVV2: any valid 3-digit number
Number: 38000000000000
Holder name: any
Expiry date: any date in the future
CID: any 3-digit number
Number: 6011000000000000
Holder name: any
Expiry date: any date in the future
CVC: any 3-digit number
Number: 675940000000000002
WorldPay

Holder name: Sansa Stark,
number: 4444333322221111,
expiryMonth: 12,
expiryYear: 2020,
CVV: 555

Other CVVs trigger different behaviors.
More information

 

Holder name: Tom James,
number: 5555555555554444,
expiryMonth: 7,
expiryYear: 2019,
CVV: 555

Other CVVs trigger different behaviors.
More information

 

       
Bank Accounts
PSP Adyen Wirecard Sofortüberweisung optile dummy adapter
Bank Account Account Number: 1234567890
Bank Code: 12345678
Holder name: any
Account Number: 12345678
Bank Code: 70070010
First Name: John F
Last Name: Doe
Bank Code (BLZ): 88888888
Account Number: any number
PIN: any 4-digit number
Account Number e.g.: 1111111
Bank Code e.g.: 79050000
Holder name: any, min. 3 chars

Web Content Display

Magic Numbers

We ask merchants to unrestrictedly go through the following testing phases before going live.

# Test Phase Test Target OPG system Adapter(s) Test Cases
1 Use Case Sandbox Tests Merchant integration with Payment Gateway Sandbox Test Adapter Provided by optile
2 Provider Sandbox Tests Provider sandbox functionality and configuration Sandbox Real adapters Provided by provider(s)
3 Provider Live Tests Provider live configuration Live Real adapters Basic cases (real money)
4 Live Monitoring Real life processing Live Real adapters Real customer payment
Use Case Sandbox Tests (1)

The Payment Gateway enables you to test the "happy path" (a success is returned) as well as negative responses (e.g. denials) and edge cases (e.g. chargebacks) in the Sandbox environment. You configure the "Test Adapter" (TESTPSP) in the background and this way you can easily double check the integration of your system(s) with the Payment Gateway.

The Test Adapter will respond according to the given payment amount and therefore confront your system with different kinds of behavior as shown in the table below. Note that depending on the features you implemented you only need a subset of test cases. The features are identified by codes that are also used throughout the documentation.

The provided cases are primarily intended for automated testing. For 'redirect' methods such as PayPal there will be a redirect to a dummy page provided, containing buttons that simulate different behavior (successful payment or customer abort). However, they only take reliably effect if none of the following test cases are used. If one of these test cases is triggered, no button should be clicked, and the OPG will proceed with status transitions according to the test case. Clicking a button in this case would result in conflicting status notifications.

Notes:
  • "sync or async provider": The test adapter can simulate two kinds of payment providers. Therefore, most test cases exist two times, one for each provider type:
    • synchronous: There is an immediate reply from the provider. Most providers behave like this.
    • asynchronous: There is an intermediate state ("pending") as a reply and first notification. Usually some seconds later the final information will be available (asynchronous), delivered via notification. An example is the provider Adyen.
  • Interaction Codes are only listed when relevant, i.e., for frontend interactions. Otherwise only the Status Codes should be evaluated.
Testcases for Frontend Checkout and Chargebacks:
Test Case # Payment Amount Feature Code Test Case Name sync or async provider Test Steps / Calls Charge statusCode (reasonCode) result(s) Charge interaction Code (Reason) result(s) Note
101 1,01 CHECKOUT Successful frontend payment sync LIST, CHARGE charged PROCEED (OK)  
102 1,02 CHECKOUT Failed frontend payment (technical reason) sync LIST, CHARGE failed ABORT (1)
103 1,03 CHECKOUT Declined frontend payment (business reason) sync LIST, CHARGE declined RETRY (1)
104 1,04 CHECKOUT Successful frontend payment async LIST, CHARGE pending, charged PROCEED (PENDING), PROCEED (OK)  
105 1,05 CHECKOUT Failed frontend payment (technical reason) async LIST, CHARGE pending, failed PROCEED (PENDING), ABORT  
106 1,06 CHECKOUT Declined frontend payment (business reason) async LIST, CHARGE pending, declined PROCEED (PENDING), RETRY  
107 1,07 CHECKOUT Payment expired due to customer inactivity (e.g., prepayment not done, actions on redirected page not completed) async LIST, CHARGE pending, aborted PROCEED (PENDING), ABORT  
108 1,08 CHARGEBACK   -

LIST, CHARGE,charged_back

CHARGE success, charged_back PROCEED (OK)  
109 1,09 CHARGEBACK   - LIST, CHARGE, information_requested, charged_back CHARGE success, information_requested, charged_back PROCEED (OK)  
110 1,10 CHARGEBACK   - LIST, CHARGE, information_requested, charged CHARGE success, information_requested, charged PROCEED (OK)  
111 1,11 REDIR Customer gets redirected for frontend charge and completes payment async LIST, CHARGE pending, charged PROCEED (PENDING), PROCEED (OK) (2)
112 1,12 REDIR Customer gets redirected for frontend charge and cancels payment async LIST, CHARGE pending, aborted PROCEED (PENDING), ABORT  
119 1,19 CHARGEBACK   - LIST, CHARGE, charged_back, chargeback_canceled CHARGE success, charged_back, chargeback_canceled PROCEED (OK)  
120 1,20 CHECKOUT Failed frontend payment (business  reason) sync LIST, CHARGE failed TRY_OTHER_NETWORK  
121 1,21 CHECKOUT   sync

LIST,

CHARGE

failed TRY_OTHER_ACCOUNT  
122 1,22 CHARGEBACK   - LIST, CHARGE, information_requested (notification_of_chargeback), charged_back CHARGE success, information_requested, charged_back PROCEED (OK)  

(1) In real world the interaction code could vary
(2) Outcome depends on customer interaction, which can also be done with the provided test adapter. Redirections always mean asynchronous communication.

Testcases for Payout of Transactions (AKA "Refunds"):
Test Case # Payment Amount Feature Code Test Case Name sync or async provider Test Steps / Calls Charge statusCode result(s) Charge interaction Code (Reason) result(s) Note
201 2,01 PAYOUT-TX Successful full refund of a previous transaction sync LIST, CHARGE, PAYOUT charged, paid_out PROCEED (OK), PROCEED (OK)  
202 2,02 PAYOUT-TX Failed full refund of a previous transaction sync LIST, CHARGE, PAYOUT charged, failed

PROCEED (OK), TRY_OTHER_NETWORK

 
203 2,03 PAYOUT-TX Declined full refund of a previous transaction sync LIST, CHARGE, PAYOUT charged, declined PROCEED (OK), RETRY  
204 2,04 PAYOUT-TX Successful full refund of a previous transaction async LIST, CHARGE, PAYOUT pending, charged, pending, paid_out PROCEED (PENDING), PROCEED (OK), PROCEED (PENDING), PROCEED (OK)  
205 2,05 PAYOUT-TX Failed full refund of a previous transaction async LIST, CHARGE, PAYOUT pending, charged, pending, failed

PROCEED (PENDING), PROCEED (OK), PROCEED (PENDING),

ABORT

 
206 2,06 PAYOUT-TX Declined full refund of a previous transaction async LIST, CHARGE, PAYOUT pending, charged, pending, declined

PROCEED (PENDING), PROCEED (OK), PROCEED (PENDING),

RETRY

 
207 2,07 PAYOUT-PART Successful partial refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial) charged, paid_out PROCEED (OK),  
208 2,08 PAYOUT-PART Failed partial refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial) charged, failed PROCEED (OK),  
209 2,09 PAYOUT-PART Declined partial refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial) charged, declined PROCEED (OK), RETRY  
210 2,10 PAYOUT-PART Successful partial refund of a previous transaction async LIST, CHARGE, PAYOUT(partial) pending, charged, pending, paid_out PROCEED (OK),  
211 2,11 PAYOUT-PART Failed partial  refund of a previous transaction async LIST, CHARGE, PAYOUT(partial) pending, charged, pending, failed PROCEED (OK),  
212 2,12 PAYOUT-PART Declined partial refund of a previous transaction async LIST, CHARGE, PAYOUT(partial) pending, charged, pending, declined PROCEED (OK), RETRY  
213 2,13 PAYOUT-MULTI Successful multiple refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial), PAYOUT (full) charged, paid_out PROCEED (OK),  
214 2,14 PAYOUT-MULTI Failed multiple refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial), PAYOUT (full) charged, failed PROCEED (OK), ABORT  
215 2,15 PAYOUT-MULTI Declined multiple refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial), PAYOUT (full) charged, declined PROCEED (OK),  RETRY  
216 2,16 PAYOUT-MULTI Successful multiple refund of a previous transaction async LIST, CHARGE, PAYOUT(partial), PAYOUT (full) pending, charged, pending, paid_out PROCEED (OK),  
217 2,17 PAYOUT-MULTI Failed multiple refund of a previous transaction async LIST, CHARGE, PAYOUT(partial), PAYOUT (full) pending, charged, pending, failed PROCEED (OK), ABORT  
218 2,18 PAYOUT-MULTI Declined multiple refund of a previous transaction async LIST, CHARGE, PAYOUT(partial), PAYOUT (full) pending, charged, pending, declined PROCEED (OK), RETRY  
Testcases for Deferred Charges:

Make sure to differentiate between the initial CHARGE and subsequent CLOSING transactions.

Test Case # Payment Amount Feature Code Test Case Name sync or async provider Test Steps / Calls CHARGE / CLOSING statusCode result(s) CHARGE / CLOSING interaction Code (Reason) reply Note
401 4,01 DEFER Successful deferred Charge sync LIST, CHARGE CHARGE: preauthorized PROCEED (OK) Credit Cards or Direct Debit
402 4,02 DEFER Failed deferred Charge sync LIST, CHARGE CHARGE: failed ABORT  
403 4,03 DEFER Declined deferred Charge sync LIST, CHARGE CHARGE: declined RETRY  
404 4,04 DEFER Successful deferred Charge async LIST, CHARGE CHARGE: pending, preauthorized PROCEED (PENDING)  
405 4,05 DEFER Failed deferred Charge async LIST, CHARGE CHARGE: pending, failed PROCEED (PENDING)  
406 4,06 DEFER Declined deferred Charge async LIST, CHARGE CHARGE: pending, declined PROCEED (PENDING)  
407 4,07 DEFER Demanded Charge (e.g., prepayment) that expired due to missing customer payment async LIST, CHARGE CHARGE: pending, request_expired PROCEED (PENDING)  
408 4,08 REDIR & DEFER Successful deferred Charge with Redirect network async LIST, CHARGE CHARGE: pending, preauthorized PROCEED (PENDING) e.g., PayPal
409 4,09 DEFER Deferred Charge that expired due to missing Closing sync LIST, CHARGE CHARGE: preauthorized, preauthorization_expired PROCEED (OK)  
410 4,10 DEFER Successful deferred Charge and full Closing sync LIST, CHARGE, CLOSING (full) CLOSING: charged PROCEED (OK)  
411 4,11 DEFER Successful deferred Charge, failed full Closing sync LIST, CHARGE, CLOSING (full) CLOSING: failed ABORT  
412 4,12 DEFER Successful deferred Charge, declined full Closing sync LIST, CHARGE, CLOSING (full) CLOSING: declined RETRY  
413 4,13 DEFER Successful deferred Charge and full Closing async LIST, CHARGE, CLOSING (full) CLOSING: pending, charged PROCEED (PENDING)  
414 4,14 DEFER Successful deferred Charge, failed full Closing async LIST, CHARGE, CLOSING (full) CLOSING: pending, failed PROCEED (PENDING)  
415 4,15 DEFER Successful deferred Charge, declined full Closing async LIST, CHARGE, CLOSING (full) CLOSING: pending, declined PROCEED (PENDING)  

(1) CANCEL is not a transaction itself, therefore the status of the corresponding CHARGE will be affected and returned.

Testcases for Recurring Charges:
Test Case # Payment Amount Feature Code Test Case Name s/a Test Steps / Calls statusCode result(s) CHARGE interaction Code (Reason) reply
701 7,01 RECUR Successful Recurring Registration sync LIST, CHARGE, CHARGE (recurring)

Init. CHARGE: charged

CUSTOMER: registered

Rec. CHARGE: charged

Init. CHARGE: PROCEED (OK)

Rec. CHARGE: PROCEED (OK)

Testcases for ADM

Please note that these cases are applicable only to recurring charges.

Test Case # Payment Amount Feature Code Test Case Name s/a Test Steps / Calls statusCode result(s) CHARGE interaction Code (Reason) reply
801 8,01 ADM-EXCEEDS_LIMIT   sync

Recurring CHARGE, (ADM - failed),  (ADM - failed), (ADM - successful)

CHARGE failed, CHARGE failed,  CHARGE success

ADM for interaction RETRY - EXCEEDS_LIMIT

802 8,02 ADM-EXCEEDS_LIMIT-FAILED   sync

Recurring CHARGE,  (ADM - failed), (ADM - failed), (ADM - failed)

CHARGE failed ADM for interaction RETRY - EXCEEDS_LIMIT
803 8,03 ADM-DECLINED   sync

Recurring CHARGE,  (ADM - failed), (ADM - failed), (ADM - successful)

CHARGE failed, CHARGE failed,  CHARGE success ADM for interaction RETRY - DECLINED
804 8,04 ADM-DECLINED-FAILED   sync

Recurring CHARGE, (ADM - failed), (ADM - failed), (ADM - failed)

CHARGE failed ADM for interaction RETRY - DECLINED
805 8,05 ADM-TEMPORARY_FAILURE   sync

Recurring CHARGE => (ADM - failed) => (ADM - failed) => (ADM - successful)

 

CHARGE failed, CHARGE failed,  CHARGE success ADM for interaction RETRY - TEMPORARY_FAILURE
806 8,06 ADM-TEMPORARY_FAILURE-FAILED   sync

Recurring. CHARGE => (ADM - failed) => (ADM - failed) => (ADM - failed)

 

CHARGE failed ADM for interaction RETRY - TEMPORARY_FAILURE

Magic Numbers

We ask merchants to unrestrictedly go through the following testing phases before going live.

# Test Phase Test Target OPG system Adapter(s) Test Cases
1 Use Case Sandbox Tests Merchant integration with Payment Gateway Sandbox Test Adapter Provided by optile
2 Provider Sandbox Tests Provider sandbox functionality and configuration Sandbox Real adapters Provided by provider(s)
3 Provider Live Tests Provider live configuration Live Real adapters Basic cases (real money)
4 Live Monitoring Real life processing Live Real adapters Real customer payment

Please sign in to view further details of this article. Login

Web Content Display

SDK Resources

Web Content Display

PHP Developer Resources

Here you find a PHP SDK for the OPG server payment API available for download.

opg-payment-php-sdk-1.0.zip

This contains a simple demo shop with an API client and model implementation in PHP that covers server-to-server communication (in the folder PaymentClient). It contains all model classes and all communication methods to manage LISTs (ListApi class), CHARGEs (ChargeApi class) and PAYOUTs (PayoutApi class). Please read the included readme.md for further information.

Please note that the PHP SDK is updated on request. Please contact us if you plan to integrate it with more features than those mentioned.

PHP Developer Resources

Here you find a PHP SDK for the OPG server payment API available for download.

Please sign in to view further details of this article. Login

Web Content Display

Java Developer Resources

Here you find the Java Model Classes for the OPG server payment API available for download.

oscato-model-download.zip

Please note that this contains the model for a server-to-server client. If you are looking for JavaScipt to run in a web browser for client-to-server communication, have a look at our AJAX library.

Java Developer Resources

Here you find the Java Model Classes for the OPG server payment API available for download.

Please sign in to view further details of this article. Login

Web Content Display

OpenAPI Definition

Here you find abstract definitions of the OPG payment APIs in OpenAPI ("Swagger") 2.0 format using YAML. You can use them to generate models for your API clients in a multitude of programming langues, for example Go, Java, NodeJS, Objective C, Perl, PHP, Python, Ruby, and others, using swagger-codegen.

Note there is a difference in models between the "server-to-server" communication, where your server makes requests against OPG (for example the LIST request), and the "client-to-server" communication, where a web browser or mobile app makes requests (for example the CHARGE request).

Please find available for download:

 

OpenAPI Definition

Here you find abstract definitions of the OPG payment APIs in OpenAPI ("Swagger") 2.0 format using YAML. You can use them to generate models for your API clients in a multitude of programming langues, for example Go, Java, NodeJS, Objective C, Perl, PHP, Python, Ruby, and others, using swagger-codegen.

Note there is a difference in models between the "server-to-server" communication, where your server makes requests against OPG (for example the LIST request), and the "client-to-server" communication, where a web browser or mobile app makes requests (for example the CHARGE request).

Please sign in to view further details of this article. Login

Web Content Display

Glossary

The following list is a compilation of terms used across this document to help you to better understand optile payment services.

  • Adapter: A software module running at optile that makes the connection to a particular Payment Provider, translates (payment) requests into their API and logic, and translates back into optile's unified API and status space.
  • CHARGE request: used to charge using a selected method during a payment session. It is also known in the payment industry as "capture".
  • LIST request: the initial request to optile payment API that starts a session. It responds with a list of applicable and registered methods (networks) used to build the payment page.
  • Method: a payment method, such as Visa, SEPA Direct Debit, PayPal, etc. Can typically be selected by a user on the Payment Page to make a payment, but potentially also for payouts (credits).
  • Network: often used as a synonym for Method in a technical context.
  • Payment Account: a customer payment account registered in OPG Secure Storage.
  • Payment Page: a page during the checkout flow of a merchant that allows users to select a (payment) Method.
  • Payment Provider: a PSP, card acquirer or wallet system that a merchant can use to execute online payments, often through various Methods.
  • Route: a combination of one Method and one Payment Provider that would be available in the context of a merchant configuration at optile.
  • Routing: the function to define which Payment Provider is used for a transaction with a selected (payment) method, depending on configurable parameters such as the country of origin, route cost and network availability.
  • TESTPSP: optile internal adapter used for testing purposes, it simulates the responses of a production adapter used with partner networks. It can be used by developers to test the integration with optile payment features.
  • Token: Secret values used for security. Tokens are needed for every merchant that wants to use optile APIs, they are unique for each merchant and differ between sandbox and live environments.

Glossary

The following list is a compilation of terms used across this document to help you to better understand optile payment services.

Please sign in to view further details of this article. Login

Web Content Display

FAQs

To check our FAQs, please refer to our Help Center.

Make sure to register or sign in to the Help Center to be able to view the protected FAQs. If you could not find an answer to your question, please do not hesitate to submit a ticket with your request.

Web Content Display

Hybrid & Migration Strategies

If you already have an existing payment provider setup which you want to keep while starting with optile in parallel, then there are multiple ways to achieve this, which we want to present here. They are separated into different aspects of payment provider integration, but we will use the following color coding.

A migration does not have to go through all stages depicted in the diagrams. Typically only one or two stages may be chosen.The stages are just ordered by the deepness of their optile integration to give conceptual orientation.

In the following description, legacy methods means those payment methods that make up your current payment page, i.e., for which you have an existing integration directly with the payment respective provider(s).

Payment Page

Static Payment Page: Most merchants have a "hard-coded" payment page, or their own selection logic which payment methods should be displayed for an individual transaction. We assume that this is typically handled on server-side. Provider routing is rarely implemented.

Use routing recommendations only: With the help of optile's Open Routing feature the legacy payment page can be used, only the decision which provider should be used for a payment request would be based on optile's LIST response. This requires all payment method forms and provider integrations to be already present on your system.

Static Redirects / Static Forms with Standalone Charge: The legacy payment page will be used, so the payment page forms and selection has to be present on your side. However, the payment request for all or some payment methods will be done through optile, using the Standalone Charge feature. This is very simple for methods that require a redirect only. For others the corresponding input forms have to be accurately modeled. In any case the configured possibilities on optile side need to always support the choices presented by the merchant's payment page. As a result there is a technical provider-independence for the optile methods, but the payment page is still limited to the methods coded in your system, so it's not "implement once".

Server-side method list merge: Here optile is configured to offer payment methods that complement the legacy ones. Therefore optile's LIST response will be read out and its methods merged with those that are still handled by your system. This requires visual merge logic and a case distinction on submit on your system, but if generically implemented this is already an "implement once" solution, meaning you could add methods and providers on runtime. Also, a step-by-step migration of legacy payment methods is easy, because you can remove your system's representation of them on the page and add them to optile instead.

Hybrid Page with AJAX library: Also in this approach there will be a mix of legacy and optile methods on the payment page. Instead of orchestrating this on your server-side, however, the optile AJAX library will inject the optile methods on client side and will also support the distinction on submit (going to legacy or optile endpoints). Therefore it requires only minimum implementation effort on your side. See the separate chapter on Hybrid AJAX page for a detailed documentation.

Own page intelligence / scoring: You are basically using optile's dynamic payment page. However, you employ your own (or third-party) customer scoring system to dynamically select the payment methods to be shown for each session. You can use this information to further limit the optile-originating set of methods via the preselection.networkCodes array in the LIST request. In theory you could also filter on your side, but for integration scenarios that have a CHARGE request directly from the client this leaves a loophole for proficient end customers to still other methods. If you also employ your own provider routing logic, you can continue doing so by using optile's Open Routing functionality and override optile's routing recommendation in the CHARGE request. In any case.

Fail-over payment page: You are using optile's full payment page (optionally with the aforementioned own intelligence or scoring), but you keep your legacy page as a fallback, which you could switch to in case optile was not reachable at some point (which you will hopefully and probably not experience).

In addition to the frontend please keep in mind that in most cases you should have a listener for Status Notifications and other backend processes in place too.

Hybrid & Migration Strategies

If you already have an existing payment provider setup which you want to keep while starting with optile in parallel, then there are multiple ways to achieve this, which we want to present here. They are separated into different aspects of payment provider integration, but we will use the following color coding.

A migration does not have to go through all stages depicted in the diagrams. Typically only one or two stages may be chosen.The stages are just ordered by the deepness of their optile integration to give conceptual orientation.

In the following description, legacy methods means those payment methods that make up your current payment page, i.e., for which you have an existing integration directly with the payment respective provider(s).

Please sign in to view further details of this article. Login

Web Content Display

Hybrid AJAX Page

We offer a simple way to use your existing payment methods (called legacy methods here) and optile powered methods together on a hybrid payment page, using the Selective Native or Display Native integration with the hybrid functionality of our AJAX library.

The idea is that you keep your existing method list, submit button, and logic. With the help of optile's AJAX library you append optile's methods to your payment method list (visually). For optile's methods you use optile's submit logic (also through the AJAX library) which is technically triggered by a separate submit button. However both, your legacy submit button and optile's submit button have exactly the same look and they get interchanged automatically and without user's notice, depending on which payment method is selected. If you prefer, you can also extend your existing submit button instead of having two that interchange. See the variation below step 4 for that option.

In any case you can keep your existing methods and logic. The addition of optile methods will only require one small change in your HTML (step 1), one server-side initialization call against OPG (step 2), and one JavaScript callback function from your side (step 3). Step 4 depends on which buttons you want to use. The rest will be taken care of by optile's AJAX library.

Step-by-Step Guide

1. Integrate optile's payment method list (through its AJAX library)

Integrate optile's AJAX library into your payment page as described in AJAX Library Integration. The placeholder for optile's methods (the paymentNetworks div) should go directly below (or above) your existing method list. Adjust the CSS in a way that the optile method list appears in the same visual style as your legacy list. Hide the radio buttons, add borders, add highlight styling for selected entries using CSS selectors, adjust sizes or whatever else is necessary. In the initialization call to the library add the deselectLegacyMethods function (see step 3.2). The payButton ID identifies the button that should be used for optile methods, not your legacy button (see step 4 how you can spare this and extend your own button instead).

2. Integrate optile's LIST request

In order to initialize optile's payment method list your system first needs to make an (authenticated) LIST request from your server-side to the OPG. This should happen when the user navigates to the payment page. As integration parameter you can use SELECTIVE_NATIVE or DISPLAY_NATIVE.

The resulting LIST ID should then be used to initialize the AJAX library on the payment page. The library will in turn fetch the payment methods available through optile's logic and the corresponding resources, and will render the list into the placeholder from step 1.

3. Combine the lists

Currently we have two lists which both can have one payment method selected. Now we need some logic that makes sure that in total only one method can be selected. This means when the user selects a method in one list, any potential selection in the other list has to be removed.

Let's look at the two cases:

3.1. If the user selects any method from the legacy list make your system call this function in optile's AJAX library: deselectDynamicMethods() - This will remove any existing selection in the optile list. Also it will hide optile's submit button, if it was given in the initialization. Make sure you show your legacy button in this case.

3.2. If the user selects any method from the optile list, the AJAX library will detect this and invoke the deselectLegacyMethods callback function that you indicated in the init call. You should implement this function in a way that is deselects all methods in your legacy list and, if applicable, hides your legacy button. optile's AJAX library will automatically show the optile button, if it was given in the init call.

4. The submit button

If you go with the two button option you have a very clear separation of the submit flows. Make sure both buttons look exactly the same and hide the correct one on page load. Detect when the user selects a legacy method, show your legacy button and invoke optile's JavaScript function from 3.1. which will also hide the optile button. Your callback function from 3.2. should in turn hide your legacy button while optile's AJAX library will show the optile button, if given in the init call.

As a result, a click on the currently visible button will either trigger your existing logic, or it will be an optile submit to OPG.

Variation: Extend your submit button

In case you already have a listener to your submit button you could also extend its logic instead of having a separate optile button.

In this variation you don't have a separate optile button on your payment page, and therefore you don't pass the payButton ID to the AJAX libraries' init call. As a consequence the JavaScript functions from 3.1. and 3.2. would still run as described, making sure only one entry in both payment method lists is selected, but now they don't show or hide submit buttons any more. Reflect this in your implementation of the callback function from 3.2.

The listener on your button, however, now needs to check before data submission, if a legacy or an optile method is selected. In case of a legacy method it can just proceed as before. In case of an optile method it should invoke the AJAX libraries' function: optilePaymentAction()

This will perform a validation first, and on success execute the transaction with OPG. If you want to skip the validation step, you can also call optileOperationAction() instead (which we don't recommend in general).

As a result, there is one button which invokes a different submission logic, depending on the selected method.

This functionality of the AJAX library will be provided within a few weeks after requested by a customer. Please contact us when interested.
AJAX library Initialization call example

$('#paymentNetworks').checkoutList({
  baseUrl: "https://api.live.oscato.com/pci/v1/",
  listId: someVariable,
  deselectLegacyMethods: yourCallbackFunctionName
});

Hybrid AJAX Page

We offer a simple way to use your existing payment methods (called legacy methods here) and optile powered methods together on a hybrid payment page, using the Selective Native or Display Native integration with the hybrid functionality of our AJAX library.

Please sign in to view further details of this article. Login

Web Content Display

Methods & Providers Special Cases

Since most PSPs require hard-coding on the merchant side to integrate different payment methods, we are often asked:

"How do I integrate this method or this provider?"

The answer for optile is in general: Simply stick to the unified flow of the LIST request and CHARGE request (and others as laid out in this documentation) and let your system listen to the Notifications. optile's API unification will make it work for all methods and providers.

You do not have to, and you should not hard code methods or forms in your system (except for Half Native Integration). Instead, include them dynamically as they provided in the LIST responses during runtime. This way, you lower you implementation and maintenance effort and profit from optile's dynamic payment page functionality, which adapts to payment amounts, customers, countries, etc.

Having said that, there are cases where a method or provider requires LIST attributes that are otherwise optional, or has other specifics regarding their technical integration. We try to give you an overview here. Please note, however, that also payment provider APIs can behave differently for different setups, so thorough testing with all combinations of providers and methods is always required.

Web Content Display

Installment Payment

Paying with installments comes with special risks. One of the consequences is a two-step form for the user, see ACTIVATE Request for technical details.

IP Address Required

Most installment providers will require the current IP address of the customer, so please provide it in the LIST Request as clientInfo.ip.

Customer Name, Billing and Shipping Addresses

Typically, customer name and addresses are also required.

There are two NetworkConfiguration flags that you can set to not include the corresponding method in the LIST Response under the following circumstances:

  • Exclude for different Shipping and Billing Addresses: If set to true this method will not be displayed if the LIST Request contained both, customer.address.shipping and customer.address.billing explicitly and any of the fields are not equal by string comparison (this includes the case when a field is undefined in one address, but exists in the other).
  • Exclude for different Shipping and Billing Names: If set to true this method will not be displayed if the LIST Request contained both, customer.address.shipping.name and customer.address.billing.name explicitly and any of the fields inside the name objects are not equal by string comparison (this includes the case when a field is undefined in one name object, but exists in the other).

Note: If the Name check excludes the method, also the Address check will exclude it, but not vice versa. In that sense the Address check is more strict. The Name check would still allow a different address as long as the recipient name is equal.

To make use of this feature, be sure to provide the customer name(s) explicitly in the address objects, not in the generic customer.name object.

This configuration can be applied to any other method, too, but for installments it is especially important.

URL to Data Privacy Guideline

In the first step of the installment form the user will give their consent to data privacy guidelines that allow the provider to do checks about the customer with external parties. These guidelines are linked, and this URL needs to be configured on the OPG side. Please contact our support about the dataPrivacyConsentUrl as part of the NetworkConfiguration as long as this option is not available in the portal. We recommend that you provide generic guidelines that fit to any of your providers. If you have only one installment provider you can also use a URL provided by them.

Base URL for Contract PDF

In the second step of the installment form there is a link to a PDF, which officially summarizes the conditions for the user. This is generated by the provider, but to make it more trustworthy, it should come from your domain. Therefore we offer you to configure a Document Proxy Base URL for your Division, e.g.:

http://www.example.com/docs.

The link in the customer form will then point to that URL with a parameter bedu attached. bedu is for base64 encoded document url. This could result in:

http://www.example.com/docs?bedu=aHR0cHM6Ly9yZXNvdXJjZXMubGl2ZS5vc2NhdG8uY29tL3Jlc291cmNlL2RvYy81N2UzOWIyYjQyL2NyZWRpdC5wZGY=

When this URL is requested your server should decode the parameter value from base64, which again contains a URL, in this example:

https://resources.live.oscato.com/resource/doc/57e39b2b42/credit.pdf

From this URL the PDF should be streamed to download for the customer. Note that it is an optile domain, which again acts as a proxy because some installment providers require additional authentication to retrieve the PDF.

If you do not configure your own Document Proxy Base URL, the optile proxy will be used for the link. This is not perfect, because it is an unknown domain for the user, but functionally, it will work.

The bottom line is that we recommend to build your own document proxy. All it has to do is decode the bedu parameter and stream the PDF from whatever URL is encoded there.

Installment Payment

Please sign in to view further details of this article. Login

Web Content Display

Intercard

There are some fields that are mandatory for an Intercard payment (in addition to optile's mandatory fields):

  • Customer#Name#firstName
  • Customer#Name#lastName
  • Mandate#reference
  • Mandate#MandateAuthentication#time

Intercard

Please sign in to view further details of this article. Login

Web Content Display

MuchBetter

When using MuchBetter, the customer is asked to confirm a transaction started on the merchant shop within their proprietary mobile application.

That means that a transaction on MuchBetter will stay on statusCode: pending until the customer logs in the app and approves the payment, and will change to statusCode: charged after confirmation.

By MuchBetter's own implementation guidelines, a merchant is required to include the following message after requesting for a payment:

"Please complete the payment in your MuchBetter app".

On a similar pattern, when implementing payouts a merchant is required to include the following message after request:

"Your funds will be with you shortly".

MuchBetter

When using MuchBetter, the customer is asked to confirm a transaction started on the merchant shop within their proprietary mobile application.

Please sign in to view further details of this article. Login

Web Content Display

PayPal, Sofort & Redirect Networks

  • These methods we call redirect networks because to complete the payment your customer has to be redirected to an external page of the corresponding provider.
     
  • However, your system does not need extra logic to take care of this. In any case it should redirect the customer if a redirect URL is given in the CHARGE Response. This also applies to non-redirect networks. In this case the user will be redirected to the successUrl or cancelUrl you provided in the LIST Request.
  • In many (but not all) cases these networks do not have an input form that can be displayed directly inside the payment page. Additionally, you do not need extra logic to cover this. The form snippets provided in the LIST Response should be included as always, they will just be empty.

PayPal, Sofort & Redirect Networks

Please sign in to view further details of this article. Login

Web Content Display

SEPA and BACS Direct Debit

SEPA (or BACS in the UK) offers a direct debit payment scheme used across Europe. When integrating this method, a merchant requests a mandate from its customer, which is used as authorization to collect payments via direct debit from the customer bank account. We give details for the integration of this method below.
  • Your system should generate and send additional information about the mandate (e.g., the proposed mandate reference) in the LIST or CHARGE Request (via the mandate parameter structure). Please note that the mandate reference should be shorter than 35 characters and alpha numeric.
  • The existing mandate information should also be sent when requesting Recurring Charges.
  • You should include in the payment.reference parameter a message in the format "Shop-URL, Shop-Hotline/Support e-mail, and transaction ID". See example in the right pane.
  • In the CHARGE Response and Status Notification your system will receive the final mandate values being used by the PSP for this transaction (because depending on your contract it may use its own values).

More information about the Mandate:

Mandate {

reference (string): 

The SEPA mandate reference (aka Mandate ID) proposed by the merchant has to be unique in the scope of the merchant's creditorId

creditorId (string, optional): 

The SEPA creditor ID of the merchant  could also be configured for some PSPs within a contract which is optional. In case when a PSP uses its own creditor ID, it will be returned in the reply and the status notification

authentication (MandateAuthentication, optional):  Required by some PSPs for SEPA transactions

Below we present a generic diagram for the payment flow:

Payment Sequence Diagram - SEPA
Example Mandate Reference

{
  "transactionId": "93acf8c4-dbb3-411c-b9fb-abc123c3f7aa",
  "country": "DE",
  "channel": null,
  "division": null,
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "notificationUrl":"https://dev.oscato.com/shop/notify.html",
    "summaryUrl": null
  },
  "customer": {
    "number": "123ABC",
    "email": "john.doe@example.com",
    "birthday": null,
    "name": {
      "title": null,
      "firstName": "FIRST_NAME",
      "middleName": null,
      "lastName": "SECOND_NAME",
      "maidenName": null
    },
    "addresses": null,
    "phones": null,
    "registration": null
  },
  "clientInfo": null,
  "payment": {
    "reference": "www.shop.com, contact support@shop.com - TiD 123456789",
    "amount": 89,
    "currency": "EUR",
    "invoiceId": null,
    "longReference": null
  },
  "products": null,
  "updateOnly": false,
  "presetFirst": false,
  "style": {
    "language": "en",
    "theme": null,
    "cssOverride": null,
    "client": null
  },
  "preselection": {
    "deferral": "ANY"
  },
  "extraElements": null,
  "mandate": {
    "reference": "Authorization for shop.com",
    "creditorId": null,
    "authentication": {
      "time": "543836748822",
      "city": null
    }
  },
  "installment": null
}

SEPA and BACS Direct Debit

SEPA (or BACS in the UK) offers a direct debit payment scheme used across Europe. When integrating this method, a merchant requests a mandate from its customer, which is used as authorization to collect payments via direct debit from the customer bank account. We give details for the integration of this method below.

Please sign in to view further details of this article. Login

Web Content Display

Vorkasse (Advance Payment)

  • After the CHARGE Request the payment will be in pending status until the customer's payment has arrived and is detected by the PSP. Then your system will receive the status charged via Notification.
  • In the CHARGE Response and corresponding Notification your system will also get additional information about the bank account your customer has to transfer the money to via the remittanceAccount data structure. This should be displayed / mailed to the customer.

Vorkasse (Advance Payment)

Please sign in to view further details of this article. Login

Web Content Display

Worldpay

When using Worldpay as a PSP, make sure to pass the clientinfo in the LIST Request.

Mandatory Parameter for WorldPay

  ...,
  "clientInfo": {
    "ip": "string",
    "userAgent": "string",
    "acceptHeader": "string"
  }, ...

Worldpay

Please sign in to view further details of this article. Login

Web Content Display

Compatibility

optile software for usage by clients' users, systems, or end customers is designed to support the following web browsers and technical standards.

Supported web browsers:

  • Internet Explorer: Version 9 and higher
  • Firefox, Chrome, Edge, Safari: Current and one previous version

Mobile apps for iPhone are designed to support iOS 4 and greater.

optile APIs do support TLS 1.2 or greater.

Usage of any other web browsers, mobile operating systems, or cryptographic protocols may lead to decreased or no functionality.

Compatibility is subject to change in the course of general technological progress.

Compatibility

optile software for usage by clients' users, systems, or end customers is designed to support the following web browsers and technical standards.

Please sign in to view further details of this article. Login

Web Content Display

Enterprise Features

For Enterprise merchants we offer additional functionality. Please note that access to these features requires corresponding contracts and has to be enabled explicitly by optile. Please contact us if you want to access this functionality.

Web Content Display

Open Routing

In some cases, a merchant needs to control the routing behaviour during a payment session, not relying on the OPG's calculated routing priority (as configured via the merchant portal), but being able to programatically define custom rules for routing on their side. This is possible in Pure Native integration scenarios, with or without Client Side Encryption, by passing routing information in the CHARGE request.

LIST Request

A LIST request (POST, GET or PUT) with the additional view=routes query parameter will trigger Open Routing information for each applicable or registered network in the LIST response.

For example, a LIST request (POST) could look like: https://api.sandbox.oscato.com/api/lists?view=routes

The following rules must be respected when using routes with the view parameter:

  • If routes is present, the route information is returned in the LIST response.
  • If there are conflicting or unknown arguments like view=routes,-routes or view=abc, the request will fail as invalid. Note that open routing can be combined with other features, such as JSON Forms.
  • If there is any query parameter present other than view, it will be ignored.

The LIST response orders routes by priority according to the currently configures routing strategy. This means the first route is the one that would be tried first if a normal CHARGE was executed. Every route in this context contains the data as given in the example in the right pane, namely:

  • Contract identification, including adapter and provider codes;
  • Cost information as defined via configuration in the contracts app in the merchant portal.
Example LIST Response
{
...
"networks": {
  "applicable": [{
    "code": "MASTERCARD",
    ...
    "routing": {
      "strategy": "LEAST_COST",
      "routes": [
      {
	"contract": {
	  "id": "5a55e5780d9c031b6c5c6f5a",
	  "providerCode": "EMERCHANTPAY",
	  "adapterCode": "EMERCHANTPAY"
	},
	"costs": {
	  "normalized": 0.1,
	  "original": {
	  "amount": 0.1,
	  "currency": "EUR"
	  }
        }
      }]
    }
...
}

CHARGE Request

During CHARGE a merchant can specify the routes to be used. Additionally to the usually required parameters, one or more routes found in the LIST response should be added as seen in the example in the right pane.

Since this not something to be manipulated by the end customer, a correpsonding CHARGE needs to come from a merchant server system, therefore a Pure Native integration scenario (with or without Client Side Encryption) is required.

This is how the OPG will behave when using Open Routing during a CHARGE operation:

  • If no routing list is passed, or it is null, then the routing priority from OPG will be used.
  • If the list is empty, then no processing will take place, and the response Interaction Code will be: ABORT - INVALID_REQUEST
  • Only the passed routes will be considered for processing, in the order in which they were given.
  • Routes are identified by contract.id, like is shown in the example. If the contract.id doesn't exist at OPG, there will be an error with interaction codes ABORT - INVALID_REQUEST.
  • adapterCode and providerCode are optional inside the contract object. If any of them is passed, they need to match the configured contract. Otherwise there will be an error (and no route fallback) with interaction codes: ABORT - INVALID_REQUEST.
  • The costs data within a route can be optionally passed, but it will be ignored.
Example of CHARGE body:
{
"account": {
  "holderName": "John Doe",
  "number": "42551111111114444",
  "verificationCode": "123",
  "expiryMonth": "12",
  "expiryYear": "2019"
  },
"autoRegistration": true,
"routes": [{
    "contract": {
      "id": "33f4b0d039272d1825ec38a0",
      "adapterCode": "ADYEN-JSON",
      "providerCode": "ADYEN"
    },
    "costs": {
      "normalized": 0.06,
      "original": {
        "amount": 0.07,
        "curency": "GBP"
      }
    }
  },
  {
    "contract": {
      "id": "54f9b03ce4b0d039272d1825"
    }
  }
]}

Open Routing

In some cases, a merchant needs to control the routing behaviour during a payment session, not relying on the OPG's calculated routing priority (as configured via the merchant portal), but being able to programatically define custom rules for routing on their side. This is possible in Pure Native integration scenarios, with or without Client Side Encryption, by passing routing information in the CHARGE request.

Please sign in to view further details of this article. Login