Web Content Display

Web Content Display

Open Payment Gateway - OPG

This documentation guides you through our Payment Orchestration Open Payment Gateway (OPG) features for frontend checkout and backend use cases. It provides important information about integration scenarios, testing possibilities, and references.

For a Glossary of Terms, go to the end of this document. 

Web Content Display

First Steps

Every potential checkout webpage includes information about the purchase, payment amount, customer details, plus 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.

To test these features, you need an account for our website. If you do not have an account, please email welcome.germany@payoneer.com and we will create one for you. You can start experimenting with OPG Sandbox as soon as you get your Payment Orchestration account details.

Try your first LIST Request by following these 4 steps:

1. Configure your OPG Sandbox
  • In the portal, go to the Dashboard and open the Provider Contracts section.
  • Click on "Add a new contract". This can alternatively be done by clicking on "Add Contract" while in the Dashboard.
  • Choose Test Adapter "TESTPSP". Make sure you add a valid URL eg (http://www.dummyvalidurl.com)
  • Click on "Select Methods and Countries" under the section "Methods and Countries".
    • In "Step 1: Countries", select Germany and France.
    • In "Step 2: Methods", add payment methods Visa, Mastercard, SEPA Direct Debit and PayPal.
    • In "Step 3: Combinations", select PayPal to 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

You must generate a Token to authenticate your system against the Payment Gateway API.

To generate a Sandbox token:

  • 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. For security reasons, it will not be shown again and cannot be recovered. You can create a new one if necessary.
3. Install a tool for manual testing

We suggest that you use one of the browser plugins listed in Tools for Manual Testing so you can 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.

Find out more about authentication and version headers in API Access.

For your request you should receive 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, Carte Bleue will not show in this list.

5. Visualize the LIST

Follow the steps below to visualize the content of a generated LIST with a default style, using our Orchestration Platform's Hosted Payment Page:

  • 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/v3/responsive.html?listUrl=https://api.sandbox.oscato.com/pci/v1/59722056cb4280f9550078e3lffpph128vffgueil7chn475bs

Note: You have 30 minutes to make a successful CHARGE. After 30 minutes, you will get an error and you should create a new LIST Session (That's also why the link above will not work).

The payment page should look like the example picture below:

This payment page has all necessary capabilities to validate and process payment account input. For example, try using the following test account and then click on the Pay button:

Card number: 5500000000000004
Expiry Date: any date in the future
Security Code: any 3 digit number
Account Holder: John Doe

Using this input above will trigger instant validation, and clicking on Pay will trigger a frontend CHARGE request and should take you to the success URL defined in the LIST request. Alternatively, you can perform the CHARGE request from your backend which we will simulate together in the next step.

6. CHARGE request

The LIST response as generated in step 4. contains information about the current payment session, including all available payment networks and their attributes as seen in the array networks.applicable. In this example every network has the same attributes, but for our testing we are now only going to look at links.operation from Mastercard:

"operation": "https://api.sandbox.oscato.com/pci/v1/59722056cb4280f9550078e3lffpph128vffgueil7chn475bs/MASTERCARD/charge"

Notice that this operation endpoint starts with a reference to the current LIST long ID and ends in /MASTERCARD/charge, which means that for the Mastercard network the next operation after listing it is a charge on the customer account. This operation URL is the endpoint to which you need to submit the CHARGE request via POST.

In the case of Mastercard, the charge cannot happen without a customer account. So, the CHARGE in this case will carry also a JSON body containing the collected customer account. We can use the same data as done in the step 5. with the hosted payment page, but now mapping them into the appropriate attributes as expected by the payment API.

The CHARGE request will then be done as exemplified in the right pane, using the same authentication and headers as previously done with the LIST request.

A successful CHARGE response should contain a "charged" status code and a redirect URL to the success page as defined in the LIST request.

Play Around

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

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 like, you can 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 of how a payment page is rendered, see our Demo. 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.

From here on we recommend you to understand our Integration Scenarios and choose the one that better fits your business model. We also have more LIST use cases and backend use cases designed to cover specific checkout flows to fit your application.

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" : {
    "hostedVersion":"v3"
  },
  "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", ... }]
... }

CHARGE Request on Mastercard Account:

POST to https://api.sandbox.oscato.com/pci/v1/59722056cb4280f9550078e3lffpph128vffgueil7chn475bs/MASTERCARD/charge
With body:
{
"account": {
  "number": "5500000000000004",
  "expiryMonth": "01",
  "expiryYear": "2029",
  "verificationCode": "123",
  "holderName": "John Doe"
  }
}

CHARGE Response:

{
  "links": {
    "payout": "https://api.sandbox.oscato.com/api/charges/5c1ce635a6cd3d3efee7f84fc/payout",
    "self": "https://api.sandbox.oscato.com/api/charges/5c1ce635a6cd3d3efee7f84fc",
    "customer": "https://api.sandbox.oscato.com/api/customers/5c0533e6b55f2801861fc6c6u"
  },
  "timestamp": "2018-12-21T13:10:13.766+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"
  },
  ...
  "redirect": {
    "url": "http://localhost:3000/html/success.html",
    "method": "GET",
  ...
}

Web Content Display

Tools for Testing

We suggest that you use one of the browser plugins listed below so that you can easily submit JSON POST requests when you test.

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":"123","country":"DE","payment":{"amount":9.99,"currency":"EUR","reference":"test"},"customer":{"number":123},"callback":{"returnUrl":"https://localhost:3000/success.html","cancelUrl":"https://localhost:3000/cancel.html","notificationUrl":"https://localhost:3000/notify.html"}}' -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

API Types and Authentication

In our API Reference you will find a complete and formal documentation of all API calls. Please note the distinction between Client API and Server API. Endpoints in the Client API are designed to be accessed by frontends, eg web browsers, without authentication. For example the CHARGE Request exists in a frontend accessible version. The Server API is for calls from your servers, such as the LIST Request.

Server API calls require HTTPS Basic Authentication with these credentials:

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

To generate payment tokens, you access the Merchant Portal (requires access rights). Contact our support team at support.de@payoneer.com for help with permissions.

Do not make requests to the Server API from a browser or any other client under control of the end customer, because it would expose your credentials.

API Changes

In your contract with us we state that new API response parameters can be added in any release without explicit warning. This will not affect the existing functionality and not require further action from you. Your system only needs to be robust against additional response attributes.

For example, if you use Java with the Jackson parser for JSON, please set the FAIL_ON_UNKNOWN_PROPERTIES to false (see the official Jackson parser documentation and additional details on Stackoverflow).

Of course we will never rename any request or response parameters and never introduce new mandatory request parameters without the contractual notice periods. So with a robust system as described above you are safe.

You are contractually obliged to implement your API integration in a way that it is robust against additional response parameters.

Accept and Content Type Headers

For every request, you should set two HTTP headers:

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

For both please use the value: application/vnd.optile.payment.enterprise-v1-extensible+json

This implies communication via JSON. For the level and version part (enterprise-v1-extensible in this case) we may allow custom contractual agreements and hence additional values in the future.

CORS support in Sandbox

Although the Sandbox and Live environment APIs are generally the same, there is one slight technical difference to allow for particular testing and demonstration scenarios:

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

The Live environment only allows CORS  for the very few Client Payment API calls (see above at Authentication and the API Reference). In all other cases CORS will not return the aforementioned headers -- so a LIST Request from a browser (for example) is not possible.

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

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 our AJAX Integration.

  • Try changing the Country to see how it adapts the payment methods and language
  • 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 on a smartphone
  • In real life you can...
    • ...apply custom styling
    • ...change the payment-method configurations with a click
    • ...and much more.

 

Web Content Display

Integration Scenarios

Simple integration includes the scenarios shown below:

 

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

By contrast, advanced integration includes:

 

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 the Orchestration Platform Orchestration Platform/ OPG

SAQ A

Display Native The merchant server generates the payment page the Orchestration Platform / 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 Orchestration Platform / OPG SAQ A-EP

 

Hybrid Scenarios

If you already have integrations with payment providers or are thinking about a parallel setup where the Orchestration Platform-powered payment methods are combined with methods of other sources, there are multiple options to achieve this, depending on your specific prerequisites and needs. Please have a look at our Hybrid & Migration Strategies.

Web Content Display

Integration Scenarios Comparison

The Payment Gateway gives merchants a lot of flexibility. It allows multiple ways to integrate the frontend part of the payment processes (compared to backend interactions, which follow a standard path). Each integration scenario has different advantages, regarding effort, conversion, user experience, and security certification.

We generally recommend the AJAX Integration. It provides very good user-experience with minimum implementation effort, and it can be combined with Selective Native integration to minimize PCI requirements on your side. But a different integration scenario will make more sense for some merchant requirements: for integration with mobile devices or other devices that do not rely on web browser rendering eg 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 the Orchestration Platform 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
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 partially, 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

This is how it works:

 

1. You initialize the payment from your backend (LIST Request). Set the parameter style.hostedVersion to v3 to get the most recent version of the hosted payment page (v3). It features a full responsive design and high-resolution payment-method logos. The legacy version (v2) can be accessed by setting style.client to "RESPONSIVE" instead. In the right pane there is an example LIST response demonstrating the location of the URL of a hosted payment page.

2. Based on the information given, OPG generates a web page with all the payment methods that can be used to pay this particular transaction. As a reply, your system gets a URL to this generated page, which it typically displays is a large iFrame.

3. Once the customer finishes their interaction within the iFrame and submits the form, the payment data is sent from within the iFrame directly to the OPG. The response will go back to the iFrame, and as a result the iFrame will redirect its parent frame to the merchant's returnUrl (or cancelUrl in rare error cases) with all available status information attached as query parameters to the URL. The right pane shows an example redirect after success.

Example LIST response (extract)

{
  "links": {
    "self": "https://api.oscato.com/api/lists/e909b8f7-97fd-463e-9069-313632a9b8cc"
  },
  "resultInfo": "6 applicable and 0 registered networks are found",
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "redirect": {
    "url": "https://resources.sandbox.oscato.com/paymentpage/v3/responsive.html?listId=5e96c3abc1235e11b14543d2lrc25jnqki363v53qmn9747gdf&liveValidation=true&smartSwitch=true",
    "method": "GET",
    "suppressIFrame": false
  }
...
}

Example redirect after success

https://dev.oscato.com/shop/success.html ?
listUrl=https%3A%2F%2Fapi.sandbox.oscato.com%2Fpci%2Fv1%2F5e96c3e541f95e11b14543d2abc123nqki363v53qmn9747gdf &
shortId=0ab85-63289 &
customerRegistrationId=5e7c86b81dab523005cf2939u &
interactionReason=OK &
resultCode=00000.TESTPSP.000 &
longId=5e96c3faabc1232f3a244fe2c &
transactionId=tr101 &
interactionCode=PROCEED &
amount=10.99 &
reference=Test &
currency=EUR

Web Content Display

Selective Native with AJAX

Selective Native can be implemented using our AJAX Library, or as a native solution. In both cases, the logic behind the implementation is the same; the only difference is that native integration needs the development of your own JavaScript code, while AJAX integration uses a library provided by the Orchestration Platform.

Here's an overview of how our AJAX library communicates with the OPG and especially the Selective Native iFrames. You can use the session "AJAX library Integration" as a reference to our AJAX library.

The Orchestration Platform AJAX Integration Library enables seamless integration of the OPG payment checkout into your own websites, with minimum effort.

Essentially, the JavaScript library takes over a major part of the communication with the Orchestration Platform 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. Download the PCI DSS SAQ A requirements. You must sign the self-assessment questionnaire (SAQ) to confirm that you are compliant. This signed SAQ is also your "Attestation of Compliance (AoC)", which may be requested at any time by your acquiring bank.

Selective Native gives a level of security for credit and debit cards in the payment page that means you need only be PCI A compliant, as opposed to PCI A-EP which requires more effort. Compared to the Hosted scenario, Selective Native integration gives more flexibility over the look and feel of the page -- so you can align it more easily to your corporate design and optimal conversion rates.

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

Technical Concept

Selective Native replaces those parts on the payment page with iFrames, where necessary. This means that all credit and debit card forms will be in small iFrames that come from a fully PCI-certified Orchestration Platform domain. The card data entered by a user cannot be read from the surrounding page. That said, 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've shown you how to handle the Selective Native iFrames at a high level. Use our AJAX Library Integration as a reference if you want to implement this part on your own.

 

Communication Flow

Here is an overview of the client-server and inter-frame communication messages when you use our AJAX library:

 

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 point, you hand the long ID over to our AJAX Integration JavaScript library, and specify the HTML container element.
  2. The JavaScript library now builds 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 their payment details and 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.

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

Web Content Display

Display Native with AJAX

Here is how communication works in this scenario :

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 automatically get the full list of methods and all resources (images, HTML input forms, etc) 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 their payment details and be redirected to the 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 all cases.

For more information on how to build this scenario, go to AJAX Integration.

Web Content Display

Advanced Integrations

Web Content Display

Selective Native

Selective Native can be implemented as a native solution or by using our AJAX Library. In both cases, the logic behind the implementation is the same; the only difference is that a native integration requires the development of your own JavaScript code, while an AJAX integration uses a library provided by the Orchestration Platform.

For an overview of Selective Native, go to Selective Native with AJAX.

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

Web Content Display

Display Native

For users without web browser rendering (eg native mobile apps) there is Half-Native Integration a variation of Display Native integration.
Display Native Integration

  1. You initialize the payment from your backend (LIST Request) and, based on the information provided, OPG replies with a JSON structure containing all possible payment methods that can be used for this particular transaction (LIST Response). With every network, there is also an HTML snippet representing the corresponding form where the customer needs to fill in their payment account details (eg 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 (ie 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.
Note

Redirect Networks such as, for example, Sofortüberweisung 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 (eg the PayPal login screen). After this step, the customer will be redirected back to your system. For you this is transparent, you do not need to do anything about 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 direct to the client and not to the Merchant's server system.

Read more about how to analyze the LIST Response.

Localized Forms

To implement Orchestration Platform's localized forms snippets returned from the original List response, please see Localized Forms section.

Web Content Display

Mobile Native

MOBILE NATIVE is a dedicated integration for native mobile applications and orchestration platform's Mobile Checkout SDKs. It was built with mobile applications in mind, so that mandatory fields required by native applications are supplied within the LIST request, and the LIST object content is tailored to mobile application needs. Using the MOBILE NATIVE integration with our mobile SDKs will allow you to keep your PCI DSS certification effort low - PCI-A.
 
Our SDKs are currently in beta. Find out more about them in the SDK section.
 
LIST creation
 
The flow between your shop application (and the SDK), your backend system and OPG is the same as in the DISPLAY NATIVE integration. For further information, see the diagram in the Display Native section.
 
The LIST request itself differs from that of the Dislay Native. The callback URLs in the LIST request are replaced with the application ID, resources inside the LIST object are in JSON format, and so on. See the example on the right for the details of the LIST request.
 
 
{
    "transactionId": "tr_1001",
    "integration": "MOBILE_NATIVE",
    "channel": "MOBILE_ORDER"
    "country": "DE",
    "customer": {
        "number": "1",
        "email": "john.doe@optile.net"
    },
    "payment": {
        "amount": 0.99,
        "currency": "EUR",
        "reference": "Shop optile/04-03-2020"
    },
    "style": {
        "language": "en_US"
    },
    "callback": {
        "appId": "com.payoneer.checkout.examplecheckout.sdk",
        "notificationUrl": "https://dev.oscato.com/shop/notify.html"
    }
}
Callbacks
 
In contrast to other integration scenarios, MOBILE NATIVE doesn't require returnUrl, summaryUrl and cancelUrl. Instead, you need the callback.appId in the LIST request. It enables a successful return from a provider's website (opened in an external browser) after a successful or a failed payment attempt in a 3rd party website (redirect networks). This applies also for credit/debit card payments which mandate a 3DS authentication which is done in an external website.
The Mobile Checkout SDK uses this unique appId as the identifier for making sure the mobile app is reopened after the browser window is closed.
See the example of the callback mobile-redirect URLs:
 
"callback":
{
    "appId": "com.payoneer.checkout.examplecheckout.sdk",
    "notificationUrl": "https://dev.oscato.com/shop/notify.html"
}

Web Content Display

Pure Native

Pure Native Integration

Native integration means you build the payment checkout page yourself, based on the information provided by the LIST response, on your server side. It gives you full control and seamless integration into your pages.

In native scenarios, you can send the payment data submitted by your customers, 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 permitted to do so by your PCI DSS certification.

Pure Native integration lets you pass sensitive data through any of your servers that process cardholder data. In this scenario the merchant must have PCI SAQ D certification.

 

These requirements must be checked, signed, and submitted for revision if necessary.

 

For the LIST Request and payment-page rendering, this scenario is like the Display Native scenario except that here, the sensitive payment-account details go from the payment checkout page to your own servers first, where they can be stored or analyzed by your custom logic. From there, the CHARGE Request is submitted to OPG.

Note that under credit-card industry regulations, you are only allowed to process credit-card details on your servers if you have the appropriate PCI DSS certification. This covers not only storage of data but also in-memory processing.

Read more about how to analyze the LIST Response.

Localized Forms

If you wish to implement Orchestration Platform's localized forms snippets returned from the original List response, go to Localized Forms section.

Web Content Display

Pure Native with CSE

Process Flow of Client-Side Encryption

The Orchestration Platform will provide you with a public key for encryption in advance. You should store this key because, later on or during the process, the software-client of the user (eg web page in browser, but possibly also mobile clients) will use it.

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. But, the Orchestration Platform's  AJAX library is not ideal for building the client-side payment page for client-side encryption, since it submits payment data direct to the OPG instead of your custom endpoint. If you want to use it anyway, you can request a development version of the library and then adjust it to your needs.

For this flow to comply with PCI A-EP level compliance, the payment-account data (eg card data, SEPA IBAN etc) entered by the customer must be encrypted by the client so that only the Orchestration Platform can decrypt it. To make that happen, this flow uses the public key referred to above, and the algorithms and data structures described below. Next, you have a choice: you can use the timestamp of encryption and/or the ID of the LIST session for encryption, to assure that the card data is being used for this specific payment session.

In a web context, the Orchestration Platform will provide a JavaScript library providing a function that handles the encryption for you. Your client can then send the encrypted data anywhere to your systems. As your server systems will not be able to decrypt the data without access to the Orchestration Platform'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 is a simultaneous response to your server systems, with all relevant information. The OPG will also send the Status Notification that your server systems would need in other integration scenarios, but it is less significant 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 view of the process:

  1. The LIST Request and payment-page rendering are very similar to a Pure Native implementation.
  2. But, sensitive account-data are encrypted on the customer-client before being sent to your servers.
  3. From there, the CHARGE Request is submitted 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 under credit-card industry regulations, you must ensure that you have the appropriate PCI DSS certification for processing credit-card details on your servers. This covers not only storage of data, but also in-memory processing. Owing to the nature of the Client-Side Encryption, PCI A-EQ level certification is required.

Read more about how to analyse the LIST Response.

Localized Forms

To implement Orchestration Platform's localized forms snippets returned from the original List response, go to Localized Forms.

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 direct, because the input forms for the payment methods are described in HTML.

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

The idea of Half-Native therefore 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, eg 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 enters the necessary payment data, the client typically submits it direct to the Payment Gateway via a CHARGE Request -- in the same way as for the Display Native Scenario.  An immediate response and a Status Notification will be sent to your server system.

A corresponding communication sequence looks like this:

Alternatively, the payment session could be initialized as Pure Native and the CHARGE Request issued to your server systems first. But this would affect your required PCI certification.

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, ie divide the common payment page into two separate steps.

Here, you could add some simple logic to show the radio buttons and logos on the first part of the payment page, with the second part of the payment page showing the logo and forms of a previously selected payment method with or without the possibility to still switch to a different 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 if 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 result. So note that other attributes cannot be changed.

Your system can also 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

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 regard to the query parameters, please note:

  • 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 any query parameter is present other than view it will be ignored.

If JSON forms are enabled (view=jsonForms), 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 a range 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. These types are allowed:
      • string (default): one line of text without special restrictions. For example: holder name
      • numeric: numbers from 0 to 9, space delimiters and dash ("-") are allowed. For example: card number
      • integer: only numbers from 0 to 9. For example: CVC
      • checkbox: values "true", "false", or undefined (non-existent).
      • select: a list of possible values is given in an additional options attribute (see below). For example: expiration date.
    • options (optional, present for "select" types): a range 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 yet present in OPG, 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
},
...

Web Content Display

Frontend Checkout

Web Content Display

Checkout Flow Overview

The Interactive Checkout Flow Diagram

Especially for developers we created also a systematic view of all combinations of the Orchestration Platform's checkout API flows. Switch between combinations in the selection box at top center. The diagram represents the relationship between a (typical) user journey and the corresponding API requests (with limited details).

Click here to open the Interactive Checkout Flow diagram in a new tab. Loading can take a few seconds, so please be patient...

Launch the interactive diagram in a new tab

Regular Checkout

The Orchestration Platform supports two main types of a regular checkout:

  • Regular checkout with immediate charge: Your customer arrives at the checkout page via the regular web browser, or via a remote checkout initiated by your Call Center where the list of products to be purchased is displayed. The customer is then directed to the payment page. The payment page is rendered based on how you choose to handle the Orchestration Platform's LIST Request, ie by a simple or advanced integration scenario with the OPG (more information about Integration 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 the customer will be redirected to the thank-you page. You can choose to close the sale once you make the order ready for delivery as a deferred charge.
  • Regular checkout with Summary Page: Your customer follows the path described above, but the customer is presented with a summary page after they enter 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 a few 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 deferred charge.

Web Content Display

Express Checkout

  • Express Checkout (for first-time customers): On the shopping cart page you already give your customers the option to use a specific Express method such as PayPal Express or Amazon Pay. If they choose one of them then they are directed to that provider or provider interaction elements to make the payment with a user account they already have there. Once the customers confirm on the provider side, their data such as shipping address are shared with your system. Your system would typically present a summary page for the customer to confirm in the fashion of Delayed Payment Submisison (DPS). The detailed Express Checkout documentation you can find in this separate space.
  • One-Click Checkout (for returning customers): You can speed up and improve the checkout experience for your return customers by sending these customers direct 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, you need to give your customers the option to register their account details on their initial purchase. Currently One-Click checkout is currently based on Payment Account Registrations.

Web Content Display

Payment Page: LIST Request

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.sandbox.oscato.com/api/lists
  • Method: POST
  • Authentication:
    • Login Name: registered company code
    • Password: generated API token

Explanations for some parameters in the request body:

  • transactionId is the alphanumeric identifier for this transaction, assigned by you as a merchant.
  • country is the "transaction country". It specifies which country-specifc OPG configuration and therefore payment method selection should be used. Typically it is the location of the current shop but it may also 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, see also below. Valid values are: HOSTED, SELECTIVE_NATIVE, DISPLAY_NATIVE (default) and PURE_NATIVE.
  • customer.number is the alphanumeric identifier of your customer, assigned by you as a merchant.
  • payment.reference is the short text that customers will see on their account statement.
  • style.hostedVersion with v3 will enable new version of payment page (for HOSTED integration scenarios) designed to support 3DS2 payment flows.
  • style.resolution when set to 3x will return logos with 96 px of height for devices with higher PPI. Other possible values are 1x (32px) and 2x (64px).
  • 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 if he or she cancels on a redirect page (such as PayPal), or a payment attempt 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 Reference.

Read about the LIST Response if you want to render the payment page yourself.

We highly recommend to always pass the customer number and email, even if you have to use dummy values, because many popular providers require this.
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": {
    "hostedVersion": "v3",
    "resolution": "3x"
  },
  "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 no integration parameter is specified, the LIST Request will default to Display Native.

