Use this file to discover all available pages before exploring further.
Mobile applications can integrate OwnPay using the same REST API that powers web and server-side integrations. The key principle is that your mobile app never holds an API key: all authenticated requests to OwnPay are made by your backend server, which returns only the checkout_url to the app. The app then presents that URL in a WebView or an in-app browser, and your backend receives the payment.completed webhook independently of the mobile session.
Never embed your OwnPay API key inside a mobile app binary. Keys embedded in apps can be extracted through decompilation or memory inspection. All Authorization: Bearer requests must originate from your server.
The secure flow for a mobile payment looks like this:
App → Your backend: User taps “Pay”. The app sends the order details to your own API endpoint (e.g. POST /api/mobile/checkout).
Your backend → OwnPay: Your server calls POST /payments with your secret API key and includes a callback_url pointing to your webhook handler.
Your backend → App: Your server returns the checkout_url (and optionally the payment_id) to the app.
App: Opens checkout_url in a WebView or SFSafariViewController / Chrome Custom Tab.
Customer: Completes payment on the OwnPay hosted checkout page.
OwnPay → Your backend: Sends payment.completed webhook.
App: Polls GET /api/mobile/payment-status/{paymentId} (your backend), or listens via WebSocket / push notification, until the order is confirmed.
OwnPay’s hosted checkout pages are mobile-optimised and render correctly inside WKWebView (iOS) and WebView/Custom Tabs (Android). No special mobile SDK is required.
func pollPaymentStatus(paymentId: String, retries: Int = 10) { guard retries > 0 else { print("Polling timed out") return } guard let url = URL(string: "https://my-store.com/api/mobile/payment-status/\(paymentId)") else { return } URLSession.shared.dataTask(with: url) { data, _, _ in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let status = json["status"] as? String else { return } DispatchQueue.main.async { if status == "completed" { print("Payment confirmed!") // Navigate to success screen } else { // Wait 2 seconds and try again DispatchQueue.main.asyncAfter(deadline: .now() + 2) { self.pollPaymentStatus(paymentId: paymentId, retries: retries - 1) } } } }.resume()}
For production apps, replace polling with a push notification triggered by your webhook handler. When OwnPay delivers the payment.completed event to your server, send an APNs or FCM notification to the user’s device for instant confirmation.
Configure a deep-link redirect_url (e.g. myapp://checkout/return) so your app can detect when the customer completes payment and the hosted checkout redirects back:
// AndroidManifest.xml — inside your Activity declaration// <intent-filter>// <action android:name="android.intent.action.VIEW" />// <category android:name="android.intent.category.DEFAULT" />// <category android:name="android.intent.category.BROWSABLE" />// <data android:scheme="myapp" android:host="checkout" android:pathPrefix="/return" />// </intent-filter>// In your Activityoverride fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) intent?.data?.let { uri -> if (uri.host == "checkout" && uri.path == "/return") { val paymentId = getStoredPaymentId() // from your session paymentId?.let { verifyPayment(it) } } }}fun verifyPayment(paymentId: String) { // Call your backend, which calls GET /payments/{paymentId} on OwnPay viewModel.verifyPayment(paymentId)}
Never call GET /payments/{paymentId} directly from the Android or iOS app — that would expose your API key. Always proxy the verification call through your backend.
Mobile apps operate in environments where the user can close the app, switch to background, or lose network connectivity at any moment. Webhooks ensure your backend always receives the payment outcome regardless of what happens to the mobile session.
Recommended webhook-to-mobile notification flow
OwnPay sends payment.completed to your callback_url.
Your webhook handler verifies the transaction via GET /transactions/{trx_id}.
Your handler updates the order status in your database.
Your handler triggers a push notification (APNs for iOS, FCM for Android) to the user’s device.
The app receives the push notification and navigates to the order confirmation screen.
This flow works even if the app was backgrounded or terminated before the payment completed.
OwnPay retries failed webhook deliveries automatically. You can inspect all attempts — including payloads, response codes, and retry counts — via GET /webhooks/deliveries.