Skip to main content

Quick Start

Triển khai tích hợp thanh toán trên thiết bị di động trong 4 bước đơn giản

Platform Examples

Ví dụ mã hoàn chỉnh cho Android, iOS, React Native và Flutter

Checkout Customization

Cấu hình theme, điền sẵn dữ liệu và 14 tham số dành riêng cho thiết bị di động

Mobile Recipes

Cấu hình checkout có thể sao chép-dán cho 5 tình huống phổ biến trên thiết bị di động
Dodo Payments cung cấp SDK checkout chính thức cho Android, iOS, React Native, và Flutter. Mỗi SDK đóng gói pattern được trình bày bên dưới (mở URL checkout, nhận kết quả trả về, phân tích kết quả) phía sau một lệnh gọi start(...) có kiểu duy nhất, đồng thời tích hợp sẵn khả năng khôi phục session bị bỏ dở. Chỉ sử dụng WebView thủ công nếu không SDK nào phù hợp với stack của bạn.

Điều kiện tiên quyết

Trước khi tích hợp Dodo Payments vào ứng dụng di động, hãy đảm bảo bạn có:
  • Tài khoản Dodo Payments: Tài khoản merchant đang hoạt động có quyền truy cập API
  • Thông tin xác thực API: API key và webhook secret key từ dashboard
  • Dự án ứng dụng di động: Ứng dụng Android, iOS, React Native hoặc Flutter
  • Backend Server: Để xử lý việc tạo checkout session một cách an toàn

Quy trình tích hợp

Tích hợp trên thiết bị di động tuân theo quy trình bảo mật gồm 4 bước, trong đó backend xử lý các lệnh gọi API còn ứng dụng di động quản lý trải nghiệm người dùng.
Deep-link status chỉ là gợi ý UI về nội dung hiển thị cho người dùng. Luôn cấp quyền từ webhook payment.succeeded / subscription.active trên backend - không bao giờ chỉ dựa vào kết quả trên thiết bị di động.
1

Backend: Create Checkout Session

Checkout Session API Docs

Tìm hiểu cách tạo checkout session trên backend bằng Node.js, Python và nhiều ngôn ngữ khác. Xem các ví dụ hoàn chỉnh và tài liệu tham chiếu tham số trong tài liệu Checkout Sessions API chuyên dụng.
Bảo mật: Checkout session phải được tạo trên backend server, không bao giờ trong ứng dụng di động. Điều này bảo vệ API key và đảm bảo quá trình validation chính xác.
2

Mobile: Get Checkout URL

Ứng dụng di động gọi backend để nhận URL checkout. Xác thực request này bằng session token riêng của người dùng đã đăng nhập.
Bảo mật: Ứng dụng di động chỉ giao tiếp với backend của bạn, không bao giờ trực tiếp với Dodo Payments API.
3

Mobile: Open Checkout in Browser

Mở URL checkout trong trình duyệt an toàn bên trong ứng dụng để xử lý thanh toán. Hoặc bỏ qua hoàn toàn phần thiết lập thủ công bằng SDK checkout chính thức dành cho nền tảng của bạn.

Pick your mobile SDK

Các bước cài đặt và hướng dẫn thiết lập cho Android, iOS, React Native và Flutter.
4

Backend: Handle Payment Completion

Xử lý việc hoàn tất thanh toán thông qua webhook và redirect URL để xác nhận trạng thái thanh toán.

Chọn SDK

Mọi SDK di động đều cung cấp cùng một contract: một lệnh gọi start(...) mở checkout được host bởi Dodo trong giao diện trình duyệt native của nền tảng và trả về CheckoutResult có kiểu, trong đó statussucceeded, failed, cancelled, pending hoặc expired. Không SDK nào chứa API key hoặc gọi Dodo Payments API, và cả bốn SDK đều hỗ trợ khôi phục session bị bỏ dở.

Android

com.dodopayments.api:checkout-android mở Chrome Custom Tab. Yêu cầu minSdk 23.

iOS

dodopayments-mobile-sdk-ios mở SFSafariViewController. Yêu cầu iOS 16+.

React Native

@dodopayments/react-native-checkout, Turbo Module hoạt động trên cả hai native core. Yêu cầu React Native 0.76+.

Flutter