These 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.sandbox.oscato.com/api/lists
  • Method: POST
  • Authentication:
    • Login Name: registered company code
    • Password: generated API token
Duplicate Charges

After a successful CHARGE is executed on a LIST object, the LIST will no longer be valid. This means that 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.

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 is redirected to (indicated by the cancelUrl) and inform the customer that the payment was successful and that only the repetition was declined. Otherwise the customer may think the payment failed.

Continue reading 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": {
    "hostedVersion": "v3"
  },
  "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": {
  ...

Web Content Display

Re-using a LIST Session

New LIST Request vs. reading existing LIST

A valid LIST can be seen as a payment session of the user. To enable payment conversion tracking through the Orchestration Platform, and to benefit from dynamic reactions of the payment page, we advise that you do not issue LIST Requests "blindly" but use existing LIST Objects if possible.

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

https://api.sandbox.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). Note that in this case the timer starts counting from 0 again with any CHARGE attempt.

After that, the LIST object will become invalid for security reasons and no further CHARGE will be possible. 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.

What this means for your implementation:

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

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 but not yet completed the payment. 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 described above.

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 (eg 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.sandbox.oscato.com/api/lists/ce3eec14-e186-4b7c-94a1-fde802412e69
  • Method: PUT
  • Authentication:
    • Login Name: DEMO
    • Password: BAtXa7yubR8ipuT

Note: 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, you may need to reflect resulting changes to the customer client (eg browser). Therefore, the LIST result should be read by the client again by passing it on from your server system, or by retrieving the LIST object direct 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 indicating which of the 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. The Orchestration Platform'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: other properties of a method cannot be changed through this API.

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

Code
{
  "selected": true
}

Web Content Display

Extended LIST Request

Sometimes you can improve the checkout experience by making more parameters available to the customer. For example, the products list could have more details about the goods ordered; or the customer might need to clearly specifiy their address. Some information may be required for risk management -- some invoice providers may restrict their offers if billing and shipping addresses are different, for example.

At the moment, the OPG accepts a long list of parameters in the LIST request, which you can find in our API Reference in the Server Payment API dropdown.

Products

The given products will be shown to the customer in some networks, eg 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. But, if you provide any part of the object but not userAgent or acceptHeader, the following defaults will be used for these attributes if empty:

  • 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 uses them for additional logic like risk management, we recommend that you set these attributes to the real values from the customer's original HTTP request.

Customer

While customer.number is the only required parameter, you should also consider customer.email. This enables basic identification that some providers use for risk management.

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

Addresses are specified better by the parameter addresses, which can cover shipping, billing, residential or other relevant address.

Multi shipping

One interesting use case is where a customer wants different products to be delivered to different addresses. A merchant could assign certain products to be delivered to the customer's home, some to be delivered to the customer's office, and some even to be collected at a physical store. This scenario can be achieved by several parameters:

  • A unique id for every customer address
  • A list of additionalAddresses to specify several addresses with the same type, for example home and office shipping
  • A merchantAddress (Boolean) to link one of the addresses as the physical store of the merchant
  • A shippingAddressId to link each product item with its address
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,
    "shippingAddressId": "addr-id-001"
  },{
    "code": "C003X6U523",
    "name": "The Lawnmower Man DVD",
    "quantity": 3,
    "amount": 9.90,
    "shippingAddressId": "addr-id-002"
  }],	
  "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",
      "lastName": "Doe"
    },
    "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",
        "id": "addr-id-001"
      },
      "additionalAddresses": [
        {
          "street": "Merchantstr.",
          "houseNumber": "1000",
          "zip": "80333",
          "city": "Munich",
          "state": "Bayern",
          "country": "DE",
          "companyName": "Merchant Ltd",
          "id": "addr-id-002"
        }
      ]
    },
    "phones": {
      "company": {"unstructuredNumber": "(0)89 1060 120-00"},
      "home": {"unstructuredNumber": "089 5060 120-55"},
      "mobile": {"unstructuredNumber": "0177 44004400"}
    }
  },
  "callback": {
    "returnUrl": "https://dev.oscato.com/shop/success.html",
    "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
    "notificationUrl":"https://dev.oscato.com/web/acb123"
  }
}

Web Content Display

More LIST Use Cases

Web Content Display

Delayed Payment Submission

The diagram shows how the user journey (on the left) relates to OPG API calls (on the right). Note how the CLOSING request from the Deferred CHARGE is separate from the Delayed Payment Submission.

 

Payment Account Validation

As soon as the customer submits their payment account data to the gateway (PRESET call), it can be validated for accuracy of format and also for existence of the account, availability of funds, and other risk checks. This means that if something goes wrong, the shop can give immediate feedback to the customer and offer alternative payment options to minimize user dropout.

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

  • NONE: No check will be made
  • VALIDATION (default): An Orchestration Platform-internal check on formal validity of the account number will be made
  • PROVIDER_CHECK: The internal verification (see above) will be made first. If this is positive, a check with the provider will be made, if available, that does not reserve the funds. 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, none will be made and the transaction will be processed as usual.
  • PREAUTHORIZATION: The internal verification (see above) will be made first. If this is positive, and the method and provider permits it, the corresponding funds will be reserved (preauthorized). If a reservation is not available, there will be a fallback to the non-reserving provider check as explained above. Again, if this is not available either, the transaction will be processed as usual.

LIST Request

As shown in the delayed payment submission diagram, the first step is to submit a LIST Request. For Delayed Payment Submission, an extra LIST parameter is needed: the optional Boolean value presetFirst. If this is set to true OPG will know that the payment submission should be preset, not charged direct. A summaryUrl must also be provided in the callback object if presetFirst is set to true. This way 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, follow the standard approach for rendering the payment methods, 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 direct to the OPG from the customer's client. It should contain the account data structure similar to the CHARGE request.

The AJAX library will handle this correctly on button click.

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

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

The response to a successful PRESET call will show that the customer should be redirected 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 also want to 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 to 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 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 on the summary page 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, 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 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",
.....

Web Content Display

Payment Account Registration

There are 2 kinds of registration: Regular and Recurring.

Regular Account Registration

If customers return to your shop, they will see their previously registered payment accounts and do not need to enter their information again. This can increase conversion, especially with credit and debit cards or SEPA direct-debit bank accounts. For credit cards, the verification code (CVV, CVC, etc.) must still be entered by the customer because PCI DSS regulations prohibit the storage of this data. (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).

The Dynamic Verification Code feature allows for hiding the CVC field for registered cards on our payment page. In this way,  you can submit a CIT payment without entering the CVC. Note that a payment provider needs to support this functionality before it can work on our end. Additionally, you need to use our payment page (so native integrations can't use the feature). 

In the 3DS 2 flow, the first payment will always require the CVC code. 

Recurring Registration

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

Payment page with a registered account (regular)

 

Customer Agreement on Payment Page

You can configure both types of registration. Since they need the customer's agreement, you should provide checkboxes in the payment page. If registration was enabled on the Orchestration Platform's side, you simply 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 2 attributes for each network: registration and recurrence, which correspond to the 2 registration types.

Depending on the configuration, these attributes can have the following values:

  • 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 can 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 can include an additional hidden value, as shown below, if you have a Display Native integration and need to pass the parameter from the client direct to OPG:

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

Checkboxes should look similar to those shown on the right. Note: a separate checkbox is needed for each payment network, 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.sandbox.oscato.com/resource/network/DEMO/de_DE/VISA/logo.gif",
    "operation":"https://api.sandbox.oscato.com/api/lists/2885c861-fae4-4fc1-add4-a856c1012e21/VISA/charge",
    "form":"https://api.sandbox.oscato.com/resource/form/VISA/standard.html",
    "validation":"https://api.sandbox.oscato.com/api/pci/2885c861-fae4-4fc1-add4-a856c1012e21/DEMO/de_DE/VISA/validate",
    "localizedForm":"https://api.sandbox.oscato.com/resource/form/DEMO/de_DE/VISA/standard.html",
    "lang":"https://api.sandbox.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 indicating which checkboxes have been checked must 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 the 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 yet been registered, they will be registered at this stage together with the payment account, and 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). But in most cases you 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 by 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 (eg 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 (ie without further customer interaction) using the customerRegistrationId and -password. Find out more about 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 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",
         ... }]
  }
}	

Web Content Display

Account Update and Registration Page

The request works in a similar way to the LIST Request but with these important differences:
  • A property operationType, which exists at root level must be set to UPDATE
  • When updating a customer's payment methods, the customer's registration details must be included to identify the customer in question

In the pane on the right, there is a sample LIST Request for this operation.

  • 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",
  "operationType": "UPDATE",
  "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 accounts that are allowed to be updated will be returned. If the account cannot be updated, it will not be shown. Where the payment account is updatable, the operationUrl returned in the LIST Response will point to an "update" instead of "charge" endpoint (for backwards compatibility with the existing integrations), eg "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, eg https://api.sandbox.oscato.com/pci/v1/5832ec78e4b0b0d86234c04bl/SEPADD/register

The attribute operationType at the top level of the response object enables the client to see 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

To demonstrate the Update LIST process, we have split the examples into different documents based on integration type:

  • 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 is similar
  • Hosted Integration will handle the Update LIST on your behalf and while it is the easiest to integrate with, it offers the least control.
Set Preferred Payment Account

In an Update LIST, a customer can also set one of their registered accounts as preferred for future use. See Set preferred payment account.

Account Update and Registration Page - Native Integration

Native integration requires some extra steps to update a LIST. Below, we show you 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 in the pane on the right.

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

Example LIST Request
 {
  "transactionId": "tr1068735466d37",
  "country": "DE",
  "operationType": "UPDATE",
  "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 enter 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 will be shown that is similar to the one below.


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

If another LIST Request is repeated with the same body as in Step 1, the newly registered card will be visible in the accounts and can be presented to the customer at the frontend. Hosted and AJAX integrations 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
},
....

 

Web Content Display

Customer Score Dynamics

3D secure
In its standard setting, a customerScore value below 300 enforces a 3D secure check, a value above 700 disables it, and values in between let the provider decide in accordance with agreed defaults.

CVV/CVC (Dynamic Verification)
For registered credit card accounts, a customerScore value above 500 will skip CVV/CVC check if the PSP supports it. Case supported, the LIST response will return an empty form snippet for the account, which means that you can charge the customer without requesting CVV/CVC input. This also means that if a registered form snippet is present in the LIST response, you must implement it to collect CVV/CVC input from your customer before charge. Please notice that the OPG will decide for you if a verification code is needed for the currently available network. This dynamic verification logic is rather complex and depends on factors such as routing, network support, and CVC used in previous registration.
In practice, if you follow the implement once principle and always integrate the form snippet as delivered by the OPG, the verification code collection will be completely automated without need for extra logic on your side. The form snippets will always define what customer data is needed when sending a CHARGE request.

If you need to change the ranges in which any of the checks above are triggered, please contact our technical support team so that they can de configured in our servers.
LIST response with empty form for Dynamic Verification

"accounts": [{
  "links": {
    "form": "https://resources.sandbox.oscato.com/resource/form/EMPTY/empty.html",
    "logo": "https://resources.sandbox.oscato.com/resource/network/DEMO_HOMERO/en_GB/MASTERCARD/logo2x.png",
    "self": "https://api.sandbox.oscato.com/api/lists/5c1cfc3b148b5135a85db1fclttvtsjiauh4sl3ubggidr1sd1/accounts/5c0fc7021968ee2a8574d8dda",
    "lang": "https://resources.sandbox.oscato.com/resource/lang/DEMO_HOMERO/en_GB/MASTERCARD.properties",
    "operation": "https://api.sandbox.oscato.com/api/lists/5c1cfc3b148b5135a85db1fclttvtsjiauh4sl3ubggidr1sd1/accounts/5c0fc7021968ee2a8574d8dda/charge",
    "localizedForm": "https://resources.sandbox.oscato.com/resource/form/EMPTY/empty.html"
    },
    "code": "MASTERCARD",
    "label": "Mastercard",
    "maskedAccount": {
      "displayLabel": "55 *** 4444    07 | 2019",
      "holderName": "Tom James",
      "number": "55 *** 4444",
      "expiryMonth": 7,
      "expiryYear": 2019
    },
    "lastSuccessfulChargeAt": "2018-12-21T12:42:36.946+0000",
    "selected": false,
    "createdAt": "2018-12-11T14:17:39.022+0000",
    "emptyForm": true
}]

Web Content Display

Set Preferred Payment Account

Integration

To let your customers set their preferred account, your system must 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 normal account registrations will be returned.

In any case the LIST Response will show the respective registered accounts, as in the 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.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 account was registered for standard registration and for 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 of 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 the order that they were set as 'preferred'.
  • If none of the registered accounts were ever set as a preferred account, then the list is organized by time of registration: the most recently registered account will be top of the list.
  • If the customer adds a new payment account, the previous preferred payment account will remain. In other words, the new account does not automatically become the preferred account unless no preferred account had been set (see above).

Web Content Display

Delete Payment Account

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

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, similar 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 switch off the possibility of account deletion 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 at their side, as shown below. Naturally, you can modify its style via your custom CSS stylesheet.

 

When a customer clicks the Delete button, the following dialog appears:

 

The button-label and user-messages are localized, so if you are using the payment page for a language supported by the Orchestration Platform, 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" : {
    "hostedVersion":"v3"
  },
  "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"
  }
}

Web Content Display

Secure Storage

The Orchestration Platform's Secure Storage is an internal component that holds 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 stored and used by the Orchestration Platform), but the provider experiences downtime, the Orchestration Platform 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 explains 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 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.

Web Content Display

Payout Page

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 you provide the parameter preselection.direction with the value PAYOUT in the LIST Request. See example.

This shows that a LIST for PAYOUT (as opposed to CHARGE) is requested. The effect is that all forms and endpoints for further actions that are returned 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 you chose a native integration.

LIST Request with Payout Parameter

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

After a LIST is initialized for payout using the parameter preselection.direction = PAYOUT, any payment method returned in the list response can be deployed for credit operations. The payout URL can be found in the operation parameter and it will have this 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 a similar way 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 made 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.

Web Content Display

AJAX Library Integration

Including the JavaScript Library

The Orchestration PlatformJavaScript Library (as known as AJAX Library) is used with Selective Native and Display Native integration scenarios to render payment components returned by API responses into your checkout page. With the library you can integrate a payment page in these scenatios with much less effort, since it implements all frontend payment features and only a single call is necessary to initialize it.

The most recent AJAX Integration package can be downloaded here (login required): v3-3.21.0 (~2.5MB).

The zip file contains the following folders and files:

  • build: The completely built and ready-to-use JavaScript and CSS files. The files should be put on the same folder level as your checkout HTML pages.
  • example: An example HTML file in two versions, one linking the minified resources (JS & CSS) the other the development versions.
  • node_modules: 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 main folder contains these files:

File Description
op-payment-widget-v3*.js The readily built and readable JavaScript library. It comes in standard, versioned and minified versions. We recommend merchants to use versioned files.
op-payment-widget-v3*.css The responsive CSS for the widget. It comes in standard, versioned and minified versions. We recommend merchants to use versioned files.
widget*.css CSS file needed to style the iFrames for Selective Native integrations. It comes in standard, versioned or minified versions.
widget-card-view*.css CSS file needed to style the iFrames for Selective Native integrations using our card view. It comes in standard, versioned or minified versions.
responsive.html The HTML source of the Orchestration Platform's hosted payment page, can be used as example to get started with development.
We recommend to keep all JS and CSS files above in the same directory level of your checkout page.

The example folder contains various implementation examples to help you getting started with our library.

You can integrate the respective JavaScript and CSS files into the header of an HTML page like demonstrated on the right pane. Make sure the HTML header contains the tag <meta charset="UTF-8"> for correct loading of the payment page.

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>

Payment page: 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 the OPG. This object 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 long ID) or its actual longId attribute.

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

LIST Response

{
  "links": {
    "self": "https://api.sandbox.oscato.com/pci/v1/5fb254c5c4ffdf5cbab77723luv2g4f46tkplecjj7a2brv123"
  },
    ...
  "identification": {
    "longId": "5fb254c5c4ffdf5cbab77723luv2g4f46tkplecjj7a2brv123",
    ...
  }
}

This URL to "self" or the contained LIST object ID (in this example: 5fb254c5c4ffdf5cbab77723luv2g4f46tkplecjj7a2brv123) has to go back to the customer's browser and from there to the AJAX Library. There are three 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.example.com/checkout/payment.html?listUrl=https%3A%2F%2Fapi.sandbox.oscato.com%2Fpci%2Fv1%2F5fb254c5c4ffdf5cbab77723luv2g4f46tkplecjj7a2brv123
    http://www.example.com/checkout/payment.html?listId=5fb254c5c4ffdf5cbab77723luv2g4f46tkplecjj7a2brv123
  2. Generate the HTML page on server side that contains the listUrl or listId parameter in the initialization call of the library.
  3. Generate the HTML page on the frontend side passing the listUrl or listId parameter to the initialization call of the library.

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",
  payButtonContainer: "submitBtnContainer",
  listUrl: listResponse.links.self,
  smartSwitch: true,
  developmentMode: false });

When calling checkoutList you can provide additional options to configure and tune the payment checkout, listed below:

baseUrl String optional

The URL of the OPG service that will handle all the AJAX calls. It depends on the OPG version and enviroment you are using.

Sandbox:  https://api.sandbox.oscato.com/pci/v1/.

Live: 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.

widgetCssUrl String optional

If your application stores CSS files in a different directory level than your checkout page, use this parameter to reference the location of widget*.css or widget-card-view*.css.

payButton String mandatory The ID of the HTML element of the submit button defined by merchant.
payButtonContainer String optional The ID of the HTML element that contains the submit button. Used with methods that require proprietary provider buttons, which will then replace the standard payment button dynamically.
cardView Boolean optional

Default: false. When set to true puts each payment method inside cards. In practice this means that the payment page will render as if in mobile mode, even on desktop clients.

fullPageLoading Boolean optional

Default: true. When set to true, the loading spinner rendered by the widget covers the entire containing page, typically the page where the widget is loading. This means the entire contents are dimmed and inactive. When set to false, the widget renders a spinner only in the container assigned to it. This mode can be used to avoid conflicts with a loading spinner rendered by the shop itself.

smartSwitch Boolean optional

Default: true. Enables the "Smart Network Switch" feature for cards. "Smart Network Switch" automatically detects the credit card scheme by its card number while typing. It is meaningless for payment methods other than cards.

summaryPage Boolean optional

Default: false. Used to load alternative payment methods in the summary page. Some methods such as PayPal Smart Buttons or Apple Pay will trigger a payment once their submit button is pressed, so if you want to use a summary page they must be initialized only there.

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.

iFrameScaleFunction Function optional

For selective native integrations using custom styling via external CSS file, it might be needed to also adapt the container iFrames height to properly fit customized input fields for payment methods, saved accounts or preset accounts.

If declared by the merchant, the function should return a float value which will be used to scale the standard iFrame height size as returned in the parameter links.iFrameHeight of the LIST response. Conditions to this function:

  • The returned value should be greater than 0
  • The returned value should be a float number

If the iFrameScaleFunction is not declared by the merchant or the returned value does not respect the conditions above, the iFrame size will be taken from the LIST response without changes.

