Links

TWINT

This chapter will handle all specifics involved with the integration of the payment method TWINT.

Requirements

  • A corresponding license and thus a valid identification with a username and password for the Saferpay system.
  • At least one active Saferpay terminal via which payment can be carried out and the associated Saferpay TerminalId.
  • A valid TWINT contract
For Twint activation on the Saferpay terminal, please contact your sales contact.

Supported features

Feature
Support
Multipart Captures
Secure Card Data
Refunds
Recurring Payments
3D Secure
Dynamic Currency Conversion (DCC)
Mail Phone Order
Testing
Omni-Channel

Integration

The general integration of TWINT can be done via the Payment Page -However other features require a different path. See further down in this chapter- and requires the following things to be noted:
  • JSON API Version 1.7 or later.
  • Unlike normal credit card transactions, where a capture could be attempted after the normal reservation time, TWINT does only offer a maximum timeframe of 7 days! After that the transaction will be discarded and a capture will not initiate the money-transfer with the next batch-close, so make sure, to capture your transactions within this time limit!
  • Due to processing limitations, a refund can fail, if it is executed earlier than two hours after the initial transaction. The initial transaction needs to be processed first, until a refund can be executed, which happens within said two hours!
  • The notification URLs, inside theNotification conatiner are mandatory, in order to avoid missing payment successes. See the Payment Page process for further information.

User on file

Twint User on File saves Twint payment means inside the Saferpay Secure Card Data Store, allowing you to execute subsequent/recurring transactions on a users Twint account.

Requirements

The following requirements are to be met, if Twint User on File is to be used, aside the normal requirements:
    • A license for Saferpay Secure Card Data, which is usually included in Saferpay Business!
  • The activation of User on File for your contract. Please contact your contractual manager, if you need this feature enabled!
  • JSON API Version 1.14 or later
Twint User on File is only available via the Standalone Secure Card Data registration and requires Saferpay Business, so the card data may be used! Furthermore, the Twint aliases may only be used with Authorize Direct.

Alias Insert

The registration is done via the Saferpay Alias Store. Within the Alias Insert Request, you need to specify the parameter Type with the value TWINT, which signals, that you want to save Twint payment means.
Request
Response
{
"RegisterAlias": {
"IdGenerator": "RANDOM_UNIQUE"
},
"Type": "TWINT",
"LanguageCode": "en",
"RequestHeader": {
"SpecVersion": "1.25",
"CustomerId": "242225",
"RequestId": "5f543be575b3f3ecff3214257ac6978a",
"RetryIndicator": 0,
"ClientInfo": {
"ShopInfo": "My Shop",
"OsInfo": "Windows Server 2013"
}
},
"ReturnUrls": {
"Success": "https://www.myshop.com/success",
"Fail": "https://www.myshop.com/fail",
"Abort": "https://www.myshop.com/abort"
}
}
{
"ResponseHeader": {
"SpecVersion": "1.25",
"RequestId": "5f543be575b3f3ecff3214257ac6978a"
},
"Token": "y6678qfw3dm9pule1inqkpr1o",
"Expiration": "2019-11-15T14:39:16.642+01:00",
"Redirect": {
"RedirectUrl": "https://test.saferpay.com/vt2/api/register/twint/242225/y6678qfw3dm9pule1inqkpr1o",
"PaymentMeansRequired": true
}
}

Redirect to TWINT

The RedirectUrl then needs to be opened inside an iFrame, as a redirect, or lightbox. Saferpay will then present the following screen.
(click to enlarge)

Redirect to Shop

Once this process is done, the user gets redirected towards one of the previously defined ReturnUrls, depending on the outcome.

Alias Assert Insert