dodopayments_checkout, kênh Pigeon hoạt động trên cả hai native core. Yêu cầu Flutter 3.44+.
status nhận được chỉ là gợi ý UI, không phải bằng chứng thanh toán. Xác nhận mọi thanh toán từ backend thông qua webhook payment.succeeded / subscription.active, hoặc truy xuất thanh toán bằng secret key.

Đăng ký Callback URL Scheme

Cả bốn SDK đều chuyển quyền điều khiển lại cho ứng dụng thông qua custom URL scheme do bạn chọn, ví dụ myapp://checkout/return. Đăng ký scheme này một lần cho mỗi nền tảng:
android/app/build.gradle
Manifest của chính SDK đã khai báo redirect activity, vì vậy bạn không cần thêm manifest XML.
Bạn muốn tự xây dựng? Mở checkout_url trong trình duyệt hệ thống của nền tảng (Android Custom Tabs / iOS SFSafariViewController) và chặn điều hướng đến return_url, sau đó đọc các query parameter statuspayment_id. Các SDK ở trên thực hiện chính xác việc này thay cho bạn.
Không mở checkout bên trong embedded WebView (WKWebView / Android WebView). Đây là vấn đề tích hợp di động phổ biến nhất: embedded WebView vô hiệu hóa Apple Pay và Google Pay, đồng thời có thể làm hỏng challenge 3-D Secure và autofill thẻ đã lưu - khiến khách hàng thấy ít phương thức thanh toán hơn và gặp nhiều lỗi hơn. Luôn sử dụng SDK hoặc mở checkout_url trong trình duyệt hệ thống (Custom Tabs / SFSafariViewController). Giao diện trình duyệt native này chính là lý do Apple Pay và Google Pay vẫn hoạt động.

Tùy chỉnh giao diện

Mọi SDK đều chấp nhận tham số tùy chọn customization trên start(...) / CheckoutParams để kiểm soát giao diện và hành vi của giao diện trình duyệt native - thanh công cụ, nút và cách hiển thị. Phần này tách biệt với theme riêng của trang checkout, được cấu hình phía server thông qua customization.theme_config trên checkout session. Các tùy chọn được nhóm theo nền tảng vì Android Custom Tab và iOS SFSafariViewController cung cấp các control native khác nhau. Tất cả field đều là tùy chọn; nếu bỏ qua hoàn toàn customization, giao diện mặc định của từng nền tảng sẽ được sử dụng.
Color
Màu nền thanh công cụ.
Color
Màu thanh điều hướng.
Color
Màu đường phân cách phía trên thanh điều hướng.
'default' | 'back'
default hiển thị biểu tượng “X” của hệ thống; back thay vào đó vẽ mũi tên quay lại.
'start' | 'end'
Vị trí trên thanh công cụ nơi nút đóng xuất hiện.
boolean
Hiển thị biểu tượng chia sẻ trên thanh công cụ.
boolean
Hiển thị tiêu đề trang bên dưới URL trên thanh công cụ.
boolean
Cho phép thanh công cụ tự ẩn khi cuộn trang.
boolean
Hiển thị “Bookmark this page” trong menu mở rộng.
boolean
Hiển thị “Download page” trong menu mở rộng.
'system' | 'light' | 'dark'
Buộc giao diện sáng hoặc tối bất kể cài đặt hệ thống của thiết bị.
'done' | 'close' | 'cancel'
Nhãn hoặc biểu tượng cho nút dismiss.
'pageSheet' | 'fullScreen'
pageSheet hiển thị dưới dạng card có thể vuốt để dismiss; fullScreen bao phủ toàn bộ màn hình.
boolean
Cho phép thanh công cụ thu gọn khi cuộn. Chỉ hiển thị khi presentationStylefullScreen - pageSheet giữ các thanh cố định bất kể cài đặt này.
'system' | 'light' | 'dark'
Buộc giao diện sáng hoặc tối bất kể cài đặt hệ thống của thiết bị.

Tùy chỉnh trang Checkout