doOperation Function optional If the AJAX library is initialized in Summary Page mode (see summaryPage attribute) this callback function can be implemented to execute any operation once the user press the submit button. This function must be declared within a summaryPageHandler container object.
onResult Function optional If the AJAX library is initialized in Summary Page mode (see summaryPage attribute) this callback function can be implemented to handle responses This function must be declared within a summaryPageHandler container object. from operations executed after the user presses the submit button.
summaryPageHandler Object optional If the AJAX library is initialized in Summary Page mode (see summaryPage attribute) this object will contain doOperation and/or onResult callbacks implemented by you.
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.

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">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
  <script type="text/javascript" src="op-payment-widget-v3.min.js"></script>
  <link rel="stylesheet" type="text/css" href="op-payment-widget-v3.min.css">
  <style>
  @media only screen and (max-device-width: 736px){
  body {
  background-color: #F2F2F2;
    }
   }
  </style>
  <script type="text/javascript">
    function initPaymentPage() {
      var dict = {};
                checkoutList('paymentNetworks', {
                    payButton: 'submitBtn',
                    payButtonContainer: 'submitBtnContainer',
                    baseUrl: '"https://api.sandbox.oscato.com/pci/v1/"',
                });
            }
            document.addEventListener('DOMContentLoaded', function (event) {
                initPaymentPage();
  });
  </script>
</head>
<body>
  <div id="paymentNetworks" class="payment-networks-container">
  </div>
  <div id="submitBtnContainer" class="submit-buttons-container">
  <button id="submitBtn" type="button"></button>
  </div>
</body>
</html> 
Native Form Rendering

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

Web Content Display

Provider Buttons

During a regular payment flow, the Orchestration Platform widget builds a list of payment methods and listens to a button-submit to process the next step (for example, capture a payment). This button is designed and implemented by the merchant, so to make this possible, it must have the ID submitBtn, which is linked to the AJAX initialization function checkoutList when building the payment page. However, providers such as PayPal impose the use of their own payment button, which has specific styling elements that cannot be changed by merchants. If you include such a provider in the list of available networks, you have the additional challenge of switching between a merchant's and a provider's payment buttons.

To solve this challenge, the Orchestration Platform AJAX library replaces this button on demand: if a user selects a provider like PayPal, its proprietary button is loaded. If any other method is clicked, the merchant button is loaded. This is done by defining a <div> with ID submitButtonContainer which will be used as container to submitBtn and the provider's button. The checkoutList function must be initialized with the parameter payButtonContainer pointing to this container defined by the merchant, as seen in the second example in the pane on the right.

After these initialization steps, the payment page will look like the example below:

Left: Submit button for other payment networks. Right: PayPal proprietary button.

From an integration point of view, this is the only change needed to start using PayPal checkout. On the Provider Contract configuration side, a new parameter JAVASCRIPT_INTEGRATION should be set to true, but you can request this change direct from our support team if you wish.

Submit Button Container:

<div id="submitBtnContainer">
  <button hidden="hidden" id="submitBtn" type="button"></button>
</div>

JavaScript Initialization:

$("#paymentNetworks").checkoutList({
  payButton: "submitBtn",
  payButtonContainer: "submitBtnContainer",
  ...
});

Delayed Payment Submission (Summary Page)

The Orchestration Platform's Delayed Payment Submission offers a unique solution: payment data is collected and cached ('PRESET') so the merchant has the chance to build a summary of the order before triggering the next step. With payment services that provide their own libraries, the summary page presents another two-fold challenge: First, the placement of the payment button has to happen there; and second, the proper process communication between the Orchestration Platform and these third party libraries must be handled.

To overcome these obstacles, the Orchestration Platform AJAX widget (the same one used for the Payment Page) must also be included in the merchant Summary Page and properly initialized with a different set of parameters. Its current implementation supports PayPal checkout, Apple Pay and Google Pay, and future updates will cover new methods. As you saw in the payment page, the library makes use of the initialization function checkoutList, but now with different parameters and extra handler functions:

  • summaryPage:true tells the library that the current context is a summary page
  • summaryPageHandler: optional functions that can be implemented by the merchant for better control of the payment process
    • doOperation: after an end-user clicks the provider-specific payment button, it will be triggered to handle the CHARGE process request to the OPG.
    • onResult: handles result object after success or error sent back from the OPG.

See the pane on the right for examples of these functions.

Example of Summary Page initialization

function loadSummaryPage(inputData) {
  $("#paymentNetworks").checkoutList({
    payButton: "submitBtn",
    payButtonContainer: "submitBtnContainer",
    listUrl: inputData.links.self,
    summaryPage: true,
    summaryPageHandler: {
      doOperation: function(data, callBack) {
        $.ajax({
          type: data.method,
          dataType: "json",
          data: JSON.stringify(data.operationData ? data.operationData : {}),
          contentType: "application/json",
          url: data.url
        }).done(callBack)
      },
      onResult: summaryPageHandlerOnResult
    }
  });
}

Summary Page Handler Functions

The idea behind the summary-page handler functions is to give merchants the opportunity to intervene in the payment process, by implementing their own way of handling the trigger and result processing of a transaction. In this way, you can introduce custom logic that starts other parallel processes in your systems; and you get better control of the payment flow without needing to rely only on the functionality provided by the Orchestration Platform. For example, with doOperation a merchant can send a signal to its backend saying that an item is being taken from stock. With onResult, you can define custom behavior of your user-interface based on the possible Interaction Codes sent by the OPG.

PayPal exception handling

There are some exceptional scenarios in which the merchant needs to cancel the payment operation mid-transaction. For example, it's possible that after triggering a CHARGE via doOperation a merchant sees that the item being ordered is no longer available. Ideally, the payment operation would be stopped before the end-user executes the payment on PayPal, meaning the PayPal popup should be closed by a trigger from the merchant systems. Since the introduction of PayPal checkout.js, such control is expected to happen in the frontend. To make this happen, the library has an exception handler that closes the popup. In practice, a merchant can trigger a popup-close by throwing a Javascript exception: throw new error.

For example, a merchant backend system can return an error to the frontend, which would then throw an error during doOperation execution to close the popup.

Example implementation of onResult handler

function handlerOnResult(data) {
  console.log("Result Data: ", data);
  switch (data.interaction.code) {
    case "PROCEED":
      $("#paymentNetworks").empty();
      $("#submitBtnContainer").hide();
      showGlobalSuccessMessage("Payment is done!")
      break;

    case "ABORT":
      $("#paymentNetworks").empty();
      $("#submitBtnContainer").hide();
      if (data.error instanceof Error) {
          showGlobalErrorMessage("Payment is aborted by Client!")
      } else {
          showGlobalErrorMessage("Payment is aborted!");
      }
      break;

    case "TRY_OTHER_ACCOUNT":
    case "RETRY":
      showGlobalErrorMessage("interaction." + data.interaction.code + "." + data.interaction.reason);
      break;
    case "TRY_OTHER_NETWORK":
    case "RELOAD":
      $("#paymentNetworks").empty();
      $("#submitBtnContainer").html('');
      //loadSummaryPage(data);
      window.setTimeout(function() {
        showGlobalErrorMessage("interaction." + data.interaction.code + "." + data.interaction.reason);
      }, 2000);
      break;
  }
}

Web Content Display

Display & Pure Native Integration

Web Content Display

LIST Response

The networks available are contained as an array in the response parameter networks.applicable. If you have registered payment accounts (eg 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 -- see below. The idea is that this advanced data will be handled only by the merchant's server systems, whereas the Display Native data (above) could safely be passed to a browser for rendering the page in the frontend.

Display the payment networks

We will provide all the resources needed for display and charge of every payment network. With these resources you can easily generate a payment page of your own, the one the customer sees, within the frame of your corporate design.

The important links are:

  • localizedForm: Links to an HTML form snippet detailing what information is needed from the customer to charge this network (eg credit card number). The language of the labels is dictated by the LIST Request's country or style.language parameters. The input fields depend heavily on the network. Their name attributes already correspond to the parameter names needed for the consecutive CHARGE. Only the ${formId} placeholder in "id" attributes needs to be replaced before displaying the form -- to avoid conflict with existing elements on the page.
  • operation: The information entered on the form should be submitted to this OPG URL. It differs from network to network. Note: 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 on whether the information is considered valid.

You create the payment checkout page (most likely but not necessarily in HTML) dynamically and per transaction, with this data. 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 (ie the browser), which displays it to your customer.

Visualization (red are parameters or resources to fetch; green are 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"
}

Web Content Display

Native Form Rendering

In Native intregrations, and in non-PCI applicable payment networks in Selective Native integrations, 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

To retrieve the relevant localised form snippets, your system will make a LIST request specifying the integration type and country. See the example on the right.

Example LIST Request
{
  "transactionId": "tr10687",
  "country": "GB",
  "integration": "DISPLAY_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"
  }
}
Presenting the forms on screen

Developers who have chosen a Native or Selective Native integration will have total control over where they present the form snippets. What follows serves only as a demonstration of how to do this; you are free to implement this at the frontend as you wish.
After retrieving the LIST Response, the associated payment networks should be presented at the frontend programmatically so that methods can be added or removed on the merchant configuration portal without the need for changes in the payment frontend of the integrated site.

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 containing the localised form snippet will be displayed. Some information from the LIST Response data values in these HTML controls are also populated; this is so they can be accessed later in the process. In this example, a Pay button is used for triggering the selected payment request; 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 noted earlier, localised form snippets contain placeholders to identify the associated form. Before these snippets can be properly used, these snippets must be replaced with the relevant value.
To do this, inject the name of the payment method into the localised form at the frontend. Although there are different approaches for doing this, in this example you simply place all localised forms inside a div named ‘optileHtmlSnippet' then on the document load calling function, replace all form name placeholders with the form name. You can find the function opTemplateEngine we used in this example in the JavaScript file ‘template-engine.min.js

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. 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 that let the user specify the payment method to be saved for future use, you must render this at 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. This is because some payment methods do not support registration.

The value in the LIST Response that illustrates 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

Some logic must be in place in the frontend, 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 uses instead 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. Again, please note this example is for illustration only; you are free to implement this any way you choose.

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;
}

Web Content Display

Provider Buttons

Payment page rendering

Whichever integration scenario you have chosen, your system starts with the LIST request. If you are using the Delayed Payment Submission flow with a Summary Page before purchase, you can find out more under Delayed Payment Submission (this is easier to integrate because you don't need a proprietary button on the Payment Page). In other cases, your system renders the Payment Page by using the building components taken from the LIST response and should place the (regular) payment button in a dedicated container (eg <div>). When the user selects one of these proprietary "frontend" methods, your system should call a generic JavaScript code from the Orchestration Platform (see below) which will place the proprietary provider button into this container. (If you are using the full AJAX library, this container corresponds to the one given as the payButtonContainer parameter in the checkoutList initialization call). At the same time, your system should hide the normal payment button. The user will probably notice that the button has been replaced, but this is unavoidable because these kinds of providers don't let you use your own generic pay button.

JavaScript initialization on method selection

Your system now needs to know if it should call a JavaScript function when the user selects a method. For this, it looks into the HTML form snippet that was returned by the LIST response for this method or registered account. In any event, the form snippets should be integrated into your payment page, in accordance with our dynamic payment page rendering standards. Keep in mind that the form may not be visible to the customer (eg for PayPal) but it should still be loaded. If this snippet contains a <fieldset> tag with the attribute initcustomsubmitbtn then this gives you the JS function name (as a string) to call.

You can easily find the tag with this attribute (if it exists) with a CSS selector like fieldset[initcustomsubmitbtn]. When used in a JavaScript implementation that supports these selectors, this returns all fieldset elements that contain the attribute named initcustomsubmitbtn.

If there is no matching tag then there is no proprietary button for this method, and the regular payment button should be shown again.

HTML snippet with JS function name

<fieldset initcustomsubmitbtn="functionName">
  ...
</fieldset>

If the function is given, it should be called as soon as the user selects the corresponding method. In other words, your system calls eval with the value of initcustomsubmitbtn and 5 parameters.

The 5 parameters are:

Example call of given JS function

eval("functionName")(networkObject, buttonContainer, paymentCallback, operationUrl, listResponse)
  • networkObject: The JS object from the LIST response for the selected network. See the example.
Network object
{
    "code": "PAYPAL",
    "label": "PayPal",
    "method": "WALLET",
    "grouping": "WALLET",
    "registration": "OPTIONAL_PRESELECTED",
    "recurrence": "NONE",
    "redirect": true,
    "links": {...},
    "button": "button.charge.label",
    "selected": false,
    "contractData": {...}
}
  • buttonContainer: a pointer to an HTML button container, as shown in the example on the right. Could also be a special "inner" container that only holds the proprietary buttons. See Button display below.
  • paymentCallback: is called to handle the payment response. It should take only one argument which will contain the (CHARGE or PRESET) response from the OPG.
  • operationUrl: is an optional string, if passed, it will be used instead of the url available in networkObject.
  • listResponse: is an optional parameter containing extra information such as currency and amount.
Button container example

<div id="submitBtnContainer">
  <button id="submitBtn" style="display: none;" type="button">My button</button>
  <span id="paymentLoadingIcon" class="payment-in-progress" style="display: none;"> </span>
</div>

Calling the initialization function will create the proprietary button and bind any subsequent click event on it. Naturally, it does not execute the payment at this point. This function acts as middleware between the payment page and the provider's proprietary JavaScript.

A click on the provider button will trigger the payment process as per the behavior defined in its own JavaScript code. The result will be given asynchronously to your given callback function (in the format of an OPG CHARGE or PRESET response) so that you can (typically) redirect the user accordingly.

On mobile devices, PayPal (for example) typically redirects immediately on mobile devices. On a desktop, the result is delivered once the user has completed the checkout in the provider popup. For your implementation, however, it makes no difference. It should just follow the redirect or react on issues (based on the Interaction Codes).

Button display

As mentioned above, your system should hide the normal payment button when the user selects a method that has its own proprietary button. We suggest you use CSS to make sure that all buttons appear at the same place so there is consistency for the user. However, they will be different, because they are provider-specific. Providers usually do not allow the buttons to be changed visually.

In a nutshell, every time the user selects a new method, your system must evaluate again which buttons to show or hide. As a general rule, the decision goes like this:

Every time the selected payment method changes, hide all buttons inside the container. Note that they cannot consist of a <button> tag but could simply be a <div> for example. Then either call the JS function to show the proprietary button, or show the generic pay button. You could also group all proprietary buttons into another (inner) container within the (outer) container (in which the regular payment button is located). This gives you clear separation between regular and proprietary buttons. In this case you would pass the inner container to the function given in initcustomsubmitbtn.

Delayed Payment Submission

You should include the Orchestration Platform's AJAX library in the Summary Page, as described under https://www.optile.io/opg#1842448 (again, look under Delayed Payment Submission). This will render any proprietary payment button, if required, or just handle the button click for you. In any case it leaves you with full rendering possibilities, so you should use it on the Summary Page even if you don't use it for Payment Page rendering. It does not make a difference at this point which integration scenario was used to render the Payment Page earlier as long as the LIST object contains a preset payment account.

Web Content Display

CHARGE Request

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). Under PCI regulations, the sensitive data takes different paths depending on the Native Integration scenario that's in place:

Display Native: The data is transferred from the payment checkout page in the customer's client (eg browser) direct to the OPG. Your server-side systems never touch 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 means your system may store the data itself. In the case of credit cards, your system must comply with some PCI DSS standards and you must be 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. But 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 (eg 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. On the other hand, the CHARGE reply should be evaluated in terms of feedback to the customer and how to direct them further. A CHARGE response can contain redirect information for methods that require the customer to finish a payment on their own platforms.

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 Methods

Some payment methods will require the customer to be redirected to their own web platform to authorize a purchase. Many alternative PSPs and especially 3D Secure methods rely on redirection, therefore it is important to understand how the CHARGE response represents them.

In such cases, a CHARGE can be considered a two-step process. It will initially stay in pending state and will only move to a successful (or failed) state after the end customer finishes interacting with it. From an integration perspective it means you should evaluate first the Interaction Code and Reason of the response and parse the redirect URL accordingly.

A positive CHARGE response of redirect methods will initially be in pending state, which is represented by status.code = pending and interaction.reason = PENDING. Its redirect object will contain parameters to inform how your systems should handle the redirection as follows:

  • url: the base URL to which the request should be sent to.
  • method: the request method used. It can be either a POST or a GET.
  • parameters: an array of parameters to be sent with the request. In case of a POST redirect, the parameters should be sent as in a form submission with header Content-type = application/x-www-form-urlencoded, in a GET redirect the parameters should be attached to the main URL as query string elements. If account placeholders are used (see next item on this list) the following key-value pairs can be present and should be replaced by the respective input form data collected from the end user.
    • holderName: ${account.holderName}
    • cardNumber: ${account.number}
    • expiryMonth: ${account.expiryMonth}
    • expiryYear: ${account.expiryYear}
    • verificationCode: ${account.verificationCode} 
  • containsAccountPlaceholders: a boolean that indicates if any of the parameters above contain placeholders for payment account data. Some PSPs will expose payment data in full details as redirect parameters, so to enable merchants that have PCI certification SAQ-A to still process such redirects, the account-related parameters will contain placeholders that our Ajax library replaces with input data from the frontend iFrames. For merchants that have are on higher levels of PCI certification SAQ A-EP or SAQ-D, these placeholders need to be filled with data collected in the frontend through regular forms.

After the user completes the purchase through the redirect window, a regular CHARGE response containing either a success or error case will follow. Note that these responses also contain redirect URLs to the success or error pages defined by your shop, and should be parsed by the exact same method described above.

 

Part of CHARGE response for redirect methods

"status": {
  "code": "pending",
  "reason": "debit_requested"
},
"interaction": {
  "code": "PROCEED",
  "reason": "PENDING"
},
...
"redirect": {
  "url": "https://preprod-tpeweb.paybox.com/cgi/RemoteMPI.cgi",
  "method": "POST",
  "parameters": [
    {
    "name": "IdMerchant",
    "value": "510525147"
    },
    {
    "name": "IdSession",
    "value": "5d654a3eb55f28722d5fb03ac"
    }
    ...
  ]
}

Code snippet used to parse a redirect

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);
      }
    }

Masked Account data

After a successful charge request, the response body will also contain a masked account used for the charge. This can be used for giving the end customer a better summary of the payment process. The data can be found inside the maskedAccount parameter in the response body. See the example in the pane on the right. 

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

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 on where the user should be redirected. Only in Pure Native scenarios, where you did not provide the callbacks in the LIST Request, must you generate the redirect in your backend yourself.

There are two reasons for redirection after a successful request:

  1. Payment was completed successfully. In this case the redirect will lead to the merchant's success page.
  2. Payment was initiated but more information is needed from customer, eg 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 website 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 next page to display additional information about the payment status. For example, it may provide data for the remittance account in the case of invoice or prepaid payment networks (see Status Notifications for a list of possible keys relating to remittance accounts).

For Hosted Integrations in an iFrame especially, 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. It should therefore be the default, as it is in the Orchestration Platform'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 of the failed payment. Depending on the Interaction Code the customer should be asked to select another payment method or provide correct account information.

  • TRY_OTHER_NETWORK Re-read the LIST object and render the payment page again accordingly, because the used network is probably not available anymore.
  • TRY_OTHER_ACCOUNT  A different payment account should be requested from the customer (it can be the same method, eg 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 the respective values provided by our live environment in a resource JSON file:

https://resources.sandbox.oscato.net/resource/lang/MERCHANT_CODE/language/checkout.json

In this URL, two parameters need to be adapted:

  • MERCHANT_CODE: your Merchant Code
  • language: a language code composed of ISO 639 two-letter language codes and ISO 3166 two-letter country codes separated by an underscore character. Similar to RFC 1766.

The resource file lists the interaction codes and reasons, with their related descriptions as specified 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.sandbox.oscato.net/resource/lang/DEMO_SK/en/checkout.json is shown in the right pane.

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

Extract of Interaction Codes from JSON resource file

{
    ...
    "button.delete.label": "Delete",
    "button.operation.CHARGE.label": "Pay",

    ...
    "interaction.RETRY.ACCOUNT_NOT_ACTIVATED.title": "Payment failed",
    "interaction.TRY_OTHER_ACCOUNT.EXCEEDS_LIMIT.text": "The limit on this account has been exceeded. Please use another payment method.",
    "interaction.RETRY.ACCOUNT_NOT_ACTIVATED.text": "Your payment method isn't yet activated. Please activate and try again or use another method.",
    "interaction.TRY_OTHER_ACCOUNT.INVALID_ACCOUNT.text": "Please verify the data you entered is correct and try again, or use another payment method.",
    "interaction.TRY_OTHER_NETWORK.BLOCKED.title": "Payment failed",

    ...

}

Reload to Proceed

For some methods with a multi-step flow, eg Installment, the Interaction Code RELOAD will be returned. As with 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 coupled with a redirect to merchant's Cancel Page, if the cancelUrl parameter was given in the LIST Request.

As with 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), ie 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 that 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
  }
}

Web Content Display

Validation API

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 links object within the LIST Response. The endpoint is unique for each of the payment networks returned.

Example LIST Response

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

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

