Quick Start
Platform Examples
Checkout Customization
Mobile Recipes
start(...) call, and each one includes abandoned-session recovery. Build the flow by hand only if none of the SDKs fits your stack.Prerequisites
Before you start, you need:- A Dodo Payments account.
- An API key from Developer → API Keys and a webhook signing secret from Developer → Webhooks.
- An Android, iOS, React Native, or Flutter app.
- A backend server that creates checkout sessions. The API key stays on this server.
Integration Workflow
Your backend makes every Dodo Payments API call. Your app only asks your backend for a checkout URL, opens it, and shows the result.status in the deep link tells your app what to show the customer. It is not proof of payment. Grant access from the payment.succeeded or subscription.active webhook on your backend, not from the mobile result.Backend: Create Checkout Session
checkout_url to the app. Set the session’s return_url to the deep link your app registers, for example myapp://checkout/return.Checkout Session API Docs
Mobile: Get Checkout URL
userSessionToken is that token and CheckoutResponse is your own response type.- iOS (Swift)
- Android (Kotlin)
- React Native (JavaScript)
- Flutter (Dart)
Mobile: Open Checkout in Browser
Pick your mobile SDK
Backend: Handle Payment Completion
payment.succeeded or subscription.active webhook. Use the result from the return URL only to update the app’s screen.Choose Your SDK
Every mobile SDK has the same contract. Onestart(...) call opens Dodo Payments hosted checkout in the platform’s system browser surface and returns a typed CheckoutResult whose status is succeeded, failed, cancelled, pending, or expired. No SDK holds an API key or calls the Dodo Payments API, and all four support abandoned-session recovery.
Android
com.dodopayments.api:checkout-android opens a Custom Tab. Requires minSdk 23.iOS
dodopayments-mobile-sdk-ios opens SFSafariViewController. Requires iOS 16+.React Native
@dodopayments/react-native-checkout, a Turbo Module over both native cores. Requires React Native 0.77+ with the New Architecture.Flutter
dodopayments_checkout, a Pigeon channel over both native cores. Requires Flutter 3.44+.Registering a Callback URL Scheme
All four SDKs return control to your app through a custom URL scheme that you choose, for examplemyapp://checkout/return. Register it once per platform:
- Android
- iOS
- Expo
returnUrl.checkout_url in the platform’s system browser surface (a Custom Tab on Android, SFSafariViewController on iOS), intercept the navigation to your return_url, and read the status and payment_id query parameters. The SDKs do this for you.Appearance Customization
Every SDK accepts an optionalcustomization parameter on start(...) or CheckoutParams. It controls the system browser surface: the toolbar, the buttons, and how the browser is presented. The checkout page’s own theme is separate. You set it on your server with customization.theme_config when you create the checkout session.
The options are grouped by platform, because a Custom Tab on Android and SFSafariViewController on iOS expose different native controls. Every field is optional. An unset field leaves the platform’s own default in place.
Android - Custom Tab
Android - Custom Tab
default shows the system “X” icon; back draws a back arrow instead.iOS - SFSafariViewController
iOS - SFSafariViewController
pageSheet presents checkout as a card that the customer can swipe to dismiss. fullScreen covers the whole screen.presentationStyle is fullScreen. With pageSheet, the bars stay pinned.android and ios option groups. The native SDKs take only their own platform’s options.
- React Native
- Flutter
- Android (Kotlin)
- iOS (Swift)
Checkout Page Customization
The checkout page itself (which fields appear, the theme, and which payment methods show) is set on your server when you create the checkout session. Appearance Customization covers only the browser surface around it. The parameters below have the most effect on mobile conversion. Các tham số này nằm ở ba vị trí trong yêu cầu checkout session: cấp cao nhất, trongcustomization hoặc trong feature_flags. Cột Vị trí cho biết object tương ứng với từng tham số. Đặt mỗi tham số vào object được chỉ định, vì tham số nằm sai object sẽ không có tác dụng.

show_order_details: false moves the contact and payment fields above the fold, instead of behind the order summary.
minimal_address: true to collect only a postcode instead of the full street, city, and state fields:

