Native checkout SDKs for Dodo Payments' hosted checkout, for iOS, Android, React Native, and Flutter.
Each SDK opens the checkout in a system browser surface. SFSafariViewController
on iOS, a Custom Tab (androidx.browser.customtabs) on Android.
Swift (iOS)
// Package.swift
.package(url: "https://github.com/dodopayments/dodopayments-mobile-sdk-ios", from: "1.0.0")Kotlin (Android)
// build.gradle.kts
implementation("com.dodopayments.api:checkout-android:1.0.2")React Native
npm i @dodopayments/react-native-checkoutFlutter
# pubspec.yaml
dependencies:
dodopayments_checkout: ^1.0.0Check each SDK's README (linked below) for setup and usage.
| Platform | Package | Docs |
|---|---|---|
| iOS (Swift) | Swift Package Manager | dodopayments-mobile-sdk-ios/README.md |
| Android (Kotlin) | com.dodopayments.api:checkout-android |
kotlin/README.md |
| React Native | @dodopayments/react-native-checkout |
react-native/README.md |
| Flutter | dodopayments_checkout |
flutter/README.md |
React Native and Flutter are thin wrappers over the native iOS and Android cores — they carry no checkout logic of their own.
All four SDKs expose the same shape, so integrating one means you already understand the others:
- One call —
start(...)— that returns aCheckoutResultwith astatus(succeeded/failed/cancelled/pending/expired). - The result is a UI hint, not proof of payment. None of these SDKs call the Dodo API or hold an API key; grant access from your backend via webhook or by retrieving the payment with your secret key.
- An optional
onEventcallback for logging (opened/return_received/closed) — never authoritative. - A
CheckoutError/CheckoutExceptionfor misuse or platform failure only (INVALID_CHECKOUT_URL,INVALID_RETURN_URL,ALREADY_IN_PROGRESS,PLATFORM_ERROR). A user cancelling or a declined payment is always a result, never a thrown error. - Abandoned-session recovery, for every checkout that ends without the SDK
resolving its return URL to a durable outcome — the app killed mid-checkout,
a
cancelledresult, or apendingone.
See each SDK's README for the exact API and platform setup.
The SDK only ever learns the outcome from the return URL. A cancelled status
means the user dismissed the browser before that URL arrived, so the real state
is unknown — a user who pays and then closes the sheet while the hosted
"Payment Successful" page counts down its redirect lands here, exactly like a
user who closed it without paying.
Don't map cancelled to a failure screen. The SDK keeps the checkout session on
record for precisely this case: read it with getAbandonedSession(), resolve
sessionId against your backend, and show what comes back.
pending deserves the same treatment. Besides genuinely async methods, it is
the fallback for a missing or unrecognized status, so an unparseable return
URL lands there too — sometimes with no payment id either. The session is kept
on record for it as well.
dodopayments-mobile-sdk/
├── swift/ # iOS core (Swift Package). Git submodule → dodopayments-mobile-sdk-ios.
├── kotlin/ # Android core (Kotlin/Gradle). Published to Maven Central.
├── react-native/ # Turbo Module wrapper over the iOS/Android cores. Published to npm.
└── flutter/ # Pigeon wrapper over the iOS/Android cores. Published to pub.dev.
Apache License 2.0, see LICENSE for details.