The JSON parameters to be sent are equal to the input field names of the HTML payment form snippets linked in the LIST Response. For example, the validation request for a Visa credit card should have parameters that match the form snippet on the right pane (notice that the name attribute is equivalent to the parameter name to be sent in the JSON request body:

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

  • holderName
  • number
  • expiryMonth
  • expiryYear
  • verificationCode
  • bic
  • iban
Payment Form Snippet for Visa

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

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 or invalid input value:

HTTP 200 OK
Examples of invalid input
Missing input
{
  "valid": false,
  "messages": {
    "expiryYear": {
      "message": "Please enter year of expiration"
      "type": "ERROR"
    },
    ...
  }
}

Invalid field value
{
  "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 [...]"
}

Web Content Display

Activate Request

If a method uses the Activation flow and you do not rely on the Orchestration Platform'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/SHOP/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/SHOP/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/SHOP/DE/de_DE/INSTALLMENT_SEPA/standard.html",
        "validation": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/SHOP/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/SHOP/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/SHOP/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/SHOP/DE/de_DE/INSTALLMENT_SEPA/activated.html",
        "validation": "https://api.sandbox.oscato.com/pci/v1/582994c0e4b0b0d86230c524l/SHOP/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/SHOP/PAYOLUTION/582994d8c3a614600a9bb6d0PcuR2eVe5q/CreditInformation.pdf",
           "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/SHOP/PAYOLUTION/582994d8c3a614600a9bb6d15t21a5zw8r/TermsAndConditions.pdf",
           "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/SHOP/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/SHOP/PAYOLUTION/582994d8c3a614600a9bb6d3iBeZYNpTI5/CreditInformation.pdf",
         "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/SHOP/PAYOLUTION/582994d8c3a614600a9bb6d4k3JJ3ilyEp/TermsAndConditions.pdf",
         "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/SHOP/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/SHOP/PAYOLUTION/582994d8c3a614600a9bb6d6bWXLcTWp5Q/CreditInformation.pdf",
         "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/SHOP/PAYOLUTION/582994d8c3a614600a9bb6d7zXd7FoIceb/TermsAndConditions.pdf",
         "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/SHOP/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/SHOP/PAYOLUTION/582994d8c3a614600a9bb6d9ETOlzIfSMw/CreditInformation.pdf",
         "termsAndConditionsUrl": "https://documents.sandbox.oscato.com/SHOP/PAYOLUTION/582994d8c3a614600a9bb6daYpicMFJ0eA/TermsAndConditions.pdf",
         "dataPrivacyConsentUrl": "https://documents.sandbox.oscato.com/SHOP/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 ......

Web Content Display

Selective Native Integration

LIST Response

If you implement this yourself, you should first be aware of the behavior of the LIST Response when it generates the payment page (client- or server-side).

For each method in accounts or networks.available that falls under the scope of PCI DSS (ie credit and debit cards), the LIST Response will not provide the links form and localizedForm. This means that your system will not be able to include the HTML snippets for the corresponding forms, 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. So 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.sandbox.oscato.com/paymentpage/iframe.html?listId=57c03359e4b0c50a7e8007cfl&network=VISA",
        "logo": "https://resources.sandbox.oscato.com/resource/network/UBUY/de_DE/VISA/logo.png",
        "self": "https://api.sandbox.oscato.com/api/lists/57c03359e4b0c50a7e8007cfl/VISA",
        "lang": "https://resources.sandbox.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). But in the standard version of Selective Native, the submit button is still outside, on the payment page. We therefore need predefined messages that can be exchanged between the frames.

Briefly, 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 (in the iFrames it is enabled by default), and the Pay button should be disabled for 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 the payment page is generated. If the selected method has a plain form (without iFrame) and 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 (eg PayPal).

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 particularly important because 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 to 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. The iFrame will also 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.sandbox.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.sandbox.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, 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.sandbox.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, during 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 always has the following structure >>

The method attribute will reflect the detected method from the list that was given as URL parameter. If none of those were 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, submit the card data direct to the OPG for payment. At this point, you should disable the Pay button and, ideally, show a spinner to indicate that the user now needs 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.

If the validation fails, there will be a validation_response_event message as shown above. These situations should be very rare 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), although it could still happen, eg 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 (eg CHARGE) and the response will be sent as operation_response_event message from the iFrame to the outer page. This means that on the page there should be a listener for this event, taking the response data and reloading or redirecting 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 react to the response, as described under CHARGE Request.

Advanced Use Cases

Specific Actions:

Besides the payment_action message, the following messages can also 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 payment_action we have described combines these two actions, two different response events can result.

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 make 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.sandbox.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 style applied. See the screenshot below for a simple example of where the frame has been translated to French and has been styled to 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 scope of PCI

If you wish to use Selective Native to integrate other payments methods (other than credit cards) then you could use the Orchestration Platform's localized forms snippets returned from the original LIST Response. Find out more about implemeting these localized forms.

Implementing Recurring Charge and Payment Registration for Selective Native Frames

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

The checkbox must be rendered after the frame. Then, on submit, the values of these checkboxes can be used in the frame's post message request to specify whether 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.

For a broader overview, go to displaying registration checkboxes in Localized Forms. 

JavaScript Code

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

Web Content Display

Client-Side Encryption

Integration package content

The integration packages are available as zip files here:

Inside each file, next to the root files with development meta information, you will find these folders:

  • demo: 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: 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

The integration starts with a LIST Request, but with CSE you must use the same integration parameter as for Pure Native integration:

"integration": "PURE_NATIVE"

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

Get the Payload

After the user has entered their payment-account data, the web 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 the Orchestration Platform's form-based API. In other words, the object should have the same attributes as those in the Orchestration Platformaccount object used for CHARGE Requests.

The most common attributes for Charges are:

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

This payload should be represented as shown on the right pane.

Card Account Data Example Object

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

Encrypt with the JavaScript Library

The minified JavaScript encryption library can be included in your web page, either by loading it direct in a <script> tag, or through require or import. In technical terms, the library provides an asynchronous API to encrypt user data in accordance with the standards 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-use scenarios that benefit from an asynchronous programming style.

Input Parameters
  • accountPayload: the JavaScript object (not a string) with any of the attributes available in the Orchestration Platform account object used for CHARGE Requests
  • publicKey: the public key in JSON Web Key (JWK) format (as JavaScript object), which you already received from the Orchestration Platform
  • timestamp (also known as generationTime - 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 standard, eg "2017-09-26T08:41:01.859Z"
  • listId (optional): the longId of the OPG LIST session on which the Charge would be executed. As it is an optional parameter, listId will 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 possible errors during encryption
      console.log(error);
  });
}

Server-Side CHARGE Request

Your server 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: registration flags are still given, unencrypted.

The LIST session for this CHARGE transaction needs to correspond to the listId used during encryption. For security, 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.

Never send unencrypted card data to your server systems.

Example CHARGE Request Body

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


Encryption Details

If you want to build your own encryption client, you will need these extra details. You don't need these details if you simply want to use the JavaScript encryption library provided by the Orchestration Platform.

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. The Orchestration Platformonly 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.

Web Content Display

Backend Use Cases

Web Content Display

Refunds & Cancellations

Payout requests generally only need a payment data structure that includes the amount to be refunded. With some PSPs, you may also be able to submit an empty payout request translating to a full refund. But with other PSPs this does not work for partial refunds that have been issued beforehand—therefore, we do not recommend it. To stay on the safe side, always specify the amount to be refunded.

In some cases you may have to specify which products are refunded (eg 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 most PSPs will give you 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 there, you build the payout URL and post an amount less than the original amount (partial refund) as follows:

Example Request
  • URL: https://api.sandbox.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.sandbox.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.sandbox.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 which the customer will have been fully refunded.

Example Request
  • URL: https://api.sandbox.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 receive 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.sandbox.oscato.com/api/payouts/bef25df3-0d24-412c-805c-fd686821ef6e"
  }
}
Third, exceeding Refund

If your refund amount exceeds the amount originally charged, 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://api.sandbox.oscato.com/api/charges/26d5b179-a3b5-4aa3-ad98-3074b41e7d2b/payout
  • Basic Authentication: UBUY:BBtXa7yubR8ipuT
  • Method: POST

Where 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.sandbox.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 ask you to list the products which are to be refunded. Make sure the product.code and amount (ie quantity) of the refunded products match 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.sandbox.oscato.com/api/charges/26d5b179-a3b5-4aa3-ad98-3074b41e7d2b/payout
  • Basic Authentication: UBUY:BBtXa7yubR8ipuT
  • Method: POST

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

The response and behavior in respect of 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
  }]
}

Cancellation

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

Canceling such a transaction means it will not be processed by the provider—so generally 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 cancellation 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 cancellation, send an HTTP DELETE request (without a body) to the CHARGE resource (as accessible by its links.self URL).

Example Request

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

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

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

Note: This cancellation is similar to the cancellation of a Deferred Charge, but the underlying situation/status of the transaction is different.

Web Content Display

Recurring Charges

In every integration scenario, you will get 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. But 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.sandbox.oscato.com/api/customers/aff7a069-b77a-4023-b5ae-ad4f48596ce4/charge

  • Basic Authentication: Merchant code and Token
  • 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 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 a recurring charge will work (or has ever worked), it just means that a mandate was given.
  2. When there is a change in recurring charge status, a new notification will be sent.
  • Example 1: If the customer had a registered "frontend" account, then registers a new account for recurring charges, there will be another notification.
  • Example 2: If the customer already had a recurring account and registers another one, there will not be a notification (because status will remain true, ie no change)
  1. While an account registration is pending, it will be not affect the recurring charges. The registration state can only change after the registration is successful. This may mean a notification for a newly registered customer (with regId and regPwd) will be sent. 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"
  }
}

Web Content Display

Automated Denial Management

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.

declinesCount parameter is provided to inform the merchant about the number of retry attempts made for the payment. Once this number reaches 10 (system default), the payment account is automatically blocked by the system. The logic of increasing and resetting the count is described in this chapter below. This logic applies not only for retry attempts made by ADM but for merchant initiated recurring charges as well.

Blocking an account after 10 attempts is default system behaviour, but there is a possibility to switch off this logic, so the account will not be blocked. In order to switch off retry attempts count, please contact our support team.

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 retry 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.sandbox.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 separate 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'.

Web Content Display

Deferred Payments

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.

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 days or even weeks. For Open Invoice Providers this is the signal that the payment is due, whereupon 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 possible to see the status code in the PURE_NATIVE integration scenario only, not with the other integration scenarios for security reasons. You could use the PURE_NATIVE integration parameter for testing reasons, but 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, 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 actions are 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, only in "Pure Native" integration 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, because, for example, you cannot deliver the 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 (ie after 10 days). For some payment networks (Open Invoice methods, for example) these requested funds may never expire. Future payments may therefore 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.sandbox.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 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. To do that, you would have to delete/cancel the DEFERRED CHARGE after the partial closing has been made. This 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.sandbox.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.

But the closing can also be performed partially and multiple times. You can do this if, for example, an order has to be split into different shipments. In this case, you can submit a different amount and also a list of products 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 the Orchestration Platform side, which represents the actual capture of the funds. It has a different ID from 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, eg 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"
  }
}



                

Web Content Display

Chargebacks

Chargebacks are by definition asynchronous. Therefore, the OPG will send a Status Notifications to inform your system about them. This means simplified implementation for you, because every payment provider delivers this information differently, and often only passively, meaning active polling is needed.

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 to intervene.

These stages are modeled and described under Status and Reason Codes. Below is an representation of their possible transitions:

Web Content Display

Fallback Routing

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 of 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 also configured to 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 straightforward. If the provider declines the transaction for a recoverable reason, the payment data as provided by the customer will be used to immediately try again with another provider. 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, ie Recurring Charges, are handled differently because the Payment Gateway is not allowed to store credit card verification numbers (CVC and CVV) and cannot therefore simply 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 by that customer, with alternative providers. If 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, another credit card that is stored, for example. If those are found, the whole story will be repeated with these accounts, ie looking for alternative providers again.

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 only a temporal pending status is returned to the payment gateway, 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.

But if no technical connection to the asynchronous provider could be established in the first place, owing to a provider downtime for example, Fallback Routing will be triggered because the OPG is able to act instantly.

Web Content Display

Gambling Restrictions

The OPG supports additional requirements which are often needed by merchants in the gambling industry, and certain wallet payment methods, PayPal for example.

1:1 Relationship

This feature can be enabled by our support team for a specific payment method and merchant division. We will ensure 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 (eg 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 (eg PayPal) the account ID used 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 is redirected to an explanation on the merchant page.
  2. Mary pays into her gambling account with her PayPal account mary123@coolmail.net. For some reason, she has a second account with the same gambling merchant, and there she also wants to pay with her PayPal account mary123@coolmail.net. After she confirmed the payment on the PayPal page, the transaction was declined by the Payment Gateway and she was redirected to an explanation on the merchant page.
Technical Communication

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 owing 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 (eg PayPal email).

  • What happens if the feature gets turned off temporarily then on again later?

The payment account IDs used are only recorded while 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.

Then 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, makes a first-time payment with her PayPal account mary123@coolmail.net, and the payment succeeds.

After that, the restriction feature gets turned on again.

John can now only make payments with his PayPal account john_doe@supermail.com again (or some other method, of course). johnny432@mail.org would be declined. But if he had a second gambling account, he could use his PayPal account johnny432@mail.org.

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 their gambling account.

  • How does the feature work if there are multiple merchant divisions?

The feature can be turned on and off per division separately. The feature will double-check 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.

But she can use a different PayPal account now to pay in D2, eg peterpoor@fastmail.com.

Note: The underlying assumption in this example is that the two seperate gambling accounts of Mary in D1 and D2 each have a different customer.number delivered to the Payment Gateway. If it were 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 the feature is not enabled there.

  • If a transcation is declined by this OPG feature, does the transaction still occur in with the wallet method eg 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

Transaction ID Types

A transaction object contains these IDs:

  • Assigned by the Orchestration Platform (will alway be present):
    • longId: generated ID (uniqueness guaranteed) for consecutive operations
    • shortId: 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 the Orchestration Platform)
    • 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.

Web Content Display

Status Notifications

Technically the notifications are normal HTTP(S) GET requests with appended query parameters (as if they would come from a browser). They are sent to a URL defined by you, 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 parameters 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 your 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.

The client should simply react on the reply, displaying the result to the customer. Your 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 your 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.

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.

Notification Parameters
Name Type Appearance Description
transactionId String 1 ID as given by you. 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 the Orchestration Platform'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

Your 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
clearingAmount Number 0..1 Cleared amount of the operation confirmed by a PSP or a financial institutution. Depending on the type of operation either authorized or captured amount is sent. Amount provided as decimal delimiter, for example: 12.99
clearingCurrency String 0..1 The currency of the cleared amount. The value format is displayed as per ISO-4217, for example "EUR"
reference String 0..1 Payment reference text used (as given by merchant)
retryAfter Datetime 0..1 Suggestion when you 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.

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 unnecessary load on our system and yours.
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
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 you if the PSP uses his own IDs.
mandate.creditorId String 0..1 Creditor ID used for this transaction. Can be different from your ID if the PSP uses his own ID.
mandate.authentication.date String 0..1 When the mandate was issued according to you.
mandate.authentication.city String 0..1 Where the mandate was issued according to you.
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

 

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 your 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.

Web Content Display

Keeping your notifications secure

It's importanty that you can recognize the notifications as valid in cases when a malicious party tries to spoof your servers by generating false notifications. You can do it in one of the three available ways:

  • by adding custom parameters to the notificationURL (shared secrets)
  • by opting for POST notifications
  • By adding additional headers to your notifications

If, for notification security reasons, you allow-list our IP's, note that we stop supporting static IP's as of April 1, 2021. Use one of the methods mentioned above to make sure your notifications are secure.

Regardless of whether you process a notification or not, acknowledge the receipt with an HTTP 200 OK. Otherwise the Payment Gateway's guaranteed message delivery will repeat them, This will put unnecessary load on our system and yours.

 

Custom Parameters (shared secrets)

You can  add custom name=value pairs to the list of parameters in the notification URL by passing them in the LIST request callback.notificationUrl definition. Any number of parameters added to the notification URL in the LIST request will be sent back once the notification arrives in your servers. On the right pane we can see the example of a token containing the value 512938z1b176598113bA1b3 sent through a LIST and later received as a notification parameter.

Use the shared secret method to control if the notifications sent by the OPG are expected by your systems. You can achieve it by adding a token to URLs provided to the Orchestration Platform and checking that notifications received through these URLs have the same token. 

Example Definition in the LIST Request

"callback": {
  "returnUrl": "https://dev.oscato.com/shop/success.html",
  "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
  "summaryUrl": "https://dev.oscato.com/shop/summary.html",
  "notificationUrl": "https://dev.oscato.com/notification?token=512938z1b176598113bA1b3"
}

Example Notification URL
https://dev.oscato.com/notification?token=512938z1b176598113bA1b3&accountStatus=registered&recurrence=false&customerRegistrationId=5d...

Additional headers

You can add more metadata to your transactions by providing custom headers to the transaction LIST request. The headers will be returned as a list in the notification you receive from our orchestration platform. The headers can be added on the transaction or division level.

If you want to add headers to transactions on the division level, contact our support. If you want to add headers to a transaction, you can do it per LIST request in a payment session (see right).

You can use this additional information to separate divisions in your systems, or for analytical or security purposes.

There is no limitation to the number of headers other than that of your HTTPS server.

There are also few limitations on the content of the header and we accept everything that doesn't overwrite OPG original headers. For example, we don't allow user agent number to be in the header. If there is a risk that the original header will be overwritten, the additional header is dropped by the system.

"callback":
{
"returnUrl": "http://example.com",
"summaryUrl": "http://example.com",
"cancelUrl": "http://example.com",
"notificationUrl": "http://example.com",
"appId": "string",
"notificationHeaders":
[
{ "name": "string",
"value": "string" }
]

POST and GET notifications

You can choose to receive notifications as a GET (the default) or POST request. In GET, the data will be placed in the query URL and in POST, in the body. Fore security reasons, we advise selecting POST notifications.

Inform support if you prefer to receive POST notifications so that they can configure those for you.

Web Content Display

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 codes and messages should not be presented to end customers due to their technical content.

There are 4 different code types sent during a payment session: Interaction codes, status codes, return codes, and result codes, plus a longer message delivered through the result info field.

The matrix below summarizes them:

Code Description
Interaction Codes Informs what the frontend system or backend shop system should do after an operation. Example: proceed after a successful payment.
Status Codes Describes the current status of an operation. Example: charged after a successful transaction.
Return Codes Unified detail representation of payment providers' responses for deeper analysis.
Result Codes Contains the payment provider's native code, if available. Can be useful for further investigations of the nature of a specific operation result.
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

The interaction code is actually composed of two parts: the code itself and a reason, which expands its meaning and can be used for more refined decision.

When in a payment session, a merchant must use the interaction code to decide on how to interact, i.e. how to react after a payment step is done. The merchant user interface (for frontend sessions) or server (for backend sessions) only needs to use the interaction codes to decide which step should be taken in the payment flow, meaning it will be able to decide if a proceed, reload, retry, etc is applicable in a given moment.

Interaction Codes are designed to lead a merchant shop system to the appropriate action in a payment session. However, they are not a comprehensive reflection of all the statuses a payment may have. This information is present in the Status Codes, which bring a deeper understanding of the current status of a transaction. Keep in mind that the Status Codes don't need to be evaluated during a session, but they can be helpful case a merchant wants to investigate the details of a particular scenario while troubleshooting or testing. 

Possible Interaction Code Values
Code Reason Description
PROCEED  

The operation worked as expected.

  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.

  TAKE_ACTION You as a merchant need to take action to proceed with this transaction, typically manually confirm or decline it on the provider side where it could be held back for reasons such as risk or others.
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

Probably a duplicate frontend Charge was issued on a LIST, meaning that the payment was already successful the first time. Then you should not show an error but indicate the successful payment to the user. For recurring backend charges a duplicated request may be declined by the provider, you should check your system logic.

  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 ("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.
  STRONG_AUTHENTICATION As per 3DS 2 strong customer authentication (SCA) is required to make the transaction successful; other retries are possible.
VERIFY   An unexpected error, currently only generated by the Orchestration Platform's resources and frontend libraries, has occurred. Your system should wait for a backend notification and/or verify the transaction status with the Orchestration Platform.
  COMMUNICATION_FAILURE A communication failure occurred on the frontend (e.g. network connectivity on a mobile device was lost during payment). Your order system should consolidate the transaction state with the Orchestration Platform's backend. Your frontend should display a message to inform the end-customer (e.g. An error has occurred and that they should check their order status on the webshop).
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.
  UPDATED A payment method was registered by the customer (standalone registration). To display it on the screen, reload the payment page.

 

Web Content Display

Status Codes

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:

Please note that the diagram above, while being a general classification of payment statuses, does not represent the actual transition flow expected in a payment session. In fact, many PSPs can initially reject a payment request (due to internal, identified errors) and later accept it. Also, initially approved transactions can move in a later stage to a rejected state (example chargebacks). For this reason, the OPG will always listen to the PSPs' backend notifications and update the transaction statuses accordingly, even transitions between such "positive" and "negative" states.

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 separately, such as with the Sofort Banking method)
^ paid_out_partial A previously charged transaction has been partially paid out.
paid_out refund_credited Payout completed. This can apply to a Refund transaction or the initial Charge when completely paid out.
^ 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). In most cases you can wait for further notification. Only processing_paused may require action, please check!
^ refund_requested ^
  payout_requested ^
^ payment_demand_requested ^
^ payment_demanded ^
^ credit_requested ^
^ registration_requested The payment process is waiting for an account registration to be complete.
^ retry_scheduled A recurring payment attempt failed, but the Orchestration Platform 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 the Orchestration Platform side with the possibility to cancel it before it gets processed (see Refunds & Cancelations).
^ processing_paused The payment request was received and is currently held back on provider side. Typically the merchant needs to manually confirm this transaction with the provider to proceed.
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 The merchant is notified that a chargeback will take place. There is enough information to conclude that a charge to the customer was incorrect.
information_requested notification_of_chargeback Charge disputed by customer: e.g., customer claimed a transaction cancelation directly at the PSP. The 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 ^
Preset Statuses

Concerning entity = payment

The following statuses can occur for PRESET flows in Delayed Payment Submission and Express Checkout, in addition to the statuses above. Note that in Delayed Payment Submission the preset account is part of the LIST object which will not change the status. Therefore these statuses only occur on the PRESET call itself in this case, and are visible if issued from the backend.