minimal_address: true reduces the billing address to a single postcode field.
theme: "system" so the checkout follows the device’s light or dark mode preference:

With theme: system, the checkout follows the device's light or dark appearance automatically.
Full checkout session parameter reference
Mobile-Optimized Recipes
Each recipe is a complete checkout session request that your backend sends. Pick the one that matches your scenario and replace the product ID with your own. The Node.js and Python clients are set up in the first recipe, and the other recipes reuse them.Minimal Mobile Checkout - fastest path to payment
Minimal Mobile Checkout - fastest path to payment
- Node.js SDK
- Python SDK
One-Click Returning Customer - saved card, instant confirmation
One-Click Returning Customer - saved card, instant confirmation
customer_id, their saved payment_method_id, and confirm: true to skip the checkout form. With a payment_method_id, the session charges the saved method directly and returns no checkout_url, so your app has nothing to open. Learn the outcome from webhooks.- Node.js SDK
- Python SDK
payment.succeeded webhook. Any status your app shows is a UI hint only.Subscription with Free Trial - trial before first charge
Subscription with Free Trial - trial before first charge
trial_period_days sets the trial length for this session.- Node.js SDK
- Python SDK
subscription.active webhook, not when the mobile SDK returns. For the full webhook flow, see the Subscription Integration Guide.On-Demand Mandate - save a card for future variable charges
On-Demand Mandate - save a card for future variable charges
- Node.js SDK
- Python SDK
Subscription Flows from Mobile
A mobile app starts a subscription with the same checkout session flow as a one-time payment. The SDK opens hosted checkout, the customer subscribes, and your app handles the deep-link return. Your backend manages the rest of the subscription lifecycle.Regular Recurring Subscriptions
For billing at a fixed interval, such as monthly or yearly, create a checkout session with a subscription product and a deep-linkreturn_url. Your backend receives subscription.active when the subscription starts.
On-Demand Subscriptions
An on-demand subscription authorizes a customer’s payment method once, so you can charge variable amounts later. Use it for wallet top-ups, pay-as-you-go, and any charge whose amount you don’t know in advance. For the full request body, see the On-Demand Mandate recipe. On mobile, keep these points in mind:- Set
show_on_demand_tag: falseso the checkout page doesn’t show subscription or on-demand wording. Customers who save a card for top-ups don’t expect subscription terms. - After the customer authorizes the mandate, your backend receives
subscription.active. Store thesubscription_id, because every later charge uses it.
Subscription with Free Trial
To offer a trial before the first charge, passsubscription_data.trial_period_days in the checkout session. The customer authorizes a payment method at signup, and Dodo Payments charges it when the trial ends. For the full request body, see the Subscription with Free Trial recipe.
Upgrades and Downgrades
Your backend changes plans through the API, not through a new checkout session. Dodo Payments calculates proration with the proration mode you choose. To let customers change plans themselves, link to the Customer Portal.Subscription Integration Guide
On-Demand Subscriptions
Upgrade / Downgrade
Customer Portal
Reducing Checkout Drop-Offs
Trên màn hình nhỏ, việc điền từng trường biểu mẫu sẽ tốn nhiều công sức hơn. Các cài đặt checkout session bên dưới giúp rút gọn biểu mẫu và giảm tỷ lệ người dùng bỏ dở.Optimize the Form
These settings shorten the checkout form on mobile:Pre-Fill Customer Data
Each field you pre-fill is one the customer doesn’t have to type:- New customers: set
customer.emailandcustomer.namefrom your auth session. - Returning customers: set
customer.customer_idto use the customer’s stored details. - Currency: pass
billing_currencyandbilling_address.countrytogether.
Recovery Tools
Recovery tools bring back customers whose checkout or renewal didn’t complete:Abandoned Cart Recovery
Payment Retries
Subscription Dunning
Recovery Overview
Các phương pháp hay nhất
- Bảo mật: Không bao giờ đưa API key vào ứng dụng của bạn. Tạo checkout session trên backend và chỉ truyền
checkout_urlcho ứng dụng. - Quyền hạn: Xem
CheckoutResult.statusnhư một gợi ý về giao diện người dùng. Chỉ cấp quyền sau khi backend xác nhận thanh toán. - Trải nghiệm người dùng: Hiển thị trạng thái đang tải trong khi backend tạo session. Đừng coi
cancelledlà lỗi, vì thanh toán vẫn có thể đã thành công. - Kiểm thử: Sử dụng chế độ test và thẻ test, đồng thời kiểm tra toàn bộ quy trình return URL trên thiết bị thật cũng như trình mô phỏng.
- Tỷ lệ chuyển đổi: Thiết lập
show_order_details: falsevàminimal_address: true. Kết hợp lại, chúng đưa các phương thức thanh toán lên phần đầu màn hình và loại bỏ hầu hết các trường địa chỉ. - Tiền tệ: Truyền cả
billing_currencyvàbilling_address.country. Nếu thiếu một trong hai, Adaptive Currency có thể chọn tiền tệ thanh toán dựa trên địa chỉ IP của khách hàng. - Thanh toán theo nhu cầu: Thiết lập
show_on_demand_tag: falsekhi bạn chỉ sử dụng subscription theo nhu cầu để lưu thẻ. Khách hàng nạp tiền vào ví sẽ không mong đợi nội dung về subscription. - Khôi phục: Bật Abandoned Cart Recovery trong dashboard để gửi email cho những khách hàng không hoàn tất checkout.
Khắc phục sự cố
Các vấn đề thường gặp
- Callback không bao giờ đến: Scheme trong
returnUrlphải khớp với scheme bạn đã đăng ký. Trên Android, đó là manifest placeholderdodoCallbackScheme. Trên iOS, đó là URL typeInfo.plist. Ứng dụng React Native và Flutter cần cả hai, còn trong Expo, config plugin sẽ thiết lập cả hai. - Checkout quay lại trình duyệt thay vì ứng dụng của bạn (iOS): Ứng dụng của bạn không chuyển tiếp URL đến. Hãy gọi
DodoCheckout.handleOpenURL(url)từ.onOpenURL,scene(_:openURLContexts:)hoặc listenerLinkingcủa React Native. PLATFORM_ERRORtrên Android: Nguyên nhân phổ biến nhất là scheme không khớp. Lỗi này cũng xuất hiện khiMainActivitycủa bạn thiết lậpandroid:taskAffinity=""(giá trị mặc địnhflutter create), khiến một số bản build Android của OEM làm mất checkout đang thực hiện.ALREADY_IN_PROGRESS: Một checkout vẫn đang mở. Hãy chờ checkout trước đó hoàn tất hoặc đóng nó trước khi bắt đầu checkout khác.- Build thất bại với placeholder chưa được phân giải: Bạn đã thêm Android SDK nhưng chưa thiết lập
manifestPlaceholders["dodoCallbackScheme"]. - Thanh toán thành công nhưng quyền truy cập chưa được cấp: Ứng dụng của bạn cấp quyền truy cập dựa trên kết quả từ mobile. Thay vào đó, hãy cấp quyền truy cập từ webhook
payment.succeededhoặcsubscription.active. - Apple Pay hoặc Google Pay không xuất hiện trên mobile: Kiểm tra xem checkout có đang tải bên trong embedded WebView hay không (
WKWebViewhoặc AndroidWebView). Hãy mở bằng SDK hoặc trong giao diện trình duyệt hệ thống: Custom Tab trên Android, hoặcSFSafariViewControllerhayASWebAuthenticationSessiontrên iOS.
Tài nguyên bổ sung
- Hướng dẫn tích hợp thanh toán
- Tài liệu Webhook
- Quy trình kiểm thử
- Câu hỏi thường gặp về kỹ thuật
- Tùy chỉnh Checkout Session
- Subscription theo nhu cầu
- Nâng cấp/Hạ cấp Subscription
- Khôi phục giỏ hàng bị bỏ quên
- Customer Portal