Phần Tùy chỉnh giao diện ở trên kiểm soát giao diện trình duyệt native - thanh công cụ, nút và bảng màu. Bản thân trang checkout - các field hiển thị, theme và phương thức thanh toán - được cấu hình phía server khi bạn tạo checkout session. Những tham số này có ảnh hưởng lớn nhất đến chuyển đổi trên thiết bị di động. Các tham số bên dưới nằm ở ba vị trí khác nhau trong request checkout session - cột Vị trí cho biết mỗi tham số thuộc object nào. Đây là lỗi phổ biến nhất: tham số đặt sai object sẽ bị bỏ qua mà không có thông báo.
Luôn truyền billing_currencybilling_address.country cùng nhau. Nếu thiếu một trong hai, Adaptive Currency có thể âm thầm thay đổi currency billing dựa trên địa chỉ IP của khách hàng. Một merchant từng thấy subscription tại Mỹ chuyển sang EUR khi khách hàng đi du lịch châu Âu - vì quốc gia billing không được đặt rõ ràng.
Tác động tăng chuyển đổi lớn nhất trên thiết bị di động: đặt show_order_details: falseminimal_address: true. Đưa phương thức thanh toán lên phần đầu màn hình và giảm số field trong form là hai thay đổi có tác động lớn nhất bạn có thể thực hiện.
So sánh checkout cạnh nhau: thông tin đơn hàng mở rộng (các field bên dưới phần đầu màn hình) và thu gọn (các field ở đầu)

show_order_details: false moves the contact and payment fields above the fold, instead of behind the order summary.

Đặt minimal_address: true để chỉ thu thập postcode thay vì toàn bộ các field street, city và state:
So sánh checkout cạnh nhau: form địa chỉ billing đầy đủ và chỉ yêu cầu postcode

minimal_address: true reduces the billing address to a single postcode field.

Đặt theme: "system" để checkout tuân theo tùy chọn giao diện sáng hoặc tối của thiết bị:
So sánh checkout cạnh nhau: cùng một trang được hiển thị ở chế độ sáng và tối

With theme: system, the checkout follows the device's light or dark appearance automatically.

Tính khả dụng của payment method thay đổi theo loại sản phẩm. Apple Pay và Cash App được hỗ trợ cho subscription định kỳ có giá trị khác 0. Với thanh toán một lần, tất cả phương thức đã bật đều khả dụng.

Full checkout session parameter reference

Xem mọi tham số, kiểu và giá trị mặc định khả dụng trong hướng dẫn Checkout Sessions.

Recipe tối ưu cho thiết bị di động

Mỗi recipe bên dưới là một request body checkout session hoàn chỉnh. Sao chép recipe phù hợp với tình huống của bạn, thay product ID và truyền vào endpoint tạo session của backend.
Dùng recipe này khi bạn muốn form ngắn nhất có thể: phương thức thanh toán ở đầu, chỉ yêu cầu postcode cho địa chỉ, không có field giảm giá và theme khớp với thiết bị.
Xem Checkout Sessions để biết tất cả tham số khả dụng và giá trị mặc định.
Dùng recipe này khi trang checkout cần tạo cảm giác như một phần của ứng dụng. Đặt màu thương hiệu, font tùy chỉnh và nhãn nút thanh toán được bản địa hóa.
Checkout di động mang thương hiệu với bảng màu xanh navy tối tùy chỉnh được áp dụng qua theme_config
theme_config chấp nhận các object darklight riêng biệt để bảng màu thích ứng với giao diện hiện tại của thiết bị. Xem Checkout Sessions để biết đầy đủ tài liệu tham chiếu về color key.
Dùng recipe này cho người dùng đã đăng nhập và từng thanh toán trước đó. Kết hợp customer ID, payment method đã lưu của họ và confirm: true để bỏ qua hoàn toàn form checkout.
status trong deep-link return chỉ là gợi ý UI. Xác nhận quyền truy cập bằng cách lắng nghe webhook payment.succeeded trên backend.
Dùng recipe này cho các sản phẩm subscription cung cấp thời gian dùng thử miễn phí trước chu kỳ billing đầu tiên.
Cấp quyền sử dụng tính năng khi backend nhận webhook subscription.active - không phải khi SDK di động trả về. Xem Subscription Integration Guide để biết toàn bộ quy trình webhook.
Dùng recipe này để tokenise card của khách hàng cho các khoản charge sau này (nạp ví, pay-as-you-go, BNPL) mà không hiển thị nhãn “subscription”. Khách hàng ủy quyền payment method một lần; sau đó bạn charge các khoản biến đổi theo nhu cầu.
Đây là pattern được các ứng dụng tính phí dựa trên mức sử dụng sử dụng - ví dụ ứng dụng chiêm tinh tính phí theo từng phiên từ card đã được ủy quyền trước, thay vì theo lịch cố định.
On-demand charge yêu cầu tối thiểu 1 USD (100 cents). Các khoản dưới 1 USD sẽ bị từ chối với "value out of range". Để authorization với số tiền bằng 0, hãy dùng mandate_only: true như bên trên, sau đó charge ít nhất 1 USD trong các request tiếp theo.
Xem On-Demand Subscriptions để biết toàn bộ quy trình charge, sự kiện webhook và chính sách retry.

