> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://amer.developers.trustly.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://amer.developers.trustly.com/_mcp/server.

# Mobile web

The Trustly mobile web integration allows you to securely build a bank authorization workflow in your app when your tech stack (such as Flutter, Xamarin, or MAUI) does not support the Trustly iOS or Android SDKs. Integrate the Select Bank Widget or the Trustly Lightbox using the device's secure system browser instead of an embedded WebView to handle bank OAuth constraints and retrieve bank authorization data.

If you need help with your integration, contact your Trustly representative or send your request to [us.integrations@trustly.com](mailto:us.integrations@trustly.com).

Trustly recommends using the Trustly [iOS](/sdks/mobile/i-os), [Android](/sdks/mobile/android), or [React Native](/sdks/mobile/react-native) SDKs to integrate the Trustly UI within mobile applications. Use the Trustly mobile web integration only if your development framework does not support these SDKs.

## Prerequisites

* **Trustly merchant credentials:** An active merchant account with your assigned `accessId` and `merchantId`.
* **Secure backend infrastructure:** A server environment capable of generating HMAC-SHA256 request signatures and handling URL-safe Base64 encoding.
* **Mobile deep link configuration:** The mobile application launching the in-app browser session must have at least one Universal Link (iOS) or App Link (Android) configured to return customers from the bank's OAuth login back to the mobile application. To learn more, see [Allowing Apps and Websites to Link to Your Content](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content) (iOS) and [Handling Android App Links](https://developer.android.com/training/app-links) (Android).

## Integration workflow

The transaction lifecycle uses a secure exchange between your application, your backend server, and the Trustly API.

```mermaid
%%{
  init: {
    'theme': 'dark',
    'themeVariables': {
      'actorFontSize': '18px',
      'messageFontSize': '52px',
      'noteFontSize': '18px'
    },
    'sequence': {
      'actorMargin': 120,
      'messageMargin': 80
    }
  }
}%%
sequenceDiagram
    autonumber
    participant Backend as Backend Server
    participant App as Mobile App
    participant Trustly as Trustly API

    Note over Backend, App: Parameter Creation<br />and Serialization
    
    Backend->>Backend: Generate Parameters and Sign Payload<br /> 
    Backend->>App: Serialize JSON &<br />Base64 Encode Token
    
    Note over App, Trustly: Secure Browser Handshake
    App->>Trustly: Launch Native In-App<br />Browser Session
    Note over Trustly: User Authenticates /<br />Completes OAuth
    
    Note over App, Trustly: App Redirect<br />and Deep Linking
    Trustly-->>App: Deep-Link Redirect<br />(Universal/App Link)
    
    Note over Backend, App: State Validation
    App->>Backend: Forward Parameters<br />for Verification
    
    Backend->>Backend: Validate HMAC Signature (Excluding trustlyContext)<br /> 
    Backend-->>App: Update and Persist<br />Transaction State
```

|  Step | Action              | Description                                                                                                                                                                                |
| :---: | :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **1** | **Generate**        | The backend server generates the required transaction parameters and signs the payload.                                                                                                    |
| **2** | **Serialize**       | The backend converts the payload to a UTF-8 JSON string, base64-encodes the token, and passes it to the mobile app.                                                                        |
| **3** | **Launch and Auth** | The mobile app launches a native in-app browser session using the designated Trustly endpoint. The user then authenticates and completes the bank OAuth flow within the secure Trustly UI. |
| **4** | **Redirect**        | Trustly executes a deep-link redirect (Universal Link or App Link) back to the mobile app.                                                                                                 |
| **5** | **Forward**         | The mobile app intercepts the redirect query parameters and forwards them to the backend server for verification.                                                                          |
| **6** | **Validate**        | The backend validates the cryptographic HMAC signature of the returned parameters (excluding the `trustlyContext`).                                                                        |
| **7** | **Update**          | The backend updates the transaction state and returns the final status to the mobile app to persist.                                                                                       |

## Build and encode the request payload

Assemble the required transaction parameters on your backend. Serialize the data into a UTF-8 JSON string, and convert it into a URL-safe Base64 security token.

Structure dot-notation properties (such as `customer.address.country`) as nested JSON objects prior to Base64 encoding.

### Required parameters