The merchant system then needs to execute the Alias Assert Insert Request, in order to gather the alias and other important payment mean details.
Request
Response
{
"Token": "67tdpr8keb3ky3y6728kqv4gk",
"RequestHeader": {
"SpecVersion": "1.14",
"CustomerId": "242225",
"RequestId": "22c449e9cb06a227491c0f18532d9ef1",
"RetryIndicator": 0,
"ClientInfo": {
"ShopInfo": "My Shop",
"OsInfo": "Windows Server 2013"
}
}
}
{
"ResponseHeader": {
"SpecVersion": "1.14",
"RequestId": "22c449e9cb06a227491c0f18532d9ef1"
},
"Alias": {
"Id": "a2f4d6390bdf5ba4ed9d0c0f2318bc2b",
"Lifetime": 1000
},
"PaymentMeans": {
"Brand": {
"PaymentMethod": "TWINT",
"Name": "TWINT"
},
"Twint": {
"CertificateExpirationDate": "2020-12-15T13:18:08.000+01:00"
}
}
}
One speciality with Twint User on File is, the Twint.CertificateExpirationDate parameter. Each registered Twint payment mean, will have its own expiration date within the Twint system, which does not correspond with the Saferpay Alias Lifetime! The parameter will return the expiration date of this registration certificate. Once it has passed, the Twint alias becomes invalid.
Furthermore note, that using RANDOM_UNIQUE will always return the already existing alias, even if it is expired on Twint side. While it can serve as a mean to filter out already existing customers and thus help preventing double-registrations, you must keep this in mind. Should you get a rejection saying, that the alias has expired on Twint side, you must first delete the old alias, before your customer can re-register.

Using the Alias

Once you have obtained the alias, you can go ahead and execute your recurring/subsequent transaction using the Transaction AuthorizeDirect request. The alias is set within the PaymentMeans.Alias container, but remember, that this transaction, like all Twint transactions, also must be captured for the money to flow.

Web View Web-to-App switch

If you are integrating Twint inisde a web-view, you may have to specifically configure your view, in order for the Twint app to open.
Here is example-code on how this is achieved.
This code has been directly provided by Twint. If you have any questions, please ask Twint for help.
iOS
Android
// In the UIViewController that embed the Payment Layer, you have to register a delegate that will detect the Twint Actions and will open the correct URL.
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSURL * srcURL = [NSURL URLWithString:@"https://yourApp.ch/webShop"];// Use your url for loading remote or local
[self.webView loadRequest:[NSURLRequest requestWithURL:srcURL]];
[self.webView setNavigationDelegate:self];
}
// Inform Payment layer about compatibility
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
[webView evaluateJavaScript:@"window.twintHookActivated=true;window.refreshUI()" completionHandler:^(id idOf, NSError * error) {
}];
}
// Detect Twint Actions and open using [UIApplication sharedApplication] openURL
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
if ([[navigationAction.request.URL absoluteString] hasPrefix:@"twint-"]) {
[[UIApplication sharedApplication] openURL:navigationAction.request.URL options:nil completionHandler:^(BOOL success) {
if(!success){
[webView evaluateJavaScript:@"if(typeof appNotInstalled!='undefined') appNotInstalled()" completionHandler:^(id idOf, NSError * error) {
}];
}
}];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}else{
decisionHandler(WKNavigationActionPolicyAllow);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView web =(WebView)findViewById(R.id.webView);
WebSettings webSettings =web.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
web.loadUrl("https://yourApp.ch/webShop");
web.setWebViewClient(new WebViewClient() {
@Override
// Inform Payment layer about compatibility
public void onPageFinished(WebView view, String url)
{
view.loadUrl("javascript:window.twintHookActivated=true;");
view.loadUrl("javascript:window.refreshUI()");
}
// Detect Twint Actions and open custom Intent
public boolean shouldOverrideUrlLoading(WebView view, String url){
// do your handling codes here, which url is the requested url
// probably you need to open that url rather than redirect:
if(url.contains("ch.twint.action.TWINT_PAYMENT")){
String action ="ch.twint.action.TWINT_PAYMENT";
String token = url.substring(url.indexOf("S.code=")+7,url.length());
token = token.substring(0,token.indexOf(";"));
Intent intent = new Intent();
intent.setAction(action);
intent.putExtra("code",token);
intent.putExtra("startingOrigin","EXTERNAL_WEB_BROWSER");
startActivity(intent);
return true ;
}else if(url.contains("ch.twint.action.TWINT_UOF_REGISTRATION")){
String action ="ch.twint.action.TWINT_UOF_REGISTRATION";
String token = url.substring(url.indexOf("S.code=")+7,url.length());
token = token.substring(0,token.indexOf(";"));
Intent intent = new Intent();
intent.setAction(action);
intent.putExtra("code",token);
intent.putExtra("startingOrigin","EXTERNAL_WEB_BROWSER");
startActivity(intent);
return true ;
}
view.loadUrl(url);
return true;
}
});
}

Testing

Please refer to this chapter, if you want to test TWINT.