Quy trình Subscription trên thiết bị di động

Subscription được tạo thông qua cùng quy trình checkout session dùng cho thanh toán một lần - SDK di động mở checkout được host, khách hàng đăng ký và ứng dụng xử lý deep-link return. Sau đó, vòng đời subscription được quản lý hoàn toàn trên backend.

Subscription định kỳ thông thường

Đối với billing theo khoảng thời gian cố định (hàng tháng, hàng năm), hãy tạo checkout session với sản phẩm subscription và deep-link return_url. Backend của bạn nhận subscription.active khi subscription được xác nhận.
Apple PayCash App được hỗ trợ cho subscription định kỳ có giá trị khác 0.
Để xem toàn bộ quy trình webhook trên backend, hãy xem Subscription Integration Guide.

On-Demand Subscription

On-demand subscription cho phép bạn ủy quyền payment method của khách hàng một lần và charge các khoản biến đổi sau đó - phù hợp cho nạp ví, pay-as-you-go và mọi tình huống chưa biết trước số tiền charge. Xem recipe On-Demand Mandate ở trên để biết request body đầy đủ. Các lưu ý chính trên thiết bị di động:
  • Đặt show_on_demand_tag: false để trang checkout không hiển thị ngôn ngữ “subscription” hoặc “on-demand”. Với các trường hợp tokenise card, khách hàng không mong đợi thuật ngữ subscription.
  • Sau khi mandate được ủy quyền, backend nhận subscription.active. Lưu subscription_id - bạn sẽ sử dụng nó cho mọi khoản charge trong tương lai.
Khoản charge tối thiểu là 1 USD (100 cents). On-demand charge dưới 1 USD sẽ bị từ chối với "value out of range". Hãy charge ít nhất 1 USD hoặc dùng mandate_only: true để authorization mà không charge, rồi thu khoản tiền thực đầu tiên sau.
Tránh retry liên tục. Nếu khoản charge trước đó vẫn đang được xử lý, charge mới trên cùng subscription sẽ thất bại với "Cannot create new charge as previous payment is not successful yet". Điều này đặc biệt phổ biến với payment method tại Ấn Độ (UPI, thẻ debit/credit Ấn Độ), nơi quy tắc mandate của RBI có thể giữ giao dịch ở trạng thái đang xử lý trong tối đa 48 giờ. Thêm kiểm tra thời gian chờ vào logic charge trước khi retry.
Xem On-Demand Subscriptions để biết endpoint charge, sự kiện webhook và chính sách retry đầy đủ.

Subscription có Free Trial

Truyền subscription_data.trial_period_days trong checkout session để cung cấp thời gian dùng thử trước chu kỳ billing đầu tiên. Khách hàng ủy quyền payment method khi đăng ký dùng thử; khoản charge đầu tiên được thực hiện tự động khi thời gian dùng thử kết thúc. Xem recipe Subscription with Free Trial ở trên để biết request body đầy đủ.

Nâng cấp và hạ cấp

Thay đổi plan được thực hiện qua API trên backend, không phải qua checkout session mới. Dodo Payments tự động tính proration. Để cung cấp tùy chọn self-service cho khách hàng, hãy nhúng hoặc liên kết đến Customer Portal.

Subscription Integration Guide

Thiết lập backend đầy đủ: quy trình webhook, cấp quyền truy cập, hủy

On-Demand Subscriptions

Ủy quyền mandate, charge biến đổi và chính sách retry

Upgrade / Downgrade

Chiến lược proration, thay đổi plan và điều chỉnh seat

Customer Portal

Quản lý subscription self-service cho khách hàng

Giảm tỷ lệ rời bỏ Checkout

Checkout trên thiết bị di động có tỷ lệ bỏ dở cao hơn web - màn hình nhỏ hơn, nhiều yếu tố gây xao nhãng hơn và form dài hơn đều góp phần vào điều này. Những cải thiện nhanh nhất đến từ chính cấu hình checkout session.

Tối ưu Form

Điền sẵn dữ liệu khách hàng

