Skip to main content
Subotiz supports completing payments inside your own iOS / Android app. This page covers the overall approach, how to choose an integration mode, the supported payment methods, the integration steps, and the constraints that apply.
Who this is for: Developers (client + server) who need to integrate Subotiz payments inside their own iOS / Android app.What you will build: Launching the Subotiz checkout page inside your app, receiving the payment result, and confirming the order via webhook.Prerequisites: A Subotiz merchant account with a Secret API Key and a webhook signing key; a server environment capable of receiving webhooks.Scope: In-app payment integration. Web / H5 integration and merchant-dashboard payment method configuration are out of scope.

Overview

In-app payments use the link-to-checkout model: your server creates a Checkout Session, and your app opens the Subotiz checkout page with the system browser inside the app. The checkout page is presented as an overlay on top of your app, so the user never leaves your app. Once payment is complete the browser closes and hands control back to the app; the order status is determined by the webhook. The integration consists of four steps, with responsibilities split as follows.
In this model your app contains no payment logic — it never holds the Secret API Key and never touches card data, so it stays out of PCI scope.Payment methods take effect as soon as they are enabled in the merchant dashboard, so adding one requires no app release; and because the checkout page is driven by the system browser, it automatically shares cookies and the complete web platform, so wallets and 3DS are more compatible than in other containers.

Three Design Principles

  1. The session is created by your server. The app never holds the Secret API Key; amounts and products are decided server-side, which prevents client-side tampering.
  2. The webhook is the single source of truth for order status. Fulfillment and entitlement activation must rely on the webhook, not on the return received by the app. The return only triggers UI.
  3. You must use the system in-app browser. It shares system cookies and supports Apple Pay / Google Pay. Do not host the checkout page in a bare WebView that allows JS injection.

First, Choose an Integration Mode

There are two integration modes for the app scenario, and their Apple Pay support differs. Decide before you start development.
Integration into native app screens is not supported. None of the three Subotiz Checkout integration forms can render a payment form or wallet button directly inside a native app screen. Payment must be hosted by the system in-app browser.
For the app scenario, Hosted is the recommended mode across the board.If any of your users are on devices below iOS 17 and Apple Pay is a primary payment method, you must use Hosted (Hosted supports all iOS versions).The Embedded Form additionally requires you to build your own host page and implement cross-window communication. And since Hosted already appears as an overlay inside the app without the user leaving it, the Embedded Form’s “stay on your own page” advantage does not apply here.

Supported Payment Methods

The table below reflects support in the in-app browser scenario. The payment methods actually available are determined by your merchant configuration, so rely on the payment_methods returned by the create session API.
Subotiz Payments runs on different underlying acquiring channels, and the available payment methods differ accordingly — methods marked “Depends on the acquiring channel” are not available to every merchant. Always rely on the payment_methods returned by the create session API; do not hardcode a payment method list from this table.For other third-party channels (Airwallex, Checkout, Oceanpayment, and so on), please contact Subotiz to confirm in-app support.

Integration Steps

1

Server Setup

Configure the following environment variables on your server. Do not bundle them into the app.
2

Step 1: Create a Checkout Session (server)

When the customer taps buy in the app, your server calls the Subotiz API to create a Checkout Session. Set return_url and cancel_url to return addresses on your own domain.

Key Parameters

  • order_id: Your platform’s internal order ID, used for subsequent business data correlation
  • integration_method: Set to hosted to use the hosted page integration method
  • return_url: The page the customer is redirected to after a successful payment; in the app scenario this should point to your Universal Link / App Link
  • cancel_url: The page the customer is redirected to if they cancel payment
Observable result: The API returns session_url (the checkout URL), in the form https://checkout.subotiz.com/m/{mid}/checkout/{sessionId}.
The Secret API Key and the webhook signing key live on the server only and must never be bundled into the app. Amounts and products must be decided server-side.
3

Step 2: Open the Checkout Page In-App (app)

Once the app has the session_url, open it with the in-app browser container provided by the system.
Do not use WKWebView / Android WebView to host the checkout page. Reasons:
  1. ApplePaySession cannot be started inside a WKWebView because of security origin restrictions, so Apple Pay is simply unavailable;
  2. Redirect-based authentication such as 3DS and OAuth is not recommended inside a WebView, and engine fragmentation makes it prone to failure or hanging;
  3. The host can inject JS to steal payment input, which widens your PCI scope;
  4. The browser session is not shared, so most payment methods do not support this scenario — Link / PayPal / Klarna / Amazon Pay are all unavailable in an in-app WebView, and Google Pay requires additional Android WebView configuration before it can work at all.
Observable result: The checkout page appears as an overlay on top of the app, and the customer can see the list of payment methods.
4

Step 3: Receive the Return (app)

After payment completes, Subotiz redirects to the return_url (or cancel_url) you passed when creating the session; the in-app browser then closes and control returns to the app.
  • iOS: Implement onOpenURL on the view hosting the checkout page, and dismiss the Safari view once the return arrives.
  • Android: Register the Activity that receives the return in AndroidManifest.xml (launchMode="singleTask" plus an intent-filter with autoVerify).
5

Step 4: Confirm the Order (server + app)

Implement a webhook endpoint on your server. This is the single source of truth for order status. Three things to get right:
  1. Verify the signature — validate X-Signature as described in Webhook reliability verification. Verification needs the raw body, so do not parse the JSON first;
  2. Deduplicate idempotently — deduplicate by event id, because the same event may be delivered more than once;
  3. Return 200 quickly — move slow business processing off the request path instead of blocking the response.
Implement polling on the app side: once the return arrives, call your own server to query the order status until it reaches a terminal state or times out.
The webhook and the return are two independent paths. Even if the return never arrives (the user manually closed the browser, a network error, and so on), the webhook still marks the order as paid, and the user gets the correct status from polling the next time they open the app. Polling is therefore not optional.

Constraints

Mandatory Requirements

Recommendations and Notes

Verification Checklist

Once the integration is complete, confirm each of the following:
  • The server can successfully create a session and return session_url
  • Opening the checkout page in-app presents it as an overlay, and the user does not leave the app
  • The expected payment methods are visible on the checkout page (matching payment_methods)
  • The Apple Pay button is visible and can be launched on a real iOS device (the test amount must be above your channel’s minimum charge, see L2)
  • After a successful payment the browser closes automatically and returns to the app
  • The server receives the webhook, signature verification passes, and repeated deliveries do not cause duplicate fulfillment
  • When the browser is closed manually and no return is triggered, the app still gets the correct order status through polling after being reopened
  • After a cancelled payment the order status is correct and no entitlement is granted by mistake