| Parameter           | Type   | Description                                                                     |
| :------------------ | :----- | :------------------------------------------------------------------------------ |
| `accessId`          | String | Your unique merchant access identifier.                                         |
| `merchantId`        | String | Your unique merchant identifier.                                                |
| `amount`            | String | The transaction amount (e.g., `"10.00"`).                                       |
| `currency`          | String | The ISO currency code (e.g., `"USD"`).                                          |
| `paymentType`       | String | The type of payment processing requested.                                       |
| `merchantReference` | String | Your internal tracking identifier for the transaction.                          |
| `requestSignature`  | String | The HMAC-SHA256 signature generated by your backend.                            |
| `returnUrl`         | String | The Universal Link (iOS) or App Link (Android) used for successful completions. |
| `cancelUrl`         | String | The Universal Link (iOS) or App Link (Android) used for canceled checkouts.     |

### Required object structures

* `metadata`: Must contain `deepLinkUrl`, `trustlyContext`, and `integrationContext`.
* `customer`: Must contain `name` and a nested `address` object containing `country`.

### Xamarin implementation example (C#)

```csharp
using System.Collections.Generic;

private Dictionary<string, string> GetEstablishDataValues()
{
    var establishDataValues = new Dictionary<string, string>();
    // Merchant Credentials & Session Setup
    establishDataValues["accessId"] = "ACCESS_ID";
    establishDataValues["merchantId"] = "MERCHANT_ID";
    establishDataValues["merchantReference"] = "MERCHANT_REFERENCE";
    establishDataValues["requestSignature"] = "REQUEST_SIGNATURE";
    establishDataValues["env"] = "sandbox"; // Use "production" for live environments
    // Transaction details
    establishDataValues["amount"] = "10.00";
    establishDataValues["currency"] = "USD";
    establishDataValues["paymentType"] = "Retrieval";
    establishDataValues["paymentProviderId"] = "PAYMENT_PROVIDER_ID";
    establishDataValues["description"] = "Xamarin InAppBrowser";
    // Customer information
    establishDataValues["customer.name"] = "John Smith Xamarin";
    establishDataValues["customer.phone"] = "2145553434";
    establishDataValues["customer.email"] = "jsmith@email.com";
    establishDataValues["customer.address.address1"] = "2000 Broadway Street";
    establishDataValues["customer.address.city"] = "Redwood City";
    establishDataValues["customer.address.state"] = "CA";
    establishDataValues["customer.address.zip"] = "94063";
    establishDataValues["customer.address.country"] = "US";
    // App/Universal link routing
    establishDataValues["metadata.deepLinkUrl"] = "https://YOURDOMAIN.com/your-deeplink";
    // Trustly and integration context
    establishDataValues["metadata.trustlyContext"] = "new";
    establishDataValues["metadata.integrationContext"] = "SecureBrowser";
    establishDataValues["returnUrl"] = "https://YOURDOMAIN.com/return";
    establishDataValues["cancelUrl"] = "https://YOURDOMAIN.com/cancel";
    
    return establishDataValues;
}
```

### Flutter implementation example (Dart)

```dart
Map<String, String> getEstablishDataValues() {
    final Map<String, String> establishDataValues = {};
    // Merchant Credentials & Session Setup
    establishDataValues['accessId'] = 'ACCESS_ID';
    establishDataValues['merchantId'] = 'MERCHANT_ID';
    establishDataValues['merchantReference'] = 'MERCHANT_REFERENCE';
    establishDataValues['requestSignature'] = 'REQUEST_SIGNATURE';
    establishDataValues['env'] = 'sandbox'; // Use "production" for live environments
    // Transaction details
    establishDataValues['amount'] = '10.00';
    establishDataValues['currency'] = 'USD';
    establishDataValues['paymentType'] = 'Retrieval';
    establishDataValues['paymentProviderId'] = 'PAYMENT_PROVIDER_ID';
    establishDataValues['description'] = 'Flutter InAppBrowser';
    // Customer information
    establishDataValues['customer.name'] = 'John Smith Flutter';
    establishDataValues['customer.phone'] = '2145553434';
    establishDataValues['customer.email'] = 'jsmith@email.com';
    establishDataValues['customer.address.address1'] = '2000 Broadway Street';
    establishDataValues['customer.address.city'] = 'Redwood City';
    establishDataValues['customer.address.state'] = 'CA';
    establishDataValues['customer.address.zip'] = '94063';
    establishDataValues['customer.address.country'] = 'US';
    // App/Universal link routing
    establishDataValues['metadata.deepLinkUrl'] = 'https://YOURDOMAIN.com/your-deeplink';
    // Trustly & Integration Context
    establishDataValues['metadata.trustlyContext'] = 'new';
    establishDataValues['metadata.integrationContext'] = 'SecureBrowser';
    establishDataValues['returnUrl'] = 'https://YOURDOMAIN.com/return';
    establishDataValues['cancelUrl'] = 'https://YOURDOMAIN.com/cancel';
    
    return establishDataValues;
}
```