Status Code Reason Code Comment
preset preset The Preset is complete and ready for a CHARGE.
pending preset_requested The Preset is still incomplete. In Express Checkout the user may have to select further data.
^ confirmation_requested Occurs in Express Checkout only, when the Preset needs a CONFIRM to be completed.
failed preset_failed Operation failed due to technical reasons
rejected preset_rejected Operation failed due to configuration issues.
declined preset_declined Operation declined by payment provider
expired preset_expired The completed or still incomplete Preset expired and can no longer be used for consecutive operations.
canceled preset_canceled Operation was canceled (typically by the merchant)
Customer Registration 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

 

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

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, wait for updated status
2 OK_SCHEDULED_FOR_BATCH   Pending due to transaction queuing, wait for updated status
5 OK_TEST_MODE   OK / Production level test mode
6 OK_CUSTOMER_ACTION_REQUIRED   Customer needs to take action, eg manually confirm on provider side. The merchant does not need to inform the customer, this is taken care of.
7 OK_MERCHANT_ACTION_REQUIRED   Merchant needs to take action, eg manually confirm on provider side, or inform the customer to take action.
8 OK_PROVIDER_ACTION_REQUIRED   Provider needs to take action, eg manually review and approve the transaction.
9 OK_DCC_REQUIRED   No action required. This code is returned when the transaction was directed to the DCC page and is pending verification. Either the frictionless flow will be triggered or a challence page will be presented to the customer.
11 ABORTED_BY_CUSTOMER   Aborted, operation is aborted by customer
14 CANCELED   Canceled, operation is canceled (typically by merchant)
15 CHARGEDBACK   Charged back, charge back was 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
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 TRANSACTION_IN_USE   Transaction is blocked by other request
11011 CURRENCY_CONVERTER_INVALID_RATE x Currency converter - invalid currency rate
11012 CURRENCY_CONVERTER_MISSING_RATE x Currency converter - missing currency rate
11013 TERMINAL_IN_USE x Terminal is locked by other request
11014 CURRENCY_CONVERTER_ERROR x Currency converter service error
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)
45065 CUSTOMER_AUTHENTICATION_REQUIRED   By providing this code, the issuing bank indicates that this transaction could be accepted if it's repeated with Strong Customer Authentication
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

 

Web Content Display

Test Accounts & Magic Numbers

Web Content Display

Test Accounts

Please note that we don't keep track of updates of PSP test card numbers, so the table below might not be entirely correct. To avoid false negatives while testing, please make sure that you get the PSPs' Sandbox test numbers directly from their developer documentation. We link some of these PSPs docs directly under their name in the table below.

Test Account Numbers Credit Cards
Payment Service Provider VISA MasterCard American Express Diner's Club Discover Maestro

Adyen

Holder name: any
Expiry date: 10 / 2020
CVV: 737
Number: 4111 1111 1111 1111
Holder name: any
Expiry date: 03 / 2030
CVC: 737
Number: 5555 5555 5555 4444
Holder name: any
Expiry date: 03 / 2030
CID: 7373
Number: 3700 0000 0000 002
Holder name: any
Expiry date: 03 / 2030
CVV2: 737
Number: 3600 6666 3333 44
Holder name: any
Expiry date: 03 / 2030
CID: 737
Number: 6011 6011 6011 6611
Holder name: any
Expiry date: 03 / 2030
CVC: 737
Number: 6771 7980 2100 0008
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 / 2020
CVV: 123
Number.: 4111 1111 1111 1111

Holder name: any
Expiry date: 12 / 2020
CVV: 123
Number.:5399 9999 9999 9999

       
eMerchantPay Holder name: any
Expiry date: 01 / 2020
CVV: 123
Number.: 4111 1111 1111 1111
Holder name: any
Expiry date: 01 / 2020
CVV: 123
Number.: 5500 0000 0000 0004
       
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
       
Orchestration Platform 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

 

Notice: For 3D Secure tests, use 4111 1111 1111 1301 card number.

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 4-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
Holder 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.: 4111 1100 0000 0211 (authorization)

Number.: 4111 1100 0000 0112 (decline)

Holder name: any
Expiry date: any
CVV: any
Number.: 5100 0000 0000 0511 (authorization)

Number.: 5100 0000 0000 0412 (decline)

       
Six Holder name: any
Expiry date: 12 / 2018
CVV: 596
Number: 4761 7390 9000 0088
Holder name: any
Expiry date: 12 / 2025
CVV: 123
Number: 5413 3300 8960 0010
       
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

Notice: For 3D Secure tests, use ">>>3D" as holder name.
Other CVVs trigger different behaviors.
More information

 

Holder name: Tom James,
number: 5555555555554444,
expiryMonth: 07,
expiryYear: 2019,
CVV: 555

Notice: For 3D Secure tests, use ">>>3D" as holder name.
Other CVVs trigger different behaviors.
More information

 

       
Bank Accounts
PSP Adyen Wirecard Sofortüberweisung Orchestration Platform 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

or

IBAN: DE02120300000000202051
BIC: BYLADEM1001
Account Holder: Any

 

Web Content Display

Magic Numbers

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 holder name or 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 listed for frontend interactions, and ideally should be the only codes evaluated during a payment session. For other scenarios like ADM, Status Codes should be used.
Test cases for Frontend Checkout and Chargebacks:
Test Case # Holder Name 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 testcase 101 1,01 CHECKOUT Successful frontend payment sync LIST, CHARGE charged PROCEED (OK)  
102 testcase 102 1,02 CHECKOUT Failed frontend payment (technical reason) sync LIST, CHARGE failed TRY OTHER NETWORK (1)
103 testcase 103 1,03 CHECKOUT Declined frontend payment (business reason) sync LIST, CHARGE declined RETRY (1)
104 testcase 104 1,04 CHECKOUT Successful frontend payment async LIST, CHARGE pending, charged PROCEED (PENDING), PROCEED (OK)  
105 testcase 105 1,05 CHECKOUT Failed frontend payment (technical reason) async LIST, CHARGE pending, failed PROCEED (PENDING), ABORT  
106 testcase 106 1,06 CHECKOUT Declined frontend payment (business reason) async LIST, CHARGE pending, declined PROCEED (PENDING), RETRY  
107 testcase 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 testcase 108 1,08 CHARGEBACK   -

LIST, CHARGE,charged_back

CHARGE success, charged_back PROCEED (OK)  
109 testcase 109 1,09 CHARGEBACK   - LIST, CHARGE, information_requested, charged_back CHARGE success, information_requested, charged_back PROCEED (OK)  
110 testcase 110 1,10 CHARGEBACK   - LIST, CHARGE, information_requested, charged CHARGE success, information_requested, charged (debited) PROCEED (OK)  
111 testcase 111 1,11 REDIR Customer gets redirected for frontend charge and completes payment async LIST, CHARGE pending, charged PROCEED (PENDING), PROCEED (OK) (2)
112 testcase 112 1,12 REDIR Customer gets redirected for frontend charge and cancels payment async LIST, CHARGE pending, aborted PROCEED (PENDING), ABORT  
119 testcase 119 1,19 CHARGEBACK   - LIST, CHARGE, charged_back,
charged
CHARGE success, charged_back,
charged (debited)
PROCEED (OK)  
120 testcase 120 1,20 CHECKOUT Failed frontend payment (business  reason) sync LIST, CHARGE failed TRY_OTHER_NETWORK  
121 testcase 121 1,21 CHECKOUT   sync

LIST,

CHARGE

failed TRY_OTHER_ACCOUNT  
122 testcase 122 1,22 CHARGEBACK   - LIST, CHARGE, information_requested, charged_back CHARGE success,
information_requested
(notification_of_chargeback), 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 # Holder Name 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 testcase 201 2,01 PAYOUT-TX Successful full refund of a previous transaction sync LIST, CHARGE, PAYOUT charged, paid_out PROCEED (OK), PROCEED (OK)  
202 testcase 202 2,02 PAYOUT-TX Failed full refund of a previous transaction sync LIST, CHARGE, PAYOUT charged, failed

PROCEED (OK), RETRY

 
203 testcase 203 2,03 PAYOUT-TX Declined full refund of a previous transaction sync LIST, CHARGE, PAYOUT charged, declined PROCEED (OK), RETRY  
204 testcase 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 testcase 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 testcase 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 testcase 207 2,07 PAYOUT-PART Successful partial refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial) charged, paid_out PROCEED (OK),  
208 testcase 208 2,08 PAYOUT-PART Failed partial refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial) charged, failed PROCEED (OK),  
209 testcase 209 2,09 PAYOUT-PART Declined partial refund of a previous transaction sync LIST, CHARGE, PAYOUT(partial) charged, declined PROCEED (OK), RETRY  
210 testcase 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 testcase 211 2,11 PAYOUT-PART Failed partial  refund of a previous transaction async LIST, CHARGE, PAYOUT(partial) pending, charged, pending, failed PROCEED (OK),  
212 testcase 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 testcase 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 testcase 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 testcase 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 testcase 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 testcase 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 testcase 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 # Holder Name 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 testcase 401 4,01 DEFER Successful deferred Charge sync LIST, CHARGE CHARGE: preauthorized PROCEED (OK) Credit Cards or Direct Debit
402 testcase 402 4,02 DEFER Failed deferred Charge sync LIST, CHARGE CHARGE: failed ABORT  
403 testcase 403 4,03 DEFER Declined deferred Charge sync LIST, CHARGE CHARGE: declined RETRY  
404 testcase 404 4,04 DEFER Successful deferred Charge async LIST, CHARGE CHARGE: pending, preauthorized PROCEED (PENDING)  
405 testcase 405 4,05 DEFER Failed deferred Charge async LIST, CHARGE CHARGE: pending, failed PROCEED (PENDING)  
406 testcase 406 4,06 DEFER Declined deferred Charge async LIST, CHARGE CHARGE: pending, declined PROCEED (PENDING)  
407 testcase 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 testcase 408 4,08 REDIR & DEFER Successful deferred Charge with Redirect network async LIST, CHARGE CHARGE: pending, preauthorized PROCEED (PENDING) e.g., PayPal
409 testcase 409 4,09 DEFER Deferred Charge that expired due to missing Closing sync LIST, CHARGE CHARGE: preauthorized, preauthorization_expired PROCEED (OK)  
410 testcase 410 4,10 DEFER Successful deferred Charge and full Closing sync LIST, CHARGE, CLOSING (full) CLOSING: charged PROCEED (OK)  
411 testcase 411 4,11 DEFER Successful deferred Charge, failed full Closing sync LIST, CHARGE, CLOSING (full) CLOSING: failed ABORT  
412 testcase 412 4,12 DEFER Successful deferred Charge, declined full Closing sync LIST, CHARGE, CLOSING (full) CLOSING: declined RETRY  
413 testcase 413 4,13 DEFER Successful deferred Charge and full Closing async LIST, CHARGE, CLOSING (full) CLOSING: pending, charged PROCEED (PENDING)  
414 testcase 414 4,14 DEFER Successful deferred Charge, failed full Closing async LIST, CHARGE, CLOSING (full) CLOSING: pending, failed PROCEED (PENDING)  
415 testcase 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 # Holder Name Payment Amount Feature Code Test Case Name s/a Test Steps / Calls statusCode result(s) CHARGE interaction Code (Reason) reply
701 testcase 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 Standalone Registration:
Test Case # Holder Name Payment Amount Feature Code Test Case Name s/a Test Steps / Calls statusCode result(s) CHARGE interaction Code (Reason) reply
751 testcase 751 7,51 REG Successful Standalone Registration async LIST for Update, REGISTRATION

Init. REGISTRATION: pending,

CUSTOMER: registered

Initial REGISTRATION: PROCEED (PENDING),

Final: PROCEED (OK)

When running this test, please send a LIST request for account registration, and register the account setting the parameter autoRegistration = true.

Testcases for ADM

Please note that these cases are applicable only to recurring charges.

Test Case # Holder Name Payment Amount Feature Code Test Case Name s/a Test Steps / Calls statusCode result(s) CHARGE interaction Code (Reason) reply
801 testcase 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 testcase 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 testcase 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 testcase 804 8,04 ADM-DECLINED-FAILED   sync

Recurring CHARGE, (ADM - failed), (ADM - failed), (ADM - failed)

CHARGE failed ADM for interaction RETRY - DECLINED
805 testcase 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 testcase 806 8,06 ADM-TEMPORARY_FAILURE-FAILED   sync

Recurring. CHARGE => (ADM - failed) => (ADM - failed) => (ADM - failed)

 

CHARGE failed ADM for interaction RETRY - TEMPORARY_FAILURE

 

Web Content Display

Developer Resources

Web Content Display

OpenAPI

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).

Notes: 

  •  In DISPLAY_NATIVE, HOSTED, and SELECTIVE_NATIVE, the CHARGE request is always sent by a browser.
  • If you want to comply with SAQ A-EP, make sure your credit card payments are triggered from the browser. 

Please find available for download:

Web Content Display

Reconciliation API

How does reconcilliation work

Different payment providers can provide their reconciliation data in various formats and following their own schedule.  

The more providers the more statuses, formats, and complexity layers an accounting department needs to deal with and understand. There is no globally accepted standard, so some providers supply the reconcilliation information in files that need to be pulled from FTP servers, some require merchants to log on to an HTTP service, and some push files directly to the merchant.

The Payoneer reconciliation pipeline collects reconciliation batch data from Providers, unifies it into a specified format, enriches the data (for example with merchant division or storeID), and makes the data available over a standardized API service.

This is a paid service.

Configuration options

You can decide how often you want to get the reconciliation reports, in what format (JSON or CSV), and how granular the data should be. You also need to decide on the data structure that would best fit your needs. 

What we need prior to configuring the reconcilliation report for you is the following data that helps us locate and fetch the original report:

Field

Description

Collector

Schedule

Cron Expression

ALL

Data Collector

SFTP, HTTPS

ALL

Merchant

Merchant Details

ALL

ContractID

Merchant Details Or Provider

ALL

Username

Merchant Login Details

ALL

Password

Merchant Login Details

ALL

Token

Token (if necessary)

ALL

Server

Address(URLS) of server

ALL

Date Range

Amount of Days to request data for

API

Data Location

Folder(s) to search

SFTP

Search Parameters

File naming convention to search for. For example: .csv, recon,  or settlement.txt.  Regex is supported.

SFTP

Scan Subfolders

Y or N (Boolean)

SFTP

Scan Depth

1 or fixed range unless blank then as deep as possible

SFTP

Delete Data on Collection

Delete once collected

SFTP

Move when collected

Move To: Base directory path to move to

SFTP

Note that reconcilliation is configured per provider.

Processing

We store the data for processing as a list of rules that define the source format from the PSP and  how we  move this  data into our unified  format. We can also also perform mathematical operations on the data, for example dividing overal fees into transaction fees based on the transaction percentage of total transactions.

API 

Once we create the data mapping for you and set all the reconcilliation rules, you can start using the API. 

To explore the parameters of the Reconcilliation Report API, click API REFERENCE. The API contains the DATA parameters that you can use to get to the batch data in either JSON or CSV, and SUMMARY parameters that offer access to report summary. 

Web Content Display

Domains and Accounts API for Merchants

Domains and Accounts API for Merchants
 
With the Domains and Accounts API you can: 
  • create and manage accounts for human users and systems, and 
  • manage access rights for accounts to the data in their domain by assigning roles

You can find the API parameters in our API reference.

Introduction to Domains and Accounts API for Merchants
 
As a merchant using our orchestration platform you are granted a domain that contains your own set of configurations and payment transactions. Those must only be accessible to your:
  • human users that use the platform interactively, and
  • systems that access the platform (mostly to process payment transactions).
 
These can be translated into the following account types:
 
  • User accounts: have a username and password; these accounts get assigned a dynamic token to authorize API calls with the authentication server, or when the user logs in.
  • Token-only accounts: only have a (permanent/static) token. These are important in, for instance, server to server communication.
 
Each account has a unique account ID (an arbitrary alphanumeric string that is assigned when the account is created) and can have different roles in the merchant domain, which determine the API functions this account has access to. 
 
For example, the roles of an account can look like this:
{
     "MERCHANT/M1": ["admin"],
}
or 
{
     "MERCHANT/M2": ["opt-business", "opt-technical"]
}
meaning that the first account has the admin role in the domain MERCHANT/M1 and the second accout has two roles: opt-business and opt-technical in the domain MERCHANT/M2.
 
Accounts can be created independently of a domain and can be assigned roles in multiple domains. This is done in two separate steps:
 
  • Create account
  • Assign roles in domain MERCHANT/M1 (or in the MERCHANT/M2 in the second example)
 
However, most token-only accounts are used in a single domain. There is a simplified one-step way to create a token-only account with some roles in a single domain. Those accounts can still be assigned roles in other domains later.
 
Each role exists in a specified domain that has a type and name forming a domain key. A domain key is a unique identifier for the domain. 
 
For example, your domain can be the following:
Domain type Domain name Domain key Description
Merchant M1 MERCHANT/M1 The domain for an active merchant M1

 

Every domain type usually has its own set of meaningful role names. These are names of roles that are used in a permission check for an API and/or GUI. For example, they can be the merchant user roles for the "MERCHANT"-type domains. You have the following roles to select from for your users:

 Role name Description
admin manage the domain and the roles in the domain
opt-technical allows access to merchant configurations and payment transactions on Sandbox
opt-business allows access to merchant configurations and payment transactions on Sandbox and Live
opt-customer-care additional role to allow giving refunds
opt-risk-manager  allows access to Risk management configurations
SANDBOX_PAYMENT allows for making Sandbox payments 
PAYMENT allows for making Live payments
 
Start working with the API
  1. Use the tokens received from the orchestration platform's team to authenticate to make calls. You should receive two tokens: a token to manage your domain and a token to create accounts.  Use the token as password for the password field in Basic Authorization header when you make an API call. 
  2. Review the roles you can grant to users (and token-only accounts).
3. Create your first single-domain token-only account . In this example, the domain MERCHANT/M1 is used:
POST https://authapi.live.oscato.com/domains/MERCHANT/M1/accounts
 
For the account to have the opt-business role, use this as the request body:
{
    "type": "TOKEN",
    "roleNames": [
        "opt-business"
    ]
}
The response will be the following:
{
    "id": "579b5360...",
    "type": "TOKEN",
    "token": "2ml9gbe...",
    "roleNames": [
        "opt-business"
    ]
}
4. Create your users with the following command:
POST /accounts
 
The request body must contain the user's e-mail address as userName and an initial password for the user
 
For example:
{
    "type": "USER",
    "userName": "users@mail.address",
    "password": "initialPasswordForUser"
}
 
Use the "create accounts" token for authorization of this request. The response will be:
{
    "id": "579b5360...",
    "type": "USER",
    "userName": "users@mail.address"
}
 
You can assign roles to the users later on. 

 

Web Content Display

Glossary

  • Adapter: A software module running at the Orchestration Platform that makes the connection to a particular Payment Provider, translates (payment) requests into their API and logic, and translates back into the Orchestration Platform'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 the Orchestration Platform 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 the Orchestration Platform.
  • 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: the Orchestration Platform 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 the Orchestration Platform payment features.
  • Token: Secret values used for security. Tokens are needed for every merchant that wants to use the Orchestration Platform APIs, they are unique for each merchant and differ between sandbox and live environments.

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

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 the Orchestration Platform'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 the Orchestration Platform'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 the Orchestration Platform, 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 the Orchestration Platformside need to always support the choices presented by the merchant's payment page. As a result there is a technical provider-independence for the Orchestration Platformmethods, 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 the Orchestration Platformis configured to offer payment methods that complement the legacy ones. Therefore the Orchestration Platform'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 the Orchestration Platform instead.

Hybrid Page with AJAX library: Also in this approach there will be a mix of legacy and the Orchestration Platformmethods on the payment page. Instead of orchestrating this on your server-side, however, the Orchestration PlatformAJAX library will inject the Orchestration Platformmethods on client side and will also support the distinction on submit (going to legacy or the Orchestration Platformendpoints). 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 the Orchestration Platform'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 the Orchestration Platform-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 the Orchestration Platform's Open Routing functionality and override the Orchestration Platform's routing recommendation in the CHARGE request. In any case.

Fail-over payment page: You are using the Orchestration Platform'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 the Orchestration Platformwas 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.

Web Content Display

Hybrid AJAX Page

The idea is that you keep your existing method list, submit button, and logic. With the help of the Orchestration Platform's AJAX library you append the Orchestration Platform's methods to your payment method list (visually). For Orchestration Platform's methods you use the Orchestration Platform's submit logic (also through the AJAX library) which is technically triggered by a separate submit button. However both, your legacy submit button and the Orchestration Platform'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 the Orchestration Platform 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 the Orchestration Platform's AJAX library.

Step-by-Step Guide

1. Integrate our payment method list (through its AJAX library)

Integrate the Orchestration Platform's AJAX library into your payment page as described in AJAX Library Integration. The placeholder for the Orchestration Platform's methods (the paymentNetworks div) should go directly below (or above) your existing method list. Adjust the CSS in a way that the the Orchestration Platform 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 the Orchestration Platform methods, not your legacy button (see step 4 how you can spare this and extend your own button instead).

2. Integrate the Orchestration Platform's LIST request

In order to initialize the Orchestration Platform'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 the Orchestration Platform'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 the Orchestration Platform's AJAX library: deselectDynamicMethods() - This will remove any existing selection in the Orchestration Platform list. Also it will hide the Orchestration Platform'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 Orchestration Platform 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. The Orchestration Platform's AJAX library will automatically show the Orchestration Platformbutton, 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 the Orchestration Platform's JavaScript function from 3.1. which will also hide the Orchestration Platform button. Your callback function from 3.2. should in turn hide your legacy button while the Orchestration Platform's AJAX library will show the Orchestration Platform 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 the Orchestration Platform 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 Orchestration Platform button.

