PIS flow
Here is the nominal flow in Payment Initiation.
Notes
- We consider that the User registration has been done.
- For simplicity, Docker and Gateway have been merged. In Private mode, there is not Gateway, the Docker is calling directly the bank and in Gateway mode, the Docker is forwarding the request to the Gateway.
- Another difference between the two modes is the roundtrip to the bank that is going directly from the client to the bank and back. In Gateway mode, since banks are checking the callback URL against the ones that have been registered in their system upon onboarding, the callback must be among one of ours. Else, if it's not found, they won't process the request.
- No UI/UX considerations here, bank selection efficiency is up to you :).
- For efficiency and flexibility, you should have a cache/copy of the banks list in your system.
Tips & tricks
Cache/copy of the list of banks in your system
Having a cache/copy of the list of banks can substantially improve the response time of your UI. It can also allow you to decide which banks you want to work with. E.g. you may not want to work with the banks that are not offering the instant payment. To do this without cache on your side, you would have to call the Docker to get the list of banks of the selected country, then, for each bank, you'll have to call again to get the connector's options and introspect the options to see if they support instant payment... You'd better to do it in a background job and cache it in your system!
Be ready to face the options
Options are describing the differences between the banks. E.g. one is requiring debtor IBAN or recipient country to work, another not. If your application can respond to the options, you'll be able to use any bank. In your code, you don't have - and you shouldn't have - to switch on the connector id to decide how to behave. Should I provide the country or not when initiating a payment? Are they mandatory or optional?
That's the kind of questions the options are answering. Your code is capable of prompting the user to enter the country or enter/select the debtor IBAN. That's all. Then you just have to check the options of the selected connector to switch your display.
Explanations
Bank selection
The key between you and us is to know which bank to use is the connector id. It is a property of a bank record. they are grouped by countries. Without any UI/UX considerations, you can grab the list of banks ask the user to select the country, then ask him to select one bank in the list the banks in that country.
You'll find also an extra parameter bankGroup which contains, when necessary, a group name for multiple connectors. E.g., in France, you'll find Banque Populaire Alsace Lorraine Champagne, Banque Populaire Aquitaine Centre Atlantique / CMM Littoral du Sud Ouest, Banque Populaire Auvergne et Rhône-Alpes... all Banque Populaire. The bankGroup for those is "Banque Populaire". You can then adapt you UI to prevent very long list of connectors. If you want of course...
Build your UI
Now that you have the connector id, you can ask the options for PIS. Based on those options, you can build your interface and logic. Don't build them depending on the bank/connector id but depending on those options. You'll have less case and your code is not sensible to bank changes.
First check the available types of payment: domestic, SEPA, instant SEPA? Maybe you know what kind of payment you want to support and you've already filtered the banks offering it prior to bank selection? Anyway, in the options, you find for each payment type, if it's available or not.
The types of payments supported for now: "domesticTransfers", "instantDomesticTransfers", "sepaCreditTransfers" and "instantSepaCreditTransfers".
In each type of payment you'll find a section "singlePayments":
{
...
"domesticTransfers": {
"singlePayments": {
"supported": true,
"cancelSupported": false,
"specificPaymentDate": 0,
"psuInformation": null
}
...
}
"supported" is quite obvious 😏.
"cancelSupported" is always false.
"specificPaymentDate" tells you if you can specify a specific date for the payment ALLOWED (1) or not NOT_ALLOWED (0)
"psuInformation" is a message in English containing explanation, tips... related to that connector, that you can show to the user(see PSU Informations).
Create the payment initiation request
Create and populate the model and call the payment Docker endpoint. In return you'll get a resultStatus with the value REDIRECT and in dataString the URL where to redirect the PSU.
You should save the necessary data for this request in your storage associated with the unique flowId of that request; you'll use it when you're back from the bank: linked PSU to get the user context, connector id, response's flowContext.
You do the redirect the PSU to that URL which leads to the bank Strong Customer Authentication (SCA). The PSU identifies and validate the payment request on bank side. The bank redirect to our Gateway which redirects to the callback URL you defined in redirectUrl field of the request.
Finalize the request
Back to your app, you can call the Docker to get the flow id you set in the flowId field of the request, providing the query string verbatim. With this flow id, you can restore the context of this call from your storage and prepare the call to the finalize endpoint.
You call the finalize endpoint by passing it the flow context you restored from your storage and the user context of the linked PSU.
Getting the status
If the response resultStatus is DONE, this means that the access request is... done, you can now ask for the status. You call this endpoint regularly. We try to provide as much detail as we have.
Sadly, not all bank will return a Payment Status of ACCC, which is the best you might have.
Multiple bank roundtrips
It may happen that the bank requires multiple roundtrip. E.g. the first is for the login of the user, the second is for the validation of the payment. In that case, you get a REDIRECT from the payment initiation request (POST payments), then you get a REDIRECT from the first call to finalize (PUT payments). You should redirect again to the new URL (dataString) and call a second time the finalize (PUT payments) as you did the first time.
Asynchronous bank (RETRY case)
Some banks may need some time to complete their internal process, they are working asynchronously. In that case, you'll get RETRY from the finalize (PUT payment).
You will never need to call twice the init (POST payments)! So you'll never have a RETRY out of it.
So, in that case, the flow is: initiation return REDIRECT > bank roundtrip > finalize call returns RETRY > wait some hundreds milliseconds > call again finalize > loop until not RETRY or your internal timeout.
DECOUPLED action
Some bank requires an action to be done on another device/application. They will certainly firstly do a REDIRECT to identify the PSU and then, they require an action to be done on this device/application. In this case, you get a DECOUPLED and you have to display a message to the user. If the bank provided a message, you'll find it in the field dataString of the response. If not provided, dataString is null, you can put your own message. You have to invite the user to press a button when the action has been done.
Programming principle
The programming principle could look to this:
- call initiation
- case REDIRECT
- do bank roundtrip
- case DECOUPLED
- display (received message || default message) && button
- case DONE
- Nothing to do, call finalize directly
- case REDIRECT
- do
- call finalize
- case REDIRECT
- do bank roundtrip
- case DECOUPLED
- display (received message || default message) && button
- case RETRY
- wait some hundreds of milliseconds
- case REDIRECT
- call finalize
- while not DONE || ERROR
- get status
Going further
You can find in the following page PIS - Payment Initiation Service more information about the calls or you can navigate to the API definition for PIS .
Updated 2 months ago