# TWINT

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

## &#x20;General requirements

* A [corresponding license](https://docs.saferpay.com/home/master/licensing) 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

{% hint style="info" %}
For Twint activation on the Saferpay terminal, please contact your account manager, or our [sales team](https://docs.saferpay.com/home/support#worldline-sales-team).
{% endhint %}

### Technical requirements

The general integration of TWINT can be done via the [Payment Page](https://docs.saferpay.com/home/integration-guide/licences-and-interfaces/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](https://saferpay.github.io/jsonapi/#Payment_v1_Transaction_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](https://saferpay.github.io/jsonapi/#Payment_v1_Transaction_Capture) **will not initiate the money-transfer with the next batch-close**, so make sure, to [capture](https://saferpay.github.io/jsonapi/#Payment_v1_Transaction_Capture) your transactions within this time limit!
  * In justified cases, this period can be extended to 30 days. Please inform our sales department  and [contact Twint](https://www.twint.ch/en/faq/how-do-i-activate-the-30-day-reservation-function/) for more information.
* Saferpay does support[ "Pay later" solution offered by Twint](https://www.twint.ch/en/business-customers/our-solutions/pay-later/).\
  However, one of the available options must be explicitly activated on our side. For more information about different "Pay later" options and their configuration, please contact our sales department.
* The parameter **`OrderId`** is limited to 50 characters.
* 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 the`Notification` container are **mandatory**, in order to avoid missing payment successes. See the [Payment Page process](https://docs.saferpay.com/home/licences-and-interfaces/payment-page#notification.successnotifyurl-and-notification.failnotifyurl) for further information.

### Supported features

| Feature                                                                                                                                                                                                         |                                  **Support**                                 |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------: |
| [Capture](https://docs.saferpay.com/home/integration-guide/licences-and-interfaces/capture-and-daily-closing)/[Cancel](https://docs.saferpay.com/home/licences-and-interfaces/capture-and-daily-closing#cancel) |  <p>✅</p><p><a href="#integration"><strong>Needs attention!</strong></a></p> |
| Multipart Captures                                                                                                                                                                                              |                                       ❌                                      |
| Secure Card Data                                                                                                                                                                                                | <p>✅</p><p><a href="#user-on-file"><strong>Needs attention!</strong></a></p> |
| [Refunds](https://docs.saferpay.com/home/integration-guide/licences-and-interfaces/transaction-interface/refunds)                                                                                               |  <p>✅</p><p><a href="#integration"><strong>Needs attention!</strong></a></p> |
| Recurring Payments                                                                                                                                                                                              | <p>✅</p><p><a href="#user-on-file"><strong>Needs attention!</strong></a></p> |
| 3D Secure                                                                                                                                                                                                       |                                       ❌                                      |
| Dynamic Currency Conversion (DCC)                                                                                                                                                                               |                                       ❌                                      |
| Mail Phone Order                                                                                                                                                                                                |                                       ❌                                      |
| [Testing](#testing)                                                                                                                                                                                             |                                       ✅                                      |
| [Omni-Channel](https://docs.saferpay.com/home/integration-guide/licences-and-interfaces/omni-channel)                                                                                                           |                                       ✅                                      |

## TWINT User on file

Twint User on File saves Twint payment means inside the [Saferpay Secure Card Data Store](https://docs.saferpay.com/home/integration-guide/licences-and-interfaces/secure-card-data), 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 valid license with access to the [Payment API and Secure Card Data](https://docs.saferpay.com/home/master/licensing).
* JSON API Version 1.14 or later

### Registration via the Payment Page

One of the ways to register a Twint account into Secure Card Data, is via the [Payment Page](https://docs.saferpay.com/home/licences-and-interfaces/secure-card-data#secure-card-data-and-the-payment-page). Simply follow the standard flow there.

{% hint style="warning" %}
A Twint user can reject the User On File registration during a payment. If that is the case, Saferpay will return a successful transaction, but a failed registration. Please make sure, that you are able to[ handle this case accordingly](https://docs.saferpay.com/home/licences-and-interfaces/secure-card-data#handling-registration-failures).
{% endhint %}

### Standalone Registration

The Standalone Registration is done via the [Saferpay Alias Store](https://docs.saferpay.com/home/licences-and-interfaces/secure-card-data#standalone-secure-card-data-registration). Within the [Alias Insert Request](https://saferpay.github.io/jsonapi/#Payment_v1_Alias_Insert), you need to specify the parameter **Type** with the value **TWINT**, which signals, that you want to save Twint payment means.

{% tabs %}
{% tab title="Request" %}

```json
{
  "RegisterAlias": {
    "IdGenerator": "RANDOM_UNIQUE"
  },
  "Type": "TWINT",
  "LanguageCode": "en",
  "RequestHeader": {
    "SpecVersion": "[CURRENT SPEC_VERSION]",
    "CustomerId": "[YOUR_CUSTOMER_ID]",
    "RequestId": "5f543be575b3f3ecff3214257ac6978a",
    "RetryIndicator": 0,
    "ClientInfo": {
      "ShopInfo": "My Shop",
      "OsInfo": "Windows Server 2013"
    }
  },
  "ReturnUrl": {
    "Url": "https://www.myshop.com/return"
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "ResponseHeader": {
    "SpecVersion": "[CURRENT SPEC_VERSION]",
    "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
  }
}
```

{% endtab %}
{% endtabs %}

#### 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)](https://3537448238-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MJbIA8fSCwoMDsZw5y-%2F-Me-PwmwB7Z0ijEEJT5k%2F-Me-W5Q7WD91T9vzT-gE%2FTwint_uof.png?alt=media\&token=24230d45-8db4-42c4-90f4-4d8d727fdb5a)

#### 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](https://saferpay.github.io/jsonapi/#Payment_v1_Alias_Insert), in order to gather the alias and other important payment mean details.

{% tabs %}
{% tab title="Request" %}

```json
{
  "Token": "67tdpr8keb3ky3y6728kqv4gk",
  "RequestHeader": {
    "SpecVersion": "[CURRENT SPEC_VERSION]",
    "CustomerId": "242225",
    "RequestId": "22c449e9cb06a227491c0f18532d9ef1",
    "RetryIndicator": 0,
    "ClientInfo": {
      "ShopInfo": "My Shop",
      "OsInfo": "Windows Server 2013"
    }
  }
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "ResponseHeader": {
    "SpecVersion": "[CURRENT SPEC_VERSION]",
    "RequestId": "22c449e9cb06a227491c0f18532d9ef1"
  },
  "Alias": {
    "Id": "a2f4d6390bdf5ba4ed9d0c0f2318bc2b",
    "Lifetime": 1000
  },
  "PaymentMeans": {
    "Brand": {
      "PaymentMethod": "TWINT",
      "Name": "TWINT"
    },
    "Twint": {
      "CertificateExpirationDate": "2020-12-15T13:18:08.000+01:00"
    }
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
&#x20;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.
{% endhint %}

#### Using the Alias

Once you have obtained the alias, you can go ahead and execute your recurring/subsequent transaction using the [Transaction AuthorizeDirect request](https://saferpay.github.io/jsonapi/#Payment_v1_Transaction_AuthorizeDirect). The alias is set within the **`PaymentMeans.Alias`** container, but remember, that this transaction, like all Twint transactions, also must be [captured](https://docs.saferpay.com/home/integration-guide/licences-and-interfaces/capture-and-daily-closing) 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.

{% hint style="info" %}
This code has been directly provided by Twint. If you have any questions, please ask Twint for help.
{% endhint %}

{% tabs %}
{% tab title="iOS" %}

```objectivec
// 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);
    }
}

```

{% endtab %}

{% tab title="Android" %}

```java
@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;
        }
    });
}
```

{% endtab %}
{% endtabs %}

## Testing

Please refer to [this chapter](https://docs.saferpay.com/home/testing-and-go-live#twint), if you want to test TWINT.
