Skip to content

Bank app HTTPS deeplinks

This page describes how a merchant mobile app or website should open a bank app payment URL when Flitt returns a bank HTTPS deeplink in the checkout_url parameter of the POST /api/checkout/url response.

This flow is in scope only when the merchant sends both parameters during order creation to obtain a single bank HTTPS deeplink:

  • payment_systems = opb|installments
  • payment_method = tbc|bog|credo|liberty // a single bank obnly

In this case Flitt always returns a bank authorization deeplink instead of a Flitt hosted checkout URL.

Regular hosted checkout URLs are outside the scope of this page.

The bank app owns the deeplink handling and payment confirmation. The merchant is responsible for opening the HTTPS URL correctly and then verifying the payment result through Flitt order status and server callbacks.

The customer must trigger the bank app link, not your code

The merchant mobile app or website should open a deep link only as the immediate result of the customer tapping a visible, clearly labelled control — such as a Pay or Continue in bank app button — on the payment screen they are looking at right now.

If deeplink opening is not triggered by a customer action on a visible control, it can fail to be handled by the bank app and can open the web version of internet banking.

So, your app or website must still wait for the customer's tap before opening the bank app and should not open it just after obtaining it from the Flitt endpoint with auto-redirect or auto-submit.

Do not open it when your app or web page launches, from a push notification, a background refresh, a hidden redirect, a timer, an automatic page load, or a silent WebView navigation.

This applies to native mobile apps, mobile websites, and merchant pages shown inside a WebView alike: if it is not a deliberate customer tap, it is not allowed.

Follow required behaviour

  • Use the exact checkout_url value returned by Flitt through the merchant backend. Bank app deeplinks in this flow are HTTPS URLs, not custom app schemes.
  • Do not construct bank payment URLs in the app. Do not rewrite, decode and re-encode, shorten, or append parameters.
  • Do not maintain a merchant-side allow-list of bank hosts or paths for validation. Flitt controls the bank URL returned for the payment, and more banks can be enabled in the future.
  • Open the bank URL only from a visible payment surface and only after mandatory user intent.
  • Do not place the bank URL in an iframe. If a browser or WebView is used, open the bank URL from the currently visible page, not from an embedded frame.
  • Do not render bank authentication pages inside a merchant WebView, iframe, or hidden browser view.
  • On mobile, open the HTTPS bank URL through the operating system so the installed bank app can handle it. This applies to both WebView navigation handling and native payment screens: on iOS, use the system URL opening mechanism; on Android, use an external ACTION_VIEW intent.
  • On desktop, render a QR code with the exact checkout_url instead of trying to open a bank app locally.
  • Treat the client return to the merchant app as informational. Confirm the final order state through Flitt callbacks or order status requests.

Because the bank deeplink is an HTTPS URL, mobile integrations commonly open it from a visible WebView or from a visible native screen. Both are acceptable; they differ only in how the app hands the URL to the operating system.

If your visible screen is an embedded WebView

An embedded WebView (WKWebView on iOS, android.webkit.WebView on Android) will try to load the bank authentication page inside your app unless you intercept it. Use the WebView only as the visible screen that starts the flow, then hand the bank URL to the OS:

  • On iOS, use WKNavigationDelegate to allow or cancel WebView navigation before opening the bank URL externally.
  • On Android, a WebView without a WebViewClient asks the system to choose a handler. If the app provides a WebViewClient, app code decides: return false to let the WebView load the URL, or open the URL externally and return true to stop WebView loading.
  • When opening externally, open the URL through the operating system URL or intent mechanism instead of rendering bank authentication inside the WebView.

The WebView must not silently continue loading the bank authorization page. It can remain available for the return page or payment result page after the external bank app flow. Do not use a hidden WebView to trigger the deeplink; if the backend response is ready before the customer's intent is immediate, show a visible Continue in bank app action first.

If your visible screen is native (or a system browser tab)

A native payment screen (a UIViewController on iOS, an Activity or Fragment on Android) has no embedded web content, so there is no navigation to intercept — the app opens the bank deeplink directly through the operating system external URL or intent mechanism (step 4 above).

If you present a system browser tab instead of a native screen (SFSafariViewController on iOS, Chrome Custom Tabs on Android), it is acceptable only when it stays visible and user-facing:

  • Present the browser tab visibly and modally as part of the checkout flow.
  • Do not hide it, obscure it, or embed it as a child view controller.
  • Do not use it as a hidden automation surface for opening the bank app.
  • If the app must consistently decide whether a WebView loads the bank URL or opens it externally, use a visible WebView with explicit navigation handling instead.

Render QR code on desktop

Desktop browsers usually cannot open a mobile banking app for the customer. When the customer is on desktop and Flitt returns a bank HTTPS checkout_url for the selected payment_method, render a QR code instead of redirecting the desktop browser to the bank URL.

The QR flow should follow these rules:

  • Encode the exact checkout_url returned by Flitt. Do not shorten, wrap, proxy, or modify the URL.
  • Show the QR code on the active payment page, with clear instruction to scan it on a mobile device where the bank app is installed.
  • Keep the desktop order page in a pending state while the customer completes authentication on mobile.
  • Refresh the desktop state from the merchant backend, which should rely on Flitt callbacks or order status requests.
  • Handle expiry by showing retry or alternative payment options.
  • Do not mark the order as failed only because the QR code was not scanned or the desktop browser did not open a bank app.

The desktop QR code only helps the customer continue on a mobile device. The payment result still comes from Flitt status, not from the QR page itself.

Review bank URL examples

These examples show how Georgian bank HTTPS authorization URLs can look when returned in checkout_url for a selected payment_method. They are examples only. Do not use this list as a validation rule or a fixed allow-list, because Flitt can enable other banks or bank URL patterns in the future.

Bank Example HTTPS authorization URL shape
TBC https://api.tbcbank.ge/psd2/openbanking/oauth/authorize?...
Bank of Georgia (BOG) https://account-ob.bog.ge/auth/realms/bog/protocol/openid-connect/auth?...
Credo https://openbanking.credo.ge/ob-oauth2/authorize?...
Liberty https://openbankingauth.lb.ge/authorize/<auth_id>?...

Do not use iframes

Iframes are not supported for opening bank payment URLs.

  • An iframe can prevent the operating system from recognizing that a user is intentionally leaving the merchant app for the bank app.
  • A hidden or nested frame makes it unclear which party initiated the external-app opening.
  • Bank authentication and app-to-app payment approval must happen in the bank app, not inside merchant-controlled embedded content.
  • If the merchant website is opened inside a WebView, the bank URL must still be opened from the currently visible WebView page, not inside a nested frame.

Fallback handling

If the bank app cannot be opened:

  • Keep the order in a pending or retryable state until the backend confirms otherwise.
  • Show a visible message that the selected bank app is not available or the payment cannot be opened.
  • Let the customer choose another available payment method or retry after installing/updating the bank app.
  • Do not mark the order as failed only because the external app could not be opened; rely on Flitt status for the final result.

References

Flitt

  • Flitt: Create order for POST /api/checkout/url and the checkout_url response parameter.
  • Flitt: Open Banking for Georgian bank payment flow and payment_method values.
  • Flitt: Installments for installment payments that use payment_systems = installments and payment_method.

iOS

Android