In this variation you don't have a separate Orchestration Platform 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 Orchestration Platform method is selected. In case of a legacy method it can just proceed as before. In case of an Orchestration Platform 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.sandbox.oscato.com/pci/v1/",
  listId: someVariable,
  deselectLegacyMethods: yourCallbackFunctionName
});

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 the Orchestration Platform 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. The Orchestration Platform'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 our 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

3D Secure 2

Refer to the information provided to comply with the PSD2 directive and upgrade to 3DS 2.

About 3DS 2

3D Secure 2 is a solution for Strong Customer Authentication (SCA) that is required under PSD2 for card payments.  3D Secure 2 offers extensive fraud protection, user convenience, and technology. It will be effective as of January 1, 2021 (and September 14, 2021 in the UK).

What is SCA

Strong Customer Authentication (SCA) is a set of requirements introduced by the EU Revised Directive on Payment Services (PSD2).

SCA is a multi-factor authentication based on the use of two or more elements categories as possession (something a user owns, such as a mobile phone), inherence (for example biometrics), and knowledge (something a user knows such as passcode). These categories are independent from each other, so that the breach of one form of authentication doesn't compromise the reliability of the others. SCA is designed to protect the confidentiality of the authentication data.

 SCA is only required when both the cardholder's issuing bank and the merchant's acquirer are located in the EEA region. If either of these parties is outside the EEA, then the SCA regulation does not apply.

What is PSD

PSD2 (the second Payment Services Directive) is an EU Directive on the regulation of payment services and payment service providers. PSD2 applies to payments in EU/EEA currencies between payment providers in the EU/EEA.

Benefits of 3DS 2

The main benefit of 3D Secure 2 is frictionless flow. For merchants and card issuers it means a far greater opportunity to easily authenticate transactions to identify high risk transactions and reduce fraud.

Customers, on the other hand, can complete the 3D Secure authentication process without being redirected from the checkout flow if the transaction is deemed eligible by their bank.

 
What's frictionless flow in practice

  1. A merchant provides risk data together with a transaction

  2. An issuer performs risk analysis and decides whether the challenge is required. If the risk is considered to be low, no challenge is presented to customer. If the risk is considerable, the bank will respond with a request for user authentication (the challenge). The challenge can be presented in the customer application, or in the bank's application on a mobile device.

 

The implementations of 3DS 2 requires merchants and card issuers to exchange more data, including cardholder's key addresses, browser language, or location data. This increase in data shared between merchants and issuers results in better fraud assessments and reduction in the rate of false declines.

Additionally, Visa and Mastercard have both created policies where merchants who utilize 3DS 2 can receive a liability shift in the event of fraud related chargebacks when they attempt authentication.

Tell me more about differences between 3DS 1 and 3DS 2

3DS 1.0

3DS 2.0

Static passwords, security
questions and risk-based
authentication

Eliminates static passwords
for stronger two-factor
authentication

Relies on browser only

Supports different
payment channels
(in-app, IoT, or browser)

15 data elements

150 data elements exchanged

Guest checkout only

Supports guest checkout with additional use cases (wallets, tokenization, etc.)

Can I keep using 3DS 1 or do I have to upgrade to 3DS 2

For the time being, no transaction should be declined by the issuer because 3DS 1 is used.

However, Mastercard Europe will double their authentication fees for 3DS 1. This increased fee will not apply to 3DS 2 as per January 1, 2021.

In October 2021, Visa will remove liability protection from 3DS 1. The liability shift, which protects your customers from fraud, will remain for 3DS2.

In October 2022, Mastercard is planning to sunset 3DS 1. Customers will then need to process all authenticated transactions through 3DS 2 after this date.

Additionally, 3DS1 might not work with recurring and card-on-file transactions. The first transaction in a recurring sequence and card-on-file transactions must go through SCA which is not guaranteed by using 3DS 1. If SCA is not used, the subsequent transactions might fail.

For the mentioned reasons, we highly advise implementing 3DS 2 as soon as possible.

What happens if I'm not prepared to integrate any of the 3DS versions

If this is the case, and your acquirer and the issuer are based in the EEA, your transactions might start failing.

If your acquirer is based outside the PSD2 zone, you are fine, and you don't need to integrate any of the 3DS versions.

PSD2 exemptions

There're several exemptions from PSD2. In the following cases transactions may require SCA depending on the issuers' decision and acquirer fraud rates:

  • Low value - transactions under EUR 30 (although there are limits to the number of such transactions per day and their total value)
  • Low risk (Transaction Risk Analysis) - low risk transactions based on the average fraud levels of the card issuer. There are two options for this exemption:
    • TRA exemption request from the merchant or the payment provider to the issuer based on low fraud levels. In this case liability stays with the merchant
    • TRA exemption from the card issuer. In this case liability shifts to the issuer.
  • Whitelisted Merchants or Trusted Beneficiaries (depending on whether the issuer supports whitelisting)

These transactions don't require SCA:

  • Merchant-initiated transactions (MIT), including recurring transactions (although initial transaction must use SCA)
  • Interregional transactions ("one leg out" transactions; here the location of the customer and the merchant is irrelevant)
  • Mail Order and Telephone Orders (MOTO)
  • Secure corporate payments
Currently, we only support exemptions for Merchant-initiated transactions (recurring transactions), interregional and Mail Order and Telephone Order transactions.
We don't support low value exemptions.

How do I get an exemption for a MIT transaction

To get an exemption for a recurring transaction you need to use the recurring flow with optile. For your initial transaction, use WEB_ORDER with "allowRecurrence": true and for the following ones transactions channel=RECURRING with the parameters:"registration": {"id": customerregistrationid,"password": password}

For details, see the example on the right. 

Don't use the RECURRING channel if the customer is present. Use the WEB_ORDER channel instead.

 

Note that the first recurring transaction will require SCA.

How do I get an exemption for MOTO transactions

To trigger MOTO transaction with OPG, use one of the following values for the channel parameter in the LIST request:

  • CALLCENTER_ORDER
  • MAIL_ORDER
Exemptions and liability

Applied exemption

Issuer

Liability

No exemption

Does not support 3DS

Issuer

Low Value transactions

Checks if number of transactions < or =5 and accepts exemption

Acquirer

No exemption

Applies low value exemption

Issuer

Low Risk transactions

Accepts exemption

Acquirer

No exemption

Applies low risk exemption

Issuer

No exemption

Performs transaction risk analysis / requests challenge (if proceeding number of low-value transactions =5)

Issuer

MIT first or card-on-file

Requests challenge

Issuer

 

Outside the EU/EEA

If your acquirer and the issuer are based outside the PSD2 zone, you don't need to comply with the PSD2 directive.

The UK is planning to adopt PSD2 on September 14, 2021.

 

Example of the MIT LIST request

{
 "transactionId": "optile_test2",
 "country": "ES",
 "channel": "RECURRING",
 "division": "Default",
 "customer": {
  "number": "136440382",
 "email": "bob.lynch@gmail.com",
 "birthday": 1535528731146,
  "name": {
      "firstName": "Joe",
      "lastName": "Blow"
  },
  "registration": {
      "id": "5fc8fd078270c916be080d68u",
      "password": "2EODNSNUQe6Wu1dq"
      }

  },
  "payment": {
      "amount": 1.03,
      "currency": "EUR",
      "reference": "430003"

  },
  "callback": {
      "returnUrl": "https://dev.oscato.com/shop/success.html",
      "summaryUrl": "https://dev.oscato.com/shop/summary.html",
      "cancelUrl": "https://dev.oscato.com/shop/cancel.html",
      "notificationUrl": "https://dev.oscato.com/c05dton"
  }
 }

Web Content Display

PSD 2 timeline in Europe

Mastercard is planning to decommission 3DS1 in October 2022, while VISA in Europe will remove liability shift starting October 2021. However, each country has their own deadlines for PSD2 migration.

Find out more about PSD 2 deadlines in the selected European countries:

UK UK is planning a progressive ramp-up with soft declines from June 1, 2021 until the SCA deadline on September 14.
Germany

BaFin has recommended to issuers to follow a rump-up plan between mid-January 2021 and mid-March 2021 introducing soft declines as per the instructions below:

  • From January 15 transactions above 250 EUR
  • From February 15 transactions above 150 EUR
  • From March 15 for all non authenticated transactions
France

Soft declines are officially applied since October 1, 2020 and progressively ramping up until March 31, 2021. The latest communicated transition plan follows the soft-decline timeline below:

  • From October until December 2020 above 2000 EUR
  • From January 2021 above 1000 EUR
  • From mid-February 2021 above 500 EUR
  • From April 2021 progressive extension to transactions below 500 EUR

Travel and hospitality MCCs are exempted until March 31, 2021.

Italy

The transition phase for the introduction of SCA in 2021 looks as per below:

  • From January 1 all in-scope non-authenticated transactions above 1000 euros will be soft-declined
  • From February 1 all in-scope non-authenticated transactions above 500 euros will be soft-declined
  • From March 1 all in-scope non-authenticated transactions above 100 euros will be soft-declined
  • From April 1 the SCA requirements are enforced for all in-scope transactions
Spain

The migration plan target is December 31, 2020. 

Belgium

The soft-decline plan is as follows:

  • From January 18 above 500 euros
  • From February 23 above 100 euros
  • From March 23, 2021 soft-decline for all non authenticated transactions
Denmark

The Danish FSA expects that strong customer authentication will be used for all payments by January 11, 2021 at the latest.

Netherlands

Soft declines have been gradually introduced starting October 2020, and The Dutch National Bank has confirmed the December 31, 2020 as the migration deadline.

Web Content Display

Requirements for 3DS 2 compliance

In order to upgrade to 3DS 2, you need to provide the issuer with more data so that transaction risk can be assessed. To complete the upgrade process, you'll need to do the following:

Step 1. Add the required parameters

Step 2. Integrate a redirect

Step 3. Activate 3DS 2 in your merchant portal

Step 4. Test the transaction flow on sandbox before rolling out to production.

Step 5. Activate 3DS 2 in your merchant portal for the production environment.


Step 1

Add the required parameters to the LIST and CHARGE requests in the Orchestration Platform's API

If you use the pure native integration, you need to provide all the required parameters yourself. If you use our payment page (hosted integration or integration using Ajax library), some parameters will be provided automatically for you.

To ensure frictionless flow, it's a good idea to provide the optional parameters, too. See the optional parameters section for details. 

Required parameters per provider

You need to provide all the listed parameters. 

If you use our payment page, you're good to go, as the parameters marked with Y(es) will be provided for you, and you only need to manually provide the N(o) parameters.

Only the payment page v3 provided the parameters for you. If you're using v2, you either need to upgrade or provide all the paramaters manually. 
Kalixa

Parameter

Provided by Orchestration Platform

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

clientInfo.language 

Y

clientInfo.timezone

Y

clientInfo.acceptHeader

N

GlobalCollect

Parameter

Provided by Orchestration Platform

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

clientInfo.javaEnabled

Y

clientInfo.language

Y

clientInfo.timezone

Y

colorDepth

Y

clientInfo.acceptHeader

N

style.challengeWindowSize

N
Worldpay

No new required parameters.

 

Wirecard

No new required parameters.

CyberSource

No new required parameteres.

 

Dallenys-B2Bill


No new required parameters.

Secure Trading
Use the Netcetera parameters
PayBox

Parameter

Provided by Orchestration Platform

products[].quantity

(called totalQuantity)

N
Verfione-Omni
No new parameters required.
Ogone

Parameter

Provided by Orchestration Platform

clientInfo.acceptHeader

N

callback.returnUrl

N

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

clientInfo.ip

Y

clientInfo.javaEnabled

Y

clientInfo.language

Y

clientInfo.timezone

Y

clientInfo.userAgent

Y

colorDepth

Y

style.challengeWindowSize

N
Payvision

Parameter

Provided by Orchestration Platform

riskData.payment.recurring.expireDate

N

riskData.payment.recurring.frequency

N
Concardis

Parameter

Provided by Orchestration Platform

riskData.payment.recurring.expireDate

only for recurring (orderOpenPaymentRequest.cofContract.ExpiryRecurring)

N

riskData.payment.recurring.Frequency

only for recurring; enter integer between 1 and 9999. (orderOpenPaymentRequest.cofContract.recurringFrequency)

N

clientInfo.javaEnabled

only if BrowserData is mapped (BrowserData.javaEnabled)

Y

clientInfo.language

only if BrowserData is mapped (BrowserData.language)

Y

clientInfo.timezone

only if BrowserData is mapped (BrowserData.timezone)

Y

colorDepth

only if BrowserData is mapped (BrowserData.colorDepth)

Y

clientInfo.acceptHeader

only if BrowserData is mapped (BrowserData.acceptHeader)

N

style.challengeWindowSize

only if BrowserData is mapped (BrowserData.windowSize)

N

clientInfo.userAgent

only if BrowserData is mapped (BrowserData.userAgent)

Y

clientInfo.ip

only if BrowserData is mapped (BrowserData.ip)

Y

clientInfo.browserScreenWidth

only if BrowserData is mapped (BrowserData.screenWidth)

Y

clientInfo.browserScreenHeight

only if BrowserData is mapped (BrowserData.screenHeight)

Y
eMerchantPay

Parameter

Provided by Orchestration Platform

clientInfo.acceptHeader

Required for native integration; optional for hosted.

N
products[].quantity N
Netcetera

Parameter

Provided by Orchestration Platform

clientInfo.acceptHeader

N

callback.returnUrl

N

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

clientInfo.ip

Y

clientInfo.javaEnabled

Y

clientInfo.language

Y

clientInfo.timezone

Y

clientInfo.userAgent

Y

colorDepth

Y

customer.addresses.billing.city

N

customer.addresses.billing.country

N

customer.addresses.billing.houseNumber

N

customer.addresses.billing.street

N

customer.addresses.billing.zip

N

style.challengeWindowSize

N

customer.addresses.shipping.city

Parameters required only if useBillingAsShippingAddress is false

N

customer.addresses.shipping.country

Parameters required only if useBillingAsShippingAddress is false

N

customer.addresses.shipping.street

Parameters required only if useBillingAsShippingAddress is false

N

customer.addresses.shipping.zip

Parameters required only if useBillingAsShippingAddress is false

N

Adyen

Parameter

Provided by Orchestration Platform

clientInfo.javaEnabled

Y

clientInfo.language

Y

clientInfo.timezone

Y

colorDepth

Y
clientInfo.browserScreenHeight Y
clientInfo.browserScreenWidth Y
clientInfo.ip Y
clientInfo.userAgent Y
clientInfo.acceptHeader N
callback.returnURL N
customer.addresses.shipping.city N
customer.addresses.shipping.country N
customer.addresses.shipping.houseNumber N
customer.addresses.shipping.street N
customer.addresses.shipping.zip N

customer.addresses.billing.city

N

customer.addresses.billing.country

N

customer.addresses.billing.houseNumber

N

customer.addresses.billing.street

N

customer.addresses.billing.zip

N

style.challengeWindowSize

N

Telecash

Parameter

Provided by Orchestration Platform

callback.returnURL N

Stripe-PI

Parameter

Provided by Orchestration Platform

channel

This parameter is required for recurring transactions. Set the recurring channel to off_session = true

N

Saferpay

Parameter

Provided by Orchestration Platform

callback.returnURL N
callback.notificationURL N

 

For the detailed description of the parameters, see API reference

Step 2

Integrate the redirect

In 3DS 2 the identity of the end user (a customer) may need to be verified using a passive, biometric, or two-factor authentication approach. The CHARGE response should provide a PSP-generated URL that enables the shopper to complete the required authentication.

You need to pass the redirect object to the frontend and handle the result. When the authentication is performed, the customer will again be redirected to one of your callback URLs from the LIST session.

The response JSON might differ between providers. Make sure you parse it correctly before passing the parameters to the handler in URL.


Tell me more about integrating the redirect

If you use our native integration, you can use the information to learn how to implement the redirect.

If you use our payment page, you don't need to do anything.

 

Specifics of the handler page

If DDC is required for a transaction, then the Orchestration Platform's adapter initiates a corresponding handler page. The handler page receives the 3DS2 redirect from the provider as input. The provider 3DS2 page is passed inside the parameters object in the redirect value. 

The URL to the redirect page and the parameters are passed via the GET call to the handler page and the handler page then redirects the browser to the issuer's challenge page.

 

Prepare your redirect URL

 

If you use a URL encoding library like JavaScript (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent), you can skip directly to step 3. 

 

The URL parameters must be passed as strings. Follow these steps to get the correct redirect URL:

  1. Remove the backslash characters from the JSON parameters redirect.

For example, convert the original response:

"{\"url\":\"

to this:

"{"url":"

2. Encode the cleaned up JSON into a URL. This means all special characters must be percent-encoded.

For example, convert this:

		"{"url":
                   "https://secure-test.worldpay.com/shopper/3ds/ddc.html",
                       "method":"POST",
                       "parameters":
                       [{
                       "name":"Bin","value":"555555"},
                       {"name":"JWT",
                        "value":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJhNTY5NzFiYS1mYjViLTRmYWMtYmY4Mi0zZThlNWRmMzUxMWYiLCJpYXQiOjE2MDc1NTA0MTQsImlzcyI6IjViZDllMGU0NDQ0ZGNlMTUzNDI4Yzk0MCIsIk9yZ1VuaXRJZCI6IjViZDliNTVlNDQ0NDc2MWFjMGFmMWM4MCJ9.ES5ONlEZs3f8Ce_lQUKiwLvxDvuD-x_3_xUkCurFrvU"
                        },
                       {"name":"ContinueUrl",
                        "value":"https%3A%2F%2Fapi.sandbox.oscato.com%2Fdecision%2FWORLDPAY%2FLOTTOLAND%2Fdo.html%3Ftype%3Daccept%26wpProcess%3D5fd145ce8270c91ca105e758c%26wpRedirectType%3Dpending%26source%3Dddc"
                         }],
                        "source":"PSP","type":"PROVIDER"}"

into:

%22%7B%22url%22%3A%22https%3A%2F%2Fsecure-test.worldpay.com%2Fshopper%2F3ds%2Fddc.html
%22%2C%22method%22%3A%22POST
%22%2C%22parameters%22%3A%5B%7B%22name%22%3A%22Bin
%22%2C%22value%22%3A%22555555%22%7D%2C%7B%22name%22%3A%22JWT
%22%2C%22value%22%3A%22eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJhNTY5NzFiYS1mYjViLTRmYWMtYmY4Mi0zZThlNWRmMzUxMWYiLCJpYXQiOjE2MDc1NTA0MTQsImlzcyI6IjViZDllMGU0NDQ0ZGNlMTUzNDI4Yzk0MCIsIk9yZ1VuaXRJZCI6IjViZDliNTVlNDQ0NDc2MWFjMGFmMWM4MCJ9.ES5ONlEZs3f8Ce_lQUKiwLvxDvuD-x_3_xUkCurFrvU
%22%7D%2C%7B%22name%22%3A%22ContinueUrl%22%2C%22value%22%3A%22https%253A%252F%252Fapi.sandbox.oscato.com%252Fdecision%252FWORLDPAY%252FLOTTOLAND%252Fdo.html
%253Ftype%253Daccept%2526wpProcess%253D5fd145ce8270c91ca105e758c%2526wpRedirectType%253Dpending
%2526source%253Dddc%22%7D%5D%2C%22source%22%3A%22PSP
%22%2C%22type%22%3A%22PROVIDER%22%7D%22 

 

3. Append these parameters into the main url and pass a GET request to the handler page:
For example:

 

https://resources.sandbox.oscato.com/3ds2/handler/testpsp?
redirect=%22%7B%22url%22%3A%22https%3A%2F%2Fsecure-test.worldpay.com%2Fshopper%2F3ds%2Fddc.html
%22%2C%22method%22%3A%22POST%22%2C%22parameters%22%3A%5B%7B%22name%22%3A%22Bin
%22%2C%22value%22%3A%22555555%22%7D%2C%7B%22
name%22%3A%22JWT%22%2C%22value%22%3A%22eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJhNTY5NzFiYS1mYjViLTRmYWMtYmY4Mi0zZThlNWRmMzUxMWYiLCJpYXQiOjE2MDc1NTA0MTQsImlzcyI6IjViZDllMGU0NDQ0ZGNlMTUzNDI4Yzk0MCIsIk9yZ1VuaXRJZCI6IjViZDliNTVlNDQ0NDc2MWFjMGFmMWM4MCJ9.ES5ONlEZs3f8Ce_lQUKiwLvxDvuD-x_3_xUkCurFrvU
%22%7D%2C%7B%22name%22%3A%22ContinueUrl%22%2C%22value%22%3A%22https%253A%252F%252Fapi.sandbox.oscato.com%252Fdecision%252FWORLDPAY%252FLOTTOLAND%252Fdo.html%253Ftype%253Daccept%2526wpProcess%253D5fd145ce8270c91ca105e758c%2526wpRedirectType%253Dpending%2526source%253Dddc
%22%7D%5D%2C%22source%22%3A%22PSP%22%2C%22type%22%3A%22PROVIDER%22%7D%22&language=en_EN

 

This will bring the handler page with the provider's 3DS2 redirect in it. The handler page redirects the browser to the issuer's challenge page fort he customer to enter the challenge information.

The issuer's challenge page then redirects the customer to our decision endpoint, which, in turn, redirects the customer to your success page or the failure page.