## Configure the environment URL and presentation options

Route your requests to the appropriate environment by adding the corresponding endpoint to your application configuration:

* **Sandbox:** `https://sandbox.paywithmybank.com/frontend/mobile/establish`
* **Production:** `https://trustly.one/frontend/mobile/establish`

Control the presentation of the bank selection screen by appending the `widget` parameter to your configuration URL:

* `widget=true`: Renders the Bank Selection Widget followed by the Checkout Lightbox.
* `widget=false`: Bypasses the widget and renders the Checkout Lightbox directly.

## Launch the secure system browser session

Launch the finalized URL combining the base endpoint, the `widget` parameter, and the `token` parameter (containing your URL-safe Base64 string) using a secure system browser session based on your development stack.

* **Flutter:** Use an in-app browser plugin supporting system-level sheets (such as `flutter_custom_tabs` or `url_launcher` configured for an in-app view).
* **Xamarin / MAUI:** Utilize the `WebAuthenticator` API from `Microsoft.Maui.Authentication` or `Xamarin.Essentials`.
* **React Native:** Use a library that wraps authentication sessions, such as `expo-web-browser` or `react-native-inappbrowser-reborn`.
* **iOS:** Use `ASWebAuthenticationSession`.
* **Android:** Use a `CustomTabsIntent` session (Chrome Custom Tabs).

### iOS example

```swift
import AuthenticationServices

private var webSession: ASWebAuthenticationSession!

private func buildASWebAuthenticationSession(url: URL, callbackURL: String) {
    webSession = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL)
    // Add basic configurations
    webSession.prefersEphemeralWebBrowserSession = true
    // Assign the ASWebAuthentication 
    webSession.presentationContextProvider = self
    webSession.start()
}
```

### Android example

```kotlin
import androidx.browser.customtabs.CustomTabsIntent
import android.net.Uri
import android.content.Context

fun launchUrl(context: Context, url: String) {
    val customTabsIntent = CustomTabsIntent.Builder().build()
    customTabsIntent.intent.setPackage("com.android.chrome")
    customTabsIntent.launchUrl(context, Uri.parse(url))
}
```

## Process the redirect and verify signatures

When Trustly triggers the deep link back to your app, intercept the incoming URL and extract the query parameters to update your system state.

### Example redirect link

```text
https://YOURDOMAIN.com/your-deeplink?transactionId=123&status=2&trustlyContext=abc
```

### Parameters to extract

* `status`: The final checkout status. A value of `2` indicates success.
* `transactionId`: Trustly's unique tracking identifier for this specific transaction.
* `trustlyContext`: The persistent user session token.

## Manage user sessions with `trustlyContext`

The `trustlyContext` parameter identifies returning users to streamline subsequent checkouts. Determine the appropriate value for your backend payload using this logic:

* **First transaction (No prior session):** `"new"`
* **Subsequent transactions (Returning user):** Pass the last saved `trustlyContext` string

### Session lifecycle management

To ensure optimal recognition of returning users, implement this four-step lifecycle process in your application:

1. **Transmit:** Pass the current `trustlyContext` token in the `metadata` payload of every initialization request.
2. **Capture:** Extract the `trustlyContext` string from the incoming redirect URL query parameters.
3. **Persist:** Save the extracted token locally in secure device storage for future checkouts.
4. **Fallback:** Retain your existing local token if an inbound redirect does not provide a new `trustlyContext` parameter. Do not manually modify the token value.