Mỗi field mà khách hàng không phải nhập là một lý do giúp họ không rời bỏ:
  • Khách hàng mới - đặt customer.emailcustomer.name từ auth session.
  • Khách hàng quay lại - đặt customer.customer_id để tự động điền sẵn mọi thông tin đã lưu.
  • Currency - luôn truyền billing_currencybilling_address.country cùng nhau.

Công cụ khôi phục

Abandoned Cart Recovery

Chuỗi email tự động cho checkout chưa hoàn tất

Payment Retries

Logic retry thông minh cho các lần gia hạn subscription thất bại

Subscription Dunning

Email tái tương tác cho subscription đã hết hạn

Recovery Overview

Tất cả công cụ khôi phục và tác động tổng hợp đến doanh thu
Hãy kiểm thử email nhắc checkout bị bỏ dở trước khi bật. Tạo checkout session ở live mode và nhập thông tin card không hợp lệ. Thanh toán thất bại sẽ kích hoạt quy trình email khôi phục, cho phép bạn xem trước chính xác nội dung khách hàng sẽ nhận.

Best Practices

  • Bảo mật: Không bao giờ đưa API key vào ứng dụng. Tạo checkout session trên backend và chỉ truyền checkout_url kết quả đến client.
  • Quyền quyết định: Xem CheckoutResult.status là gợi ý UI. 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 loading trong khi backend tạo session và xử lý cancelled như một kết quả bình thường thay vì lỗi.
  • Kiểm thử: Dùng test mode và test card, đồng thời xác minh vòng lặp return-URL trên thiết bị thật cũng như simulator.
  • Chuyển đổi: Đặt show_order_details: falseminimal_address: true để đạt tỷ lệ hoàn tất checkout di động tốt nhất. Đưa phương thức thanh toán lên phần đầu màn hình và giảm số field trong form là hai thay đổi có tác động lớn nhất.
  • Currency: Luôn truyền rõ ràng cả billing_currencybilling_address.country - nếu thiếu một trong hai, Adaptive Currency có thể thay đổi currency billing dựa trên địa chỉ IP của khách hàng.
  • On-demand billing: Đặt show_on_demand_tag: false khi dùng on-demand subscription để tokenise card. Khách hàng sử dụng quy trình nạp ví không mong đợi thấy ngôn ngữ “subscription”.
  • Khôi phục: Bật khôi phục giỏ hàng bị bỏ dở trong dashboard Dodo Payments để tự động tái tương tác với 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

  • Không bao giờ nhận được callback: Scheme trong returnUrl phải khớp với scheme bạn đã đăng ký. Trên Android, đó là manifest placeholder dodoCallbackScheme; trên iOS và React Native, đó là URL type Info.plist.
  • Checkout quay lại trình duyệt thay vì ứng dụng (iOS): Bạn chưa chuyển tiếp URL đến. Gọi DodoCheckout.handleOpenURL(url) từ .onOpenURL, scene(_:openURLContexts:) hoặc listener Linking của React Native.
  • PLATFORM_ERROR trên Android: Thường là do scheme không khớp. Cũng có thể xảy ra nếu MainActivity đặt android:taskAffinity="" (giá trị mặc định flutter create), khiến một số bản build OEM làm mất checkout đang thực hiện.
  • ALREADY_IN_PROGRESS: Một checkout vẫn đang mở. Hãy chờ hoặc dismiss checkout trước đó rồi mới bắt đầu checkout khác.
  • Build thất bại với placeholder chưa được resolve: Bạn đã thêm Android SDK nhưng chưa đặt manifestPlaceholders["dodoCallbackScheme"].
  • Thanh toán thành công nhưng chưa cấp quyền: Đây là điều được dự đoán nếu bạn dựa vào kết quả trên thiết bị di động. Thay vào đó, hãy cấp quyền từ webhook payment.succeeded / subscription.active.
  • Apple Pay / Google Pay không hiển thị trên thiết bị di động: Checkout đang được tải bên trong embedded WebView (WKWebView / Android WebView), làm ẩn các ví và có thể khiến 3-D Secure bị lỗi. Hãy mở bằng SDK hoặc trong trình duyệt hệ thống (Custom Tabs / SFSafariViewController).

Tài nguyên bổ sung

Nếu có câu hỏi hoặc cần hỗ trợ, hãy liên hệ support@dodopayments.com.
Lần sửa đổi cuối 21 tháng 8, 2026