Mobile web

Build bank authorization workflows without a mobile SDK.
View as Markdown

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.

Trustly recommends using the Trustly iOS, Android, or 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 (iOS) and Handling Android App Links (Android).

Integration workflow

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

StepActionDescription
1GenerateThe backend server generates the required transaction parameters and signs the payload.
2SerializeThe backend converts the payload to a UTF-8 JSON string, base64-encodes the token, and passes it to the mobile app.
3Launch and AuthThe 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.
4RedirectTrustly executes a deep-link redirect (Universal Link or App Link) back to the mobile app.
5ForwardThe mobile app intercepts the redirect query parameters and forwards them to the backend server for verification.
6ValidateThe backend validates the cryptographic HMAC signature of the returned parameters (excluding the trustlyContext).
7UpdateThe 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

ParameterTypeDescription
accessIdStringYour unique merchant access identifier.
merchantIdStringYour unique merchant identifier.
amountStringThe transaction amount (e.g., "10.00").
currencyStringThe ISO currency code (e.g., "USD").
paymentTypeStringThe type of payment processing requested.
merchantReferenceStringYour internal tracking identifier for the transaction.
requestSignatureStringThe HMAC-SHA256 signature generated by your backend.
returnUrlStringThe Universal Link (iOS) or App Link (Android) used for successful completions.
cancelUrlStringThe 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#)

1using System.Collections.Generic;
2
3private Dictionary<string, string> GetEstablishDataValues()
4{
5 var establishDataValues = new Dictionary<string, string>();
6 // Merchant Credentials & Session Setup
7 establishDataValues["accessId"] = "ACCESS_ID";
8 establishDataValues["merchantId"] = "MERCHANT_ID";
9 establishDataValues["merchantReference"] = "MERCHANT_REFERENCE";
10 establishDataValues["requestSignature"] = "REQUEST_SIGNATURE";
11 establishDataValues["env"] = "sandbox"; // Use "production" for live environments
12 // Transaction details
13 establishDataValues["amount"] = "10.00";
14 establishDataValues["currency"] = "USD";
15 establishDataValues["paymentType"] = "Retrieval";
16 establishDataValues["paymentProviderId"] = "PAYMENT_PROVIDER_ID";
17 establishDataValues["description"] = "Xamarin InAppBrowser";
18 // Customer information
19 establishDataValues["customer.name"] = "John Smith Xamarin";
20 establishDataValues["customer.phone"] = "2145553434";
21 establishDataValues["customer.email"] = "jsmith@email.com";
22 establishDataValues["customer.address.address1"] = "2000 Broadway Street";
23 establishDataValues["customer.address.city"] = "Redwood City";
24 establishDataValues["customer.address.state"] = "CA";
25 establishDataValues["customer.address.zip"] = "94063";
26 establishDataValues["customer.address.country"] = "US";
27 // App/Universal link routing
28 establishDataValues["metadata.deepLinkUrl"] = "https://YOURDOMAIN.com/your-deeplink";
29 // Trustly and integration context
30 establishDataValues["metadata.trustlyContext"] = "new";
31 establishDataValues["metadata.integrationContext"] = "SecureBrowser";
32 establishDataValues["returnUrl"] = "https://YOURDOMAIN.com/return";
33 establishDataValues["cancelUrl"] = "https://YOURDOMAIN.com/cancel";
34
35 return establishDataValues;
36}

Flutter implementation example (Dart)

1Map<String, String> getEstablishDataValues() {
2 final Map<String, String> establishDataValues = {};
3 // Merchant Credentials & Session Setup
4 establishDataValues['accessId'] = 'ACCESS_ID';
5 establishDataValues['merchantId'] = 'MERCHANT_ID';
6 establishDataValues['merchantReference'] = 'MERCHANT_REFERENCE';
7 establishDataValues['requestSignature'] = 'REQUEST_SIGNATURE';
8 establishDataValues['env'] = 'sandbox'; // Use "production" for live environments
9 // Transaction details
10 establishDataValues['amount'] = '10.00';
11 establishDataValues['currency'] = 'USD';
12 establishDataValues['paymentType'] = 'Retrieval';
13 establishDataValues['paymentProviderId'] = 'PAYMENT_PROVIDER_ID';
14 establishDataValues['description'] = 'Flutter InAppBrowser';
15 // Customer information
16 establishDataValues['customer.name'] = 'John Smith Flutter';
17 establishDataValues['customer.phone'] = '2145553434';
18 establishDataValues['customer.email'] = 'jsmith@email.com';
19 establishDataValues['customer.address.address1'] = '2000 Broadway Street';
20 establishDataValues['customer.address.city'] = 'Redwood City';
21 establishDataValues['customer.address.state'] = 'CA';
22 establishDataValues['customer.address.zip'] = '94063';
23 establishDataValues['customer.address.country'] = 'US';
24 // App/Universal link routing
25 establishDataValues['metadata.deepLinkUrl'] = 'https://YOURDOMAIN.com/your-deeplink';
26 // Trustly & Integration Context
27 establishDataValues['metadata.trustlyContext'] = 'new';
28 establishDataValues['metadata.integrationContext'] = 'SecureBrowser';
29 establishDataValues['returnUrl'] = 'https://YOURDOMAIN.com/return';
30 establishDataValues['cancelUrl'] = 'https://YOURDOMAIN.com/cancel';
31
32 return establishDataValues;
33}

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

1import AuthenticationServices
2
3private var webSession: ASWebAuthenticationSession!
4
5private func buildASWebAuthenticationSession(url: URL, callbackURL: String) {
6 webSession = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURL)
7 // Add basic configurations
8 webSession.prefersEphemeralWebBrowserSession = true
9 // Assign the ASWebAuthentication
10 webSession.presentationContextProvider = self
11 webSession.start()
12}

Android example

1import androidx.browser.customtabs.CustomTabsIntent
2import android.net.Uri
3import android.content.Context
4
5fun launchUrl(context: Context, url: String) {
6 val customTabsIntent = CustomTabsIntent.Builder().build()
7 customTabsIntent.intent.setPackage("com.android.chrome")
8 customTabsIntent.launchUrl(context, Uri.parse(url))
9}

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.

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.