CHARGE response example with rediect to success page (no challenge)
{
  "resultInfo": "Operation successful.",
  "interaction": {
    "code": "PROCEED",
    "reason": "OK"
  },
  "redirect": {
    "url": "https://dev.oscato.com/shop/success.html",
    "method": "GET",
    "parameters": [
      {
        "name": "shortId",
        "value": "11926-61834"
      },
      {
        "name": "interactionReason",
        "value": "OK"
      },
      {
        "name": "resultCode",
        "value": "00000.PAYBOX.00000"
      },
      {
        "name": "longId",
        "value": "5fd0af7bc4ffdf5b3caa7212c"
      },
      {
        "name": "transactionId",
        "value": "AL_1607511931226"
      },
      {
        "name": "interactionCode",
        "value": "PROCEED"
      },
      {
        "name": "amount",
        "value": "19.99"
      },
      {
        "name": "reference",
        "value": "Shop 101/20-03-2016"
      },
      {
        "name": "currency",
        "value": "EUR"
      }
    ],
    "type": "RETURN"
  },
  "links": {
    "redirect": "https://api.sandbox.oscato.com/redirect/5fd0af7b41f95e7ed2c8cd75lsqmo3aebrmeqbmd87fgs0ph08/5fd0af7bc4ffdf5b3caa7212c"
  }
}
CHARGE response with challenge

{
  "resultInfo": "Pending, you have to check the status later",
  "interaction": {
    "code": "PROCEED",
    "reason": "PENDING"
  },
  "redirect": {
    "url": "https://3ds-test.wirecard.com/acs?reqid=A4DFFD8EA86C108709B02D9B23AC263CEEA60C8C",
    "method": "POST",
    "parameters": [
      {
        "name": "PaReq",
        "value": "eJxtkEFLAzEQhf/Lnt3tJDubTXptEQoKYqteepnNzLYL3UaTqIj43w30UBCv37w37/G+qwNleaGvXaRz2qyrZbWyDgGNMtB34LAzfd+Dqm6qOR2eJaYpnItKNVBQlLd3SXk3zbI5T3miUzlp0KA0OAUalS2qfIwi6+1W4ofEa9DILY3eSW099jWOoGqHw1CzAKOQc+KxuB9iyMGH0zVbN5d08unp8a6AY86vablf7BctpzqXRs3nFMVT5MaHeb8oymuPe8nHwBfnX7qmTAU7HkSzsYgsMo7AjEOnUMB2rRIP2rXInvE/+22Ic3nRGmoZoBN0KAaGgYDQ2DKKBfJaVz+/TP9zFQ=="
      },
      {
        "name": "TermUrl",
        "value": "https://api.sandbox.oscato.com/decision/WIRECARD/DEMO_AL/do.html?type=accept&requestId=5fd0a5d01dab521d2296f2b9c"
      },
      {
        "name": "MD",
        "value": ""
      }
    ],
    "suppressIFrame": true,
    "type": "PROVIDER"
  },
  "links": {
    "redirect": "https://api.sandbox.oscato.com/redirect/5fd0a5d041f95e7ed2c8caf8lt1s6p38i44co3b8jvub7uif1c/5fd0a5d0c4ffdf5b3caa6fc6c"
  }
}


The redirect is a standard browser redirect to a new page. It's not different from a standard redirect used in the Orchestration Platform to redirect to the payment page or a success page.

If you're using the Orchestration Platform pure native integration, the specifics of your redirect integration will depend on the frontend. Refer to https://www.optile.io/reference#operation/payWithPaymentNetwork for the detailed description of the redirect object.

 

Step 3

Activate 3DS 2 in your merchant portal

When you're tests have succeeded and you're ready to start using 3DS 2, you need to activate it in the merchant portal.

  1. Go to your merchant portal.

  2. Open Provider Contracts.

  3. Select an existing contract with a provider or create a new contract.

  4. For the 3DS2_SUPPORTED option select True.

Some providers might also require additional data provided on the contract page.


Step 4

Test in sandbox before rolling out to production.

Use your PSP test accounts to test the integration. For example:

  • Netcetera: contact support for information on how to test

 

Some PSPs offer a fallback to 3DS 1 when 3DS 2 fails. 


Step 5

Go live

Repeat step 3 for the production environment and try the integration in production.

 

Example of a CHARGE request response:

"redirect":
{ "url": "https://resources.sandbox.oscato.com/3ds2/handler/worldpay",
  "method": "GET",
  "parameters": [
  {
   "name": "redirect",
    "value": "{\"url\":\"https://secure-test.worldpay.com/shopper/3ds/ddc.html\",
   \"method\":\"POST\",\"parameters\":[{\"name\":\"Bin\",\"value\":\"555555\"
    },
   {
    \"name\":\"JWT\",
    \"value\":
    \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJhNTY5NzFiYS1mYjViLTRmYWMtYmY4Mi0zZThlNWRmMzUxMWYiLCJpYXQiOjE2MDc1NTA0MTQsImlzcyI6IjViZDllMGU0NDQ0ZGNlMTUzNDI4Yzk0MCIsIk9yZ1VuaXRJZCI6IjViZDliNTVlNDQ0NDc2MWFjMGFmMWM4MCJ9.ES5ONlEZs3f8Ce_lQUKiwLvxDvuD-x_3_xUkCurFrvU\"
    },
   {
   \"name\":\"ContinueUrl\",\"value\":\"https%3A%2F%2Fapi.sandbox.oscato.com%2Fdecision%2FWORLDPAY%2FLOTTOLAND%2Fdo.html%3Ftype%3Daccept%26wpProcess%3D5fd145ce8270c91ca105e758c%26wpRedirectType%3Dpending%26source%3Dddc\"}],
    \"source\":\"PSP\",\"type\":\"PROVIDER\"
     }"
    },
    {
    "name": "language", "value": "en_EN"
      }
      ],
    "type": "3DS2-HANDLER"
     }

You can form the URL with this algorithm:

var redirectUrl = response.redirect.url;
foreach (param in response.redirect.parameters) {
  if (redirectUrl.contains("?")) {
    redirectUrl += "&";
  } else {
    redirectUrl += "?";
  }  /// THE ONLY CORRECT WAY
  redirectUrl += urlencode(param.name) +
  "=" + urlencode(param.value)
}

Web Content Display

Transaction and user flow

3DS 2 doesn't change the user flow for transactions. From the customer's perspective, the only thing that is different is the spinner that shows during the device data collection phase (after the CHARGE response has been generated). This is when the transaction data is being verified and the decision is made whether or not a challenge should be presented.

From the technical perspective, the flow is the same for all integration types.

  1. A merchant sends the LIST request with the required parameters.

  2. The Orchestration Platform's payment page, or merchant's frontend, or merchant's backend sends the CHARGE request.

  3. The payment provider communicates to the Orchestration Platform what should happen next:

    1. Device data collection (DDC -collection of information about a remote device for the purpose of identification)

    2. 3DS challenge

    3. transaction completion (success/failure)

  4. After DDC results have been submitted, the payment provider communicates next steps to the Orchestration Platform (challenge/no challenge). The customer is redirected either to "Thank you" page, provided by merchant, or to 3DS challenge page. After completion of the challenge, the customer is redirected to the merchant's success or failure page.

See the flow diagrams

Notifications

For 3DS 2 we use standard Orchestration Platform notifications. For details, see Interaction codes.

Currently, we don't detect whether a transaction might have been declined because of 3DS and whether or not the challenge was requested. 

Web Content Display

Best practises for frictionless flow

Mastercard advises the following fields to be correctly populated for frictionless authentication and higher chances of approval :

  •  device info
  •  browser IP
  •  PAN or Token number
  •  cardholder name
  •  cardholder mobile number
  •  billing address

We advise you not to leave these fields blank or fill them with static information. If a field is optional, leave it blank and don't populate it with a space. Additionally, make sure the Merchant Category Code (MCC) is correctly filled in and reflects your business.

Web Content Display

3DS 2 optional parameters

To ensure a frictionales flow, it's a good idea to provide optional parameters as well as the required ones.It also speeds up the process of adding a new provider because most likely they'll need the same set of parameters to be passed.

You need to provide all the listed parameters. 

If you use our payment page, you're good to go, as the parameters marked with Y(es) will be provided for you, and you only need to manually provide the N(o) parameters.


Kalixa

Parameter

 

Provided by Orchestration Platform

 

 

customer.deliveryEmail

Y if not provided, customer.email will be used

clientInfo.javaEnabled

Y

colorDepth

Y

style.challengeWindowSize

N

preselection.challengeIndicator

N


GlobalCollectNo optional parameters

Worldpay

Parameter

 

Provided by Orchestration Platform

 

customer.deliveryEmail

Y if not provided, customer.email will be used

customer.accountInfo.method

N

customer.accountInfo.timestamp

N

riskData.customer.paymentAttemptsLastDay

N

riskData.customer.paymentAttemptsLastYear

N

riskData.customer.cardRegistrationAttemptsLastDay

N

riskData.customer.purchasesLastSixMonths

N

riskData.customer.suspiciousActivity

N

riskData.shipping.type

N

riskData.payment.reorderItems

N

riskData.gift.amount

N

riskData.gift.currency

N

riskData.gift.cardCount

N

style.challengeWindowSize

N

preselection.challengeIndicator

N

riskData.customer.account.registrationDate

Y (for registered customers)

shippingNameMatchesAccountName

optile will calculate the parameter from other data points. This parameter doesn't require any actions from merchants.


Wirecard

Parameter

 

Provided by Orchestration Platform

 

customer.deliveryEmail

Y if not provided, customer.email will be used

customer.accountInfo.creationDate

N

customer.accountInfo.updateDate

N

customer.accountInfo.passwordChangeDate

N

riskData.customer.purchasesLastSixMonths

N

riskData.customer.suspiciousActivity

N

riskData.gift.amount

N

riskData.gift.currency

N

riskData.gift.cardCount

N

clientInfo.javaEnabled

Y

clientInfo.language

Y

colorDepth

Y

clientInfo.timezone

Y

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

style.challengeWindowSize

N

preselection.challengeIndicator

N


CyberSource

Parameter

 

Provided by Orchestration Platform

 

riskData.customer.paymentAttemptsLastDay

N

riskData.customer.purchasesLastSixMonths

N

riskData.payment.reorderItems

N

riskData.payment.recurring.expireDate

N

riskData.payment.recurring.frequency

N

clientInfo.javaEnabled

Y

clientInfo.language

Y

colorDepth

Y

clientInfo.timezone

Y

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

style.challengeWindowSize

N

preselection.challengeIndicator

N


Dalenys-B2Bill

Parameter

 

Provided by Orchestration Platform

 
customer.deliveryEmail Y

customer.accountInfo.method

N

customer.accountInfo.creationDate

N

customer.accountInfo.updateDate

N

customer.accountInfo.passwordChangeDate

N

addresses.shippting.firstTimeUseDate

N

riskData.customer.paymentAttemptsLastDay

N

riskData.customer.paymentAttemptsLastYear

N

riskData.customer.cardRegistrationAttemptsLastDay

N

riskData.customer.purchasesLastSixMonths

N

riskData.customer.suspiciousActivity

N

riskData.shipping.itemsAvailable

N

riskData.payment.reorderItems

N

riskData.payment.recurring.expireDate

N

riskData.payment.recurring.frequency

N

riskData.gift.amount

N

riskData.gift.currency

N

riskData.gift.cardCount

N

style.challengeWindowSize

N

preselection.challengeIndicator

N

riskData.customer.account.registrationDate

Y (for registered customers)

channel

N

customer.phones.home

N

products[].quantity

N


Secure Trading

Parameter

 

Provided by Orchestration Platform

 

customer.accountInfo.method

N

PayBoxNo optional parameters.

Verifione-Omni

Parameter

 

Provided by Orchestration Platform

 

customer.deliveryEmail

Y if not provided, customer.email will be used

customer.accountInfo.method

N (alternate_authentication_method)

customer.accountInfo.timestamp

N (alternate_authentication_date)

customer.accountInfo.creationDate

N (account_create_date)

customer.accountInfo.passwordChangeDate

N (account_pwd_change_date)

addresses.shippting.firstTimeUseDate

N (shipping_address_usage_date)

Address[billing].firstTimeUseDate will be used in case customer.addresses.useBillingAsShippingAddress flag is true. Otherwise Address[Shipping].firstTimeUseDate will be used.

riskData.customer.paymentAttemptsLastDay

N (transaction_count_day)

riskData.customer.paymentAttemptsLastYear

N (transaction_count_year)

riskData.customer.cardRegistrationAttemptsLastDay

N ( add_card_attempts)

riskData.customer.purchasesLastSixMonths

N (account_purchases)

riskData.customer.suspiciousActivity

N (fraud_activity)

riskData.shipping.type

N (delivery_time_frame)

riskData.shipping.itemsAvailable

N (pre_order_indicator)

riskData.payment.reorderItems

N (reorder_indicator)

riskData.payment.recurring.expireDate

N (recurring_end)

riskData.payment.recurring.frequency

N (recurring_frequency)

riskData.gift.amount

N (gift_card_amount)

riskData.gift.currency

N (gift_card_currency_code)

riskData.gift.cardCount

N (gift_card_count)

clientInfo.javaEnabled

Y (browser_java_enabled)

clientInfo.language

Y

colorDepth

Y (browser_color_dept)

clientInfo.timezone

Y (browser_time_zone)

clientInfo.browserScreenHeight

Y (browser_screen_height)

clientInfo.browserScreenWidth

Y (browser_screen_width)

style.challengeWindowSize

N (acs_window_size)

preselection.challengeIndicator

N (challenge_required)

riskData.customer.account.registrationDate

N (for registered customers) (account_create_date)

channel

N (shopper_interaction)


Ogone

Parameter

 

Provided by Orchestration Platform

 

customer.deliveryEmail

Y if not provided, customer.email will be used

customer.accountInfo.method

N

customer.accountInfo.timestamp

N

customer.accountInfo.creationDate

N

customer.accountInfo.updateDate

N

customer.accountInfo.passwordChangeDate

N

riskData.customer.paymentAttemptsLastDay

N

riskData.customer.paymentAttemptsLastYear

N

riskData.customer.purchasesLastSixMonths

N

riskData.customer.suspiciousActivity

N

riskData.shipping.itemsAvailable

N

riskData.payment.reorderItems

N

riskData.payment.recurring.expireDate

N

riskData.payment.recurring.frequency

N

riskData.gift.amount

N

riskData.gift.currency

N

riskData.gift.cardCount

N

riskData.customer.account.registrationDate

Y (for registered customers)

channel

N

customer.phones.home

N

customer.phones.mobile

N

customer.number

N


Payvision

Parameter

 

Provided by Orchestration Platform

 

customer.deliveryEmail

Y if not provided, customer.email will be used

customer.accountInfo.method

N

customer.accountInfo.timestamp

N

customer.accountInfo.creationDate

N

customer.accountInfo.passwordChangeDate

N

addresses.shippting.firstTimeUseDate

N

riskData.customer.paymentAttemptsLastDay

N

riskData.customer.paymentAttemptsLastYear

N

riskData.customer.cardRegistrationAttemptsLastDay

N

riskData.customer.purchasesLastSixMonths

N

riskData.customer.suspiciousActivity

N

riskData.shipping.type

N

riskData.shipping.itemsAvailable

N

riskData.payment.reorderItems

N

riskData.gift.amount

N

riskData.gift.currency

N

riskData.gift.cardCount

N

riskData.customer.account.registrationDate

Y (for registered customers)

customer.phones.mobile

N

customer.number

N


Concardis

Parameter

 

Provided by Orchestration Platform

 

customer.accountInfo.method

N

customer.accountInfo.timestamp

N

customer.accountInfo.creationDate

N

customer.accountInfo.updateDate

N

customer.accountInfo.passwordChangeDate

N

riskData.customer.paymentAttemptsLastDay

N

riskData.customer.paymentAttemptsLastYear

N

riskData.customer.purchasesLastSixMonths

N

riskData.customer.suspiciousActivity

N

riskData.shipping.type

N

riskData.shipping.itemsAvailable

N

riskData.payment.reorderItems

N

riskData.payment.recurring.expireDate

N

riskData.payment.recurring.frequency

N

clientInfo.javaEnabled

Y

clientInfo.language

Y

colorDepth

Y

clientInfo.timezone

Y

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

clientInfo.ip

Y

clientInfo.userAgent

Y

style.challengeWindowSize

N

clientInfo.acceptHeader

N

customer.number

N

Shipping name matches account name indicator

optile will calculate the parameter from other data points. This parameter doesn't require any actions from merchants.


eMerchantPay

Parameter

 

Provided by Orchestration Platform

 

clientInfo.javaEnabled

Y

clientInfo.language

Y

colorDepth

Y

clientInfo.timezone

Y

clientInfo.browserScreenHeight

Y

clientInfo.browserScreenWidth

Y

clientInfo.ip

Y

clientInfo.userAgent

Y

style.challengeWindowSize

N

clientInfo.acceptHeader

N (to be provided for native integration only)

callback.notificationUrl

N


Netcetera

Parameter

 

Provided by Orchestration Platform

 

customer.deliveryEmail

Y if not provided, customer.email will be used

customer.accountInfo.method

N

customer.accountInfo.timestamp

N

customer.accountInfo.creationDate

N

customer.accountInfo.updateDate

N

customer.accountInfo.passwordChangeDate

N

addresses.shippting.firstTimeUseDate

N

riskData.customer.paymentAttemptsLastDay

N

riskData.customer.paymentAttemptsLastYear

N

riskData.customer.cardRegistrationAttemptsLastDay

N

riskData.customer.purchasesLastSixMonths

N

riskData.customer.suspiciousActivity

N

riskData.shipping.type

N

riskData.shipping.itemsAvailable

N

riskData.payment.reorderItems

N

riskData.payment.recurring.expireDate

N

riskData.payment.recurring.frequency

N

riskData.gift.amount

N

riskData.gift.currency

N

riskData.gift.cardCount

N

preselection.challengeIndicator

N

riskData.customer.account.registrationDate

Y (for registered customers)

customer.phones.home

N

customer.phones.mobile

N

customer.addresses.shipping.state

N

customer.addresses.shipping.name

N

customer.addresses.shipping.verified

N

customer.addresses.shipping.firstTimeUseDate

N


Adyen

Parameter

 

Provided by Orchestration Platform

 

customer.addresses.shipping.state

N


Telecash

Parameter

 

Provided by Orchestration Platform

 

style.challengeWindowSize

N

preselection.challengeIndicator N

Stripe-PI

Parameter

 

Provided by Orchestration Platform

 

callback.returnURL

N

customer.addresses.shipping.street N
customer.addresses.shipping.houseNumber N
customer.addresses.shipping.zip N
customer.addresses.shipping.city N
customer.addresses.shipping.state N
customer.addresses.shipping.country N
customer.addresses.billing.street N
customer.addresses.billing.houseNumber N
customer.addresses.billing.zip N
customer.addresses.billing.city N
customer.addresses.billing.state N
customer.addresses.billing.country N

Saferpay

Parameter

 

Provided by Orchestration Platform

 
customer.deliveryEmail Y
customer.accountInfo.timestamp N
customer.accountInfo.creationDate N
customer.accountInfo.passwordChangeDate N
riskData.shipping.type N
clientInfo.language Y
clientInfo.ip Y

preselection.challengeIndicator

(configure using ThreeDsChallenge parameter)
N

customer.phones.home

N
products[].quantity N
customer.phones.mobile N
customer.number N
customer.addresses.shipping.street N
customer.addresses.shipping.zip N
customer.addresses.shipping.city N
customer.addresses.shipping.country N
customer.addresses.shipping.name N
customer.addresses.shipping.companyName N
customer.addresses.billing.street N
customer.addresses.billing.zip N
customer.addresses.billing.city N
customer.addresses.billing.country N
customer.addresses.billing.name N
customer.addresses.billing.companyName N

 

For the detrailed description of the parameters, see API parameters.

Web Content Display

Soft declines

A Soft decline happens when an issuing bank confirms the card used exists but for some reason can't accept the transaction. The reason might be (but is not limited to) that Strong customer authentication (SCA) is required (compliance reasons).

Transactions can also be soft declined on the PSP/Acquirer side.

Soft decline means that this transaction could be accepted, if the issue, which caused a soft decline, was removed.

Soft decline code

Transactions are usually soft declined by the issuing bank with a variety of codes that depend on the scheme used. OPG tags these transactions with its own soft decline code of
45065, CUSTOMER_AUTHENTICATION_REQUIRED. By providing this code, the issuing bank indicates that this transaction could be accepted if it's repeated with Strong Customer Authentication.

Orchestration platform and soft declines

When a PSP sends us a soft decline ( "Authentication required" ) response code, we do retry with SCA on customer present transactions, if challenge flow was not initiated during this transaction.

We also generate the RETRY/STRONG_AUTHENTICATION interaction code for the merchant to know that SCA is required and automatically initiate the retry mechanism. The re-try information is logged in data.retryInfo and can be accessed in the Technical Monitor.

To make sure transactions passing smoothly, it's a good idea to include challengeIndicator = CHALLENGE_REQUESTED_MANDATE in the LIST request for transactions when the same cardholder is trying to pay again after after a soft decline response code has been received.

Recurring transactions

Customers are not present during recurring transactions, so you need to ensure that upon receiving the CUSTOMER_AUTHENTICATION_REQUIRED soft decline code for the RECURRING channel you trigger a new payment sequence through the WEB_ORDER or MOBILE_ORDER channel. You could do it, for example, by providing a new payment link to customer via email.

Soft decline timelines

For details on the deadlines per country, see https://www.optile.io/opg#21108832. Note that the dates might still change.

Web Content Display

3DS2 lightbox in payment page

In most 3DS2 scenarios, the CHARGE request returns a response with interaction.code PROCEED and redirect.type = 3DS2-HANDLER. In this case, the widget will render the 3DS2 challenge in a lightbox, instead of a full page redirect. That gives a better user experience as the challenge feels like it is occurring within the merchant's shop instead of a completely different site. This also allows the widget to call merchant custom functions for initiating redirect following the 3DS2 process.

 

What do I need to do to start using the lightbox?

If you're already using our payment page widget (selective native or display native implementation), upgrade to version 3.18.0 or later and the full page redirect will automaticlly change to lightbox. 

If you implement the orchestration platform natively, read on to get the technical details that will help you integrate the lightbox. 

If you use single-page application and haven't used our widget yet, read on to underdstand the technical details of how the lightbox work. 

If you use hosted implementation, consider switching to selective or display native implementation to have the lightbox available. 

---------------------------

Prerequisites:

  • the widget is NOT in the HOSTED integration mode
  • the payment page is in version 3

What's the flow?

How does it work in practice?

  1. Widget makes a CHARGE request and receives a redirect. In case of the SELECTIVE_NATIVE integration this occurs in the SELECTIVE_NATIVE iframe, which passes the redirect to the widget code using a window.postMessage.
  2. If the CHARGE returns a response with the interaction.code PROCEED and redirect.type 3DS2-HANDLER then the widget renders a lightbox.
  3. The lightbox then opens an iframe, passing the URL for the handler page, along with several parameters such as the redirect url for the handler page to use, and also a parameter which tells the handler page whether to return a message or redirect itself at the end of the 3DS2 challenge process.
  4. The handler page takes care of any interactions with the PSP.
  5. On final redirect from OPG specifying which merchant page the user should be redirected to, the handler page  (if it was instructed by lightbox to return a message) sends a cross-frame message back to the lightbox with the details of the redirect
  6. The lightbox listens for the message, and on receipt, calls the appropriate code in the payment page v3 widget to initiate the redirect, taking into account any custom callbacks used by single page applications.
  7. The user is redirected to the correct merchant page.

How do I set the lightbox size?

You can specify certain sizes of 3DS2 window from the payment service provider (and in turn the issuer) with the challengeWindowSize parameter. The parameter is offered by the payment page widget v3 in the CHARGE response: style.challengeWindowSize.

The possible sizes are:

  • fullPage (not recommended for use)
  • 250x400
  • 390x400
  • 600x400
  • 500x600 (default)

You can provide values for the style.challengeWindowSize parameter already when making your initial server-side LIST request (for details, see LIST request). In this case, the lightbox will be displayed in that size. 

If no values for the style.challengeWindowSize are provided, then the lightbox will be displayed in a default size of 500x600. 

If the screen size is too small (e.g. mobile device) for the default or the selected size, the lightbox will be displayed as a fullscreen-sized iframe.

How do I work with z-index?

Depending on the design of your merchant shop, you might need to adjust different z-index property values. The default value can be overwritten by creating a custom style. It will overwrite any z-index value you have. See the example below:

.op-payment-widget-lb-overlay {
    ...
    z-index: 3;
    ...
}

Implementation details

The main changes to the 3DS2 handler page to enable this flow are:

  • Implementation of additional parameters which can be appended to the URL used to open the handler page in an iframe (the lightbox). The purpose of these additional parameters is to:

    • inform the handler page that it is being loaded within an iframe instead of a separate window, and

    • pass some data needed for processing the result message that the handler page will return to the parent window.

  • Implementation of a logic for handling final redirects (to merchant payment success or failure page) from the Payment Gateway where the parent window is messaged instead of initiating a full page redirect. This is because a full page redirect that occurs within the handler page inside a lightboxed iframe will only redirect within the iframe, but not initiate a full page redirect in the parent window (merchant's shop page).

 

Full page redirect vs lightbox

  Lightbox mode Full redirect mode
CHARGE response CHARGE returns a response with interaction.code PROCEED and redirect.type 3DS2-HANDLER CHARGE returns a response with interaction.code PROCEED and redirect.type 3DS2-HANDLER
Opening page

The handler page is  opened using the redirect.url (and redirect.parameters encoded as query string) from the CHARGE response

Additionally:

These parameters are appended as additional query string parameters to the  querystring when opening it in iframe:

  • isLightbox - boolean - notifies the handler page that it loaded in a parent window iframe
  • targetOrigin - string - the origin of the parent, used for security purposes to check the target of the redirect message
  • suppress - boolean - a parameter with the value of the redirect.suppressIFrame returned by OPG in the CHARGE response by the payment widget v3 when initiating redirects
The handler page is  opened using the redirect.url (and redirect.parameters encoded as query string) from the CHARGE response
Behavior on final redirect

If isLightbox=true was passed as a query string parameter, the handler page will post a cross-window message using window.postMessage, with a data object containing, as a minimum:

  • an interaction object with code and reason properties to inform the merchant of the outcome of the 3DS2 process
  • a redirect object, with URL and parameter properties indicating which redirect should be performed in the merchant's shop
  • the supress value that was passed to the handler page.
The handler page will initiate a full page redirect to either the merchant success or cancel page.
 
Parent window will not be informed of this redirect.

 

Opening the lightbox

The format of the URL used when opening the handler page in lightbox mode should look like in the following way:

{redirect.url received in CHARGE response}?{query string built from the redirect.parameters received in the CHARGE response}&isLightbox=true&targetOrigin={merchant shop origin}&suppress={value of redirect.suppressIFrame from CHARGE response}

 

Listener for the final redirect message

Within the parent application (payment widget v3 or merchant shop), there should be a listener for the final redirect message, for example:

window.addEventListener('message', function (event) {

        if (redirectUrl.includes(event.origin)) {
            var message = JSON.parse(event.data);
            var redirect = { ...message.data.redirect, suppressIFrame: message.suppress };
            
            // Merchant shop redirect logic here...
        }
    });
 
Final redirect message
When the final redirect message is received back from the handler page, there are several scenarios that we handle in the payment page widget v3. Each scenario depends on the shop's application architecture. 
 
  Scenario 3DS2 success case 3DS2 error case
Non-preset-first flow(for example, regular CHARGE call) Merchant provided no custom proceedFunction or abortFunction when initiating payment widget Full page redirect to the redirect.url received in message => should be merchant's success page Full page redirect to the redirect.url received in message => should be merchant's cancelled payment page
Merchant provided a custom proceedFunction but not an abortFunction The custom proceedFunction is called with the data from the handler page redirect message The custom proceedFunction is called with the data from the handler page redirect message
Merchant provided a custom proceedFunction and a custom abortFunction The custom proceedFunction is called with the data from the handler page redirect message
If the interaction code in the handler page message is specifically ABORT, then we call the abortFunction
 
Otherwise, the custom proceedFunction is called with the data from the handler page redirect message
Preset-first flow (for example summary page) Merchant provided no custom onResult function Full page redirect to the redirect.url received in message => should be merchant's success page Full page redirect to the redirect.url received in message => should be merchant's cancelled payment page
Merchant provided a custom onResult function The custom onResult is called with the data from the handler page redirect message The custom onResult is called with the data from the handler page redirect message

 

 

Single page applications
 
If you have a single page application using client side routing and you use the non-preset-first flow, ensure that you  provide a custom proceedFunction when initiating the payment page v3 widget and that the function handles the following interaction codes: PROCEED, RETRY, ABORT and has default handling for any unrecognised interaction codes.
 
If you usw the preset-first flow (with a confirmation page), ensure you have provided a custom onResult function within an summaryPageHandler object, handling these codes: PROCEED, RETRY, ABORT and that the function has default handling for any unrecognised interaction codes.
 
Within these custom functions, you will need to handle the redirect logic yourself.
 
See the documentation on initiating the payment page v3 widget
 
Troubleshooting
When there is an error in the handler page, the lightbox closes displaying an error message on the payment form using the widget standard error message. The customer normally needs to reload the payment form with a new payment session.
 

Web Content Display

3D Secure 1

In the following examples we will use a Wirecard sandbox contract with 3D Secure enabled. The following accounts can be used for testing 3D Secure scenarios on Wirecard:

VISA:

Card Number: 4012000300001003
CVV: 003
Expiry Date: Any valid date
3D Secure Password: wirecard
Holder Name: Any

Mastercard:

Card Number: 5413330300001006
CVV: 006
Expiry Date: Any valid date
3D Secure Password: wirecard
Holder Name: Any

Note: The 3D Secure enrolled test accounts are PSP specific, the format and behavior differs very much. Please refer to PSP specific documentation or contact our support (support.de@payoneer.com) to find out 3D Secure testing details with different PSPs.
Step 1: LIST Request

This example illustrates the PURE_NATIVE integration type where a CHARGE request with account information is passed from the merchant's system to the OPG. To ensure that 3D Secure processing is enabled in this example, we explicitly configured a separate division called "3Dsecure" with PSP contracts that have 3D Secure enabled on the PSP side (please contact our support to help you with contract configuration). As an alternative, passing a customerScore in the LIST with values ranging from 0 - 1000 can filter out some contracts depending on the configuration, and enable or disable the security features like 3D Secure check. Passing a low number in the customerScore field should leave only 3D Secure contracts in the routing.

Important: Many PSPs require a customer IP and a user Agent to be passed during a 3D Secure authentication request. That is why it is recommended to fill out the clientInfo object during a LIST request.
LIST Request:
 {
"transactionId": "3d-0001234",
"country": "DE",
"integration": "PURE_NATIVE",
"division": "3Dsecure",
"callback": {
  "returnUrl": "https://dev.oscato.com/demoshop/summary.html",
  "cancelUrl": "https://dev.oscato.com/demoshop/payment-failure.html",
  "notificationUrl": "https://dev.oscato.com/demoshop/optile-notifications"
  },
"customer": {
  "number": "123",
  "email": "buyer123@example.com"
  },
"customerScore": 200,
"clientInfo": {
  "ip": "83.171.174.105",
  "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:55.0) Gecko/20100101 Firefox/55.0",
  "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
  },
"payment": {
  "reference": "demoshop 0001234-123",
  "amount": 25.99,
  "currency": "EUR"
  }
}

Response:
 {
"links": {
  "self": "https://api.sandbox.oscato.com/api/lists/59c10807cb425c2661d45481lmn83pf5uk1775tukqc41v52j9"
  },
"timestamp": "2017-09-19T12:05:27.646+0000",
"operation": "LIST",
"resultCode": "00000.11.000",
"resultInfo": "2 applicable and 0 registered networks are found",
"returnCode": {
  "name": "OK",
  "source": "GATEWAY"
  },
"status": {
  "code": "listed",
  "reason": "listed"
  },
"interaction": {
  "code": "PROCEED",
  "reason": "OK"
  },
"identification": {
  "longId": "59c10807cb425c2661d45481lmn83pf5uk1775tukqc41v52j9",
  "shortId": "16244-09875",
  "transactionId": "3d-0001234"
  },
"networks": {
  "applicable": [{
    "code": "VISA",
    "label": "Visa",
    "method": "CREDIT_CARD",
    "grouping": "CREDIT_CARD",
    "registration": "OPTIONAL",
    "recurrence": "NONE",
    "redirect": false,
    "links": {
      "form": "https://resources.sandbox.oscato.com/resource/form/DEMOSHOP/standard.html",
      "logo": "https://resources.sandbox.oscato.com/resource/network/DEMOSHOP/de_DE/VISA/logo.png",
      "self": "https://api.sandbox.oscato.com/api/lists/59c10807cb425c2661d45481lmn83pf5uk1775tukqc41v52j9/VISA",
      "lang": "https://resources.sandbox.oscato.com/resource/lang/DEMOSHOP/de_DE/VISA.properties",
      "operation": "https://api.sandbox.oscato.com/api/lists/59c10807cb425c2661d45481lmn83pf5uk1775tukqc41v52j9/VISA/charge",
      "localizedForm": "https://resources.sandbox.oscato.com/resource/form/DEMOSHOP/DE/de_DE/VISA/standard.html",
      "validation": "https://api.sandbox.oscato.com/pci/v1/59c10807cb425c2661d45481lmn83pf5uk1775tukqc41v52j9/DEMOSHOP/de_DE/VISA/standard/validate"
      },
    "button": "button.charge.label",
    "selected": false
    },
  {
    "code": "MASTERCARD",
     ...
    }]
    },
    "operationType": "CHARGE"
}

Step 2a. CHARGE with enrolled credit card

If the request was successful (interaction.code = PROCEED) and the redirect.url contains a URL that does not lead to one of the "callback" URLs provided during the LIST, it means that the credit card supplied by a customer is 3D Secure enrolled and a PA request is generated.

At this point the merchant's system should redirect the client's browser to a URL from a "redirect" block of CHARGE response using a suggested HTTP "method" and HTTP "parameters". In the example above, these are the POST method and PaReq, TermUrl, and MD parameters. The property suppressIFrame, if set to true, indicates that a redirect cannot be performed within the IFrame: either a full page redirect should be executed or a new window/tab is opened.

This action should result in the rendering of a 3D Secure page by the customer's issuer bank system; in our case that is a Wirecard demo page for 3D Secure check, as shown in the figure below.

The customer is then asked to enter additional validation (SMS-tan, 3D Secure password, etc.) and continue with the payment or cancel the transaction.

In case of Wirecard, the test contract password is: wirecard

If everything was successful, the customer is automatically redirected to the returnUrl of a "callback" from the original LIST request with additional parameters from the OPG system, e.g.:
https://dev.oscato.com/demoshop/summary.html?shortId=10127-51825&interactionReason=OK&resultCode=00000.WIRECARD.0&longId=59c10d47cb427abc123263c9c&transactionId=3d-0001234&interactionCode=PROCEED&amount=25.99&reference=demoshop+0001234-123¤cy=EUR¬ificationId=2436093064195617&referenceId=59c10d47cbabc123be3263c9c×tamp=2017-09-19T14%3A47%3A34.156%2B02%3A00

If a payment has failed (due to 3D Secure check or during Authorization/Capture), the customer is automatically redirected to the cancelUrl of a "callback" from the original LIST request with additional parameters from the OPG system, e.g.:
https://dev.oscato.com/demoshop/payment-failure.html?shortId=08706-31667&interactionReason=INVALID_ACCOUNT&resultCode=45010.WIRECARD.525&longId=59c112b4cb4abc123c1a7a69c&transactionId=3d-0001234&interactionCode=TRY_OTHER_ACCOUNT¬ificationId=2436364692588779&referenceId=59c112b4cb42f93abc123a69c×tamp=2017-09-19T14%3A52%3A05.785%2B02%3A00

CHARGE Request:
POST to VISA operation link from previous LIST response
{
"account": {
  "holderName": "Testy Threed",
  "number": "4012000300001003",
  "expiryMonth": 1,
  "expiryYear": 2019,
  "verificationCode": "003"
  }
}

Response:
{
"links": {
  "self": "https://api.sandbox.oscato.com/api/charges/59c10d47cb427396be3263c9c"
  },
"timestamp": "2017-09-19T12:27:53.844+0000",
"operation": "CHARGE",
"resultCode": "00001.WIRECARD.0",
"resultInfo": "Pending, you have to check the status later",
"pspCode": "WIRECARD",
"returnCode": {
  "name": "OK_PENDING",
  "source": "PSP"
  },
"status": {
  "code": "pending",
  "reason": "debit_requested"
  },
"interaction": {
  "code": "PROCEED",
  "reason": "PENDING"
  },
"identification": {
  "longId": "59c10d47cb427396be3263c9c",
  "shortId": "10127-51825",
  "transactionId": "3d-0001234",
  "pspId": "C660018150582407317218"
  },
"redirect": {
  "url": "https://c3-test.wirecard.com/acssim/app/bank",
  "method": "POST",
  "parameters": [{
    "name": "PaReq",
    "value": "eJxtU9tuozAQfe9XIN6LL2CMI+Oq3ewlD9lNt6kq7RsLo4IacGpgQ/br11CybQIWSMzMGebM+Iy86cqd8wdMXegqdomHXQeqVGdF9Ry7j9sv15Hr1E1SZclOVxC7R6jdG3Ult7kBWD5A2hpQV449cg11nTyDU2Sxy4KQM1/YJ/B5QEUYEOy+4Qbs5vYnvL7bg29koSwJj0p0Ms9BazBpnlTNuXsIJenr3eq7ItQPWCjRaE5xJZjVUjGMMbEvlujNMQVWSQnqqTCQJiZzllBq5yHXe4mGwBSf6rZqzFFF1JY/GVNYa3Yqb5r9AqHD4eAdxgJeqkuJ+uB5x2i+Zblpe3c9R6QrMvV7d0/v//7arF/yFTzpbvuS3f342unt51UsUY+Y5mVJA4piwrEgwiHBgvIF8yUa/DMDL/seFWWeEPjDsZc3hqY5+5H17SlXCIkunDOTbY2xsjwqwSM72pM1BUK3tzLtfyzR/++Lec4PTn76NquptLHa4CwUViyMR4zy0KeM+5QEHPshi3qlDaBZNoWVABGYDHSKSz1I9LGqpfa+Fv29D/tklw2db9s/Ym7rMQ=="
    },
    {
    "name": "TermUrl",
    "value": "https://api.sandbox.oscato.com/decision/WIRECARD/DEMOSHOP/do.html?type=accept&requestId=59c10d4880ae1fa446fb3b6dc"
    },
    {
    "name": "MD",
    "value": ""
    }],
  "suppressIFrame": true
  },
"customer": {
  "number": "123",
  "email": "buyer123@example.com"
  }
}

Step 2b. CHARGE with not enrolled credit card

If the request was successful (interaction.code=PROCEED) and the redirect.url contains a URL that lead to one of the "callback" URLs provided during LIST, it means that the credit card supplied by a customer is not 3D Secure enrolled or cannot be validated via a 3D Secure process at the time and CHARGE was processed without a 3D Secure authentication.

The interaction code may also indicate an issue with the payment; if this is the case and if redirect is present, the redirect.url will lead to cancelUrl from "callback" provided during LIST.

At this point the merchant's system may redirect the client's browser to a URL from the redirect block of CHARGE response using a suggested HTTP "method" and HTTP "parameters" or it may follow any other logic of successful payment processing as it is done during a non-3D Secure flow.

CHARGE Request:
POST to VISA operation link from previous LIST response
{
"account": {
  "holderName": "Testy Threed",
  "number": "4111111111111111",
  "expiryMonth": 1,
  "expiryYear": 2019,
  "verificationCode": "003"
  }
}

Response:
{
"links": {
  "payout": "https://api.sandbox.oscato.com/api/charges/59c117dfcb427396be3263efc/payout",
  "self": "https://api.sandbox.oscato.com/api/charges/59c117dfcb427396be3263efc"
  },
"timestamp": "2017-09-19T13:13:04.615+0000",
"operation": "CHARGE",
"resultCode": "00000.WIRECARD.0",
"resultInfo": "AVS Unavailable.",
"pspCode": "WIRECARD",
"returnCode": {
  "name": "OK",
  "source": "PSP"
  },
"status": {
  "code": "charged",
  "reason": "debited"
  },
"interaction": {
  "code": "PROCEED",
  "reason": "OK"
  },
"clearing": {
  "amount": 25.99,
  "currency": "EUR"
  },
"identification": {
  "longId": "59c117dfcb427396be3263efc",
  "shortId": "10818-81133",
  "transactionId": "3d-0001235",
  "pspId": "C874211150582678450819"
  },
"redirect": {
  "url": "https://dev.oscato.com/demoshop/summary.html",
  "method": "GET",
  "parameters": [{
    "name": "shortId",
    "value": "10818-81133"
    },
    {
    "name": "interactionReason",
    "value": "OK"
    },
    {
    "name": "resultCode",
    "value": "00000.WIRECARD.0"
    },
    {
    "name": "longId",
    "value": "59c117dfcb427396be3263efc"
    },
    {
    "name": "transactionId",
    "value": "3d-0001235"
    },
    {
    "name": "interactionCode",
    "value": "PROCEED"
    },
    {
    "name": "amount",
    "value": "25.99"
    },
    {
    "name": "reference",
    "value": "demoshop 0001235-123"
    },
    {
    "name": "currency",
    "value": "EUR"
    }]
    },
"customer": {
  "number": "123",
  "email": "buyer123@example.com"
  }
}

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.sandbox.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 Orchestration Platform 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 Orchestration Platform 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.

Web Content Display

Intercard

There are some fields that are mandatory for an Intercard payment (in addition to the Orchestration Platform's  mandatory fields):

  • Customer#Name#firstName
  • Customer#Name#lastName
  • Mandate#reference
  • Mandate#MandateAuthentication#time

Web Content Display

Klarna

Mandatory fields for Klarna Pay Now:

  • style.language: a language code composed of ISO 639 two-letter language codes and ISO 3166 two-letter country codes separated by an underscore character. Similar to RFC 1766. Customer's locale.
  • country: ISO 3166 alpha-2 country code.
  • payment
    • amount: Non-negative, minor units. Total amount of the order, including tax and any discounts.
    • curreny: ISO 4217 currency code.
  • products
    • name: String, any descriptive item name.
    • quantity: Non-negative. Quantity of items of this type.
    • amount: Minor units. Includes tax and discount.
    • * netAmount: Minor units. Includes tax and discount. Same value as amount above.
    • * taxAmount: Minor units. Total tax amount for this product.
    • * taxRatePercentage: Tax rate. Ratio between tax_amount and net_amount.

The parameters marked with an asterisk above are not mandatory as per Klarna API, but it is considered good practice to include them in payment requests.

Web Content Display

MuchBetter

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".

Web Content Display

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.
     
  • For pure redirect methods, 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 methods with in-page forms such as cards. 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. 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.