Mobile SDKs
Futa’s Android and iOS SDKs open a payment’s hosted checkout full screen in the platform’s own web view inside your app. The web view loads the checkout’s origin and nothing else. They are not yet distributed: build them from source, as the last section says.
Create the payment for an app
Section titled “Create the payment for an app”Your server creates the payment with embedding for an app, and hands your app its checkout_url; the app never
holds your secret key.
{ "amount": 2500000, "currency": "CDF", "merchant_reference": "order-10482", "description": "Order 10482", "return_url": "https://shop.example/thanks", "expires_at": "2026-10-20T12:00:00Z", "embedding": { "mode": "app" }}An app payment’s pages are never framed by a web page. The Idempotency-Key binds embedding with the other terms,
and direct mode (method and msisdn) refuses it. Compute expires_at once per order, within the next 24 hours, as
the quick start says: the instant above is an example.
Android
Section titled “Android”Kotlin, Android 8.0 (API 26) and later, with the platform’s own WebView and no other library:
val session = FutaCheckout.open( activity, CheckoutOptions( checkoutOrigin = "https://checkout.sandbox.futa-app.com", checkoutUrl = checkoutUrl, returnUrl = "https://shop.example/thanks", onState = { state -> showProgress(state.payment, state.state, state.final) }, onClose = { closed -> readOrderFromServer() }, ),)checkoutOrigin is the checkout’s origin your app trusts: an https origin, or plain HTTP only in a debuggable app,
and only for the developer’s loopback with a port: 127.0.0.1, localhost or the emulator’s 10.0.2.2, as
http://10.0.2.2:18140 reaches the local sandbox’s checkout on the emulator’s host. The hosted sandbox’s checkout,
https://checkout.sandbox.futa-app.com, needs none of that: an emulator and a device reach it alike. checkoutUrl is
the payment’s checkout_url exactly as Futa issued it, and returnUrl, optional, its return_url, so going back to
your shop reads as returned. open returns a CheckoutSession, whose close() ends it as the back button does. The
session lives no longer than the activity it opened over: when that activity is destroyed, finishing or recreated by a
configuration change your app does not handle, such as a rotation, the session ends as closed; open a new one if the
payer is still to pay.
The Swift package FutaCheckout, iOS 16 and later, with no dependency:
let checkout = try FutaCheckout.open( from: viewController, options: CheckoutOptions( checkoutOrigin: "https://checkout.sandbox.futa-app.com", checkoutURL: checkoutURL, returnURL: "https://shop.example/thanks", onState: { state in showProgress(state) }, onClose: { closed in readOrderFromServer() } ))checkoutOrigin is an https origin, such as the hosted sandbox’s checkout above, or plain HTTP only for 127.0.0.1
or localhost with a port, which a simulator reaches and a device does not: http://127.0.0.1:18140 for the local
sandbox. It presents a CheckoutViewController full screen under the platform’s
navigation bar; its close() ends the session. The web view uses your app’s default website data store, never
Safari’s. openOutside, optional, decides how another site opens, UIApplication.open by default.
What your app hears
Section titled “What your app hears”onState gets the payment’s id, the state the checkout’s page shows and final, as the
embedded checkout describes them: advisory, so confirm the payment on your server by its
signed webhook or GET /v1/payments/{id}. onClose gets final as the checkout last said it, false
until then, and why the session ended: closed, returned or left. closed means the payer closed it or your app
did; returned, that the payer went back to your return_url (its origin and path); left, that they went to any
other site, the bank’s included.
What opens outside your app
Section titled “What opens outside your app”Only the checkout’s origin loads in the web view. Every other address opens outside it and ends the session: the
bank’s handoff, so bank credentials are never typed inside your app, your return address and any other site. On
Android it opens in the system browser, on iOS with UIApplication.open or your openOutside. A receipt opens
outside without ending the session: in the system browser on Android, in SFSafariViewController on iOS, or through
your openOutside when you set it. The payer’s method is never remembered on the device. Your app’s own policy must
allow plain HTTP too: its network security configuration on Android, App Transport Security on iOS.
Your app sees what the payer types
Section titled “Your app sees what the payer types”Your app owns the web view, so it can read what the payer types there, their phone number included, and inject script into the page, which a redirect to the hosted checkout never allowed. Treat what the payer types as you would your own form’s, and never record it. The bank’s handoff always opens outside the app for that reason.
Build them from source
Section titled “Build them from source”For sandbox testing, by those Futa has given access to Futa-payer-web: both live there, each its own build, outside the checkout’s:
- Android,
sdks/android. The library modulecheckout(com.futa.checkout.android). It needs JDK 17 or later, the Gradle 9.8.1 wrapper, the Android Gradle plugin 9.4.1 and Kotlin 2.4.21, which Gradle fetches, and an Android SDK with platform 35 and build-tools 36.0.0, named byANDROID_HOMEor alocal.properties. Every module Gradle resolves is checked against its SHA-256 ingradle/verification-metadata.xml../gradlew :checkout:testDebugUnitTestruns its tests. - iOS,
sdks/ios. The Swift package whose product isFutaCheckout, with no dependency, built with Xcode 26.swift testruns its tests.