Mobile
Flutter SDK
Release candidate: the SDK is published to pub.dev with Vezmo's mobile launch. Until then, use Checkout for apps.
vezmo_checkout adds the Vezmo payment sheet to a Flutter app: cards with 3D Secure, Apple Pay, Google Pay, Klarna, Affirm, Afterpay, Amazon Pay, Cash App, UPI and Pix, in the buyer's own currency, and subscriptions. The same sheet is in the React Native, iOS and Android SDKs; the plugin draws it with the iOS and Android SDKs, so it looks and behaves exactly as in a native app. Your server keeps your API key; the app only ever gets a session token.
Requirements
- Flutter 3.41 or later (Dart 3.11).
- Android 7.0 (API 24) or later,
compileSdk36, Kotlin 2.1, Java 17; yourMainActivityextendsFlutterFragmentActivity. - iOS 15.1 or later, Xcode 16 or later, with Swift Package Manager (Flutter's default).
- Your app added under Developers → Mobile apps, with its return link for iPhone (see Take payments in your mobile app).
1. Install
flutter pub add vezmo_checkoutAndroid
The sheet reports its result through your activity, so MainActivity must be a FlutterFragmentActivity. Remove android:taskAffinity="" from it in AndroidManifest.xml if it is there (new Flutter apps have it): with it, the buyer can't come back from a bank app or a pay-later provider to the open sheet. Set minSdk to at least 24.
// android/app/src/main/kotlin/…/MainActivity.kt
import io.flutter.embedding.android.FlutterFragmentActivity
class MainActivity : FlutterFragmentActivity()iPhone
Set the minimum iOS version to 15.1, and add your return link's scheme and the camera text used to scan a card. The plugin hands the links that come back to the app to the sheet by itself.
<!-- ios/Runner/Info.plist -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array><string>acme</string></array>
</dict>
</array>
<key>NSCameraUsageDescription</key>
<string>Scan your card to fill in its number.</string>2. Create the session on your server
The same API checkout session as the web. Your server first exchanges your API key and secret for an access token (see Authenticate); sandbox keys are under VezmoPay → Developers → API keys.
POST https://api.vezmo.com/api/v1/merchant/secure-payments
Authorization: Bearer <access token>
{
"title": "Order #1042",
"amount": 49.00,
"currency": "USD",
"client": { "name": "Ana Silva", "email": "ana@example.com", "country": "US", "postalCode": "10001" }
}Send data.securePayment.clientToken to the app. Add app.returnUrl only if you also open Checkout for apps.
3. Take the payment
import 'package:vezmo_checkout/vezmo_checkout.dart';
final vezmo = VezmoCheckout(
configuration: const VezmoConfiguration(
returnUrl: 'acme://vezmo', // iPhone: registered under Developers → Mobile apps
applePay: ApplePayOptions(merchantId: 'merchant.com.acme'), // Apple Pay shows only with your Merchant ID
),
);
Future<void> pay(String orderId) async {
final clientToken = await myApi.createVezmoSession(orderId); // your server, your API key
final error = await vezmo.prepare(clientToken: clientToken);
if (error != null) return showError(error.message);
switch (await vezmo.present()) { // never throws
case CheckoutSucceeded(:final paymentId):
showPaid(paymentId);
case CheckoutProcessing():
showPaymentReceived(); // UPI or Pix still settling
case CheckoutCanceled():
break; // the buyer closed the sheet
case CheckoutFailed(:final error):
showError(error.message);
}
}Fulfil the order from the webhook (payment.success), not from the result alone.
Subscriptions
Start a subscription in the app: the first payment, or a free trial with the card saved for the renewals. Your server creates it and sends its checkoutToken; pass it as subscriptionToken. On iPhone, Apple Pay shows the plan as a recurring payment. Digital goods used inside the app follow the app store rules.
// checkoutToken from POST /merchant/subscription, via your server
final error = await vezmo.prepare(subscriptionToken: checkoutToken);
if (error != null) return showError(error.message);
final result = await vezmo.present();
if (result case CheckoutSucceeded(:final paymentId, :final subscription?)) {
// subscription.ref → 'VS7K2P9Q4FXM'; subscription.status → SubscriptionStatus.trialing or .active
// paymentId → the first payment, or null when a free trial started
}When the buyer starts a free trial, Vezmo sends subscription.trial_started; the first charge sends subscription.activated (or subscription.payment_failed). See Subscriptions → Webhooks.
Results and errors
present() completes with one of four results (a sealed class, so a switch covers them all):
CheckoutSucceeded | Paid. paymentId and transactionId match the dashboard and the webhook. A subscription also has subscription (ref, status); paymentId is null when a free trial started. |
CheckoutProcessing | Paid, money on its way (UPI or Pix still settling). Wait for the webhook. |
CheckoutCanceled | The buyer closed the sheet or pressed Back. Not an error. |
CheckoutFailed | error.code is one of the codes below; error.message is written for the buyer and safe to show. |
VezmoErrorCode (also returned by prepare() when a session can't be paid):
declined | The bank said no. The buyer can try another card or way to pay. |
expired | The session ran out. Create a new one on your server. |
alreadyPaid | The session was already paid. Treat the order as paid. |
notAvailable | This way to pay can't be used for this session. |
network | No connection. Let the buyer try again. |
config | A setup mistake in the app, for example present() before prepare(). |
unknown | Anything else. Let the buyer try again. |
Apple Pay and Google Pay
Apple Pay needs your Apple Merchant ID and its certificate, set up under Developers → Mobile apps → Apple Pay in your iPhone app as in the iOS SDK. Google Pay needs Google's production approval before live payments, as in the Android SDK.
Testing
Create the session with your sandbox API key and pay with test card 4242 4242 4242 4242, any future expiry and any CVC. 3D Secure shows a test page where you can approve or fail the payment. Card 4000 0000 0000 0002 is always declined; 4000 0000 0000 3220 always asks for 3D Secure. More test cards are in Test mode. The example app (a small shop) pays against Vezmo's sandbox; how to run it is in the SDK's README on GitHub.
Going live
- Your server creates sessions with your live API key.
- Apple Pay: your Apple Merchant ID shows Active under Developers → Mobile apps → Apple Pay in your iPhone app, and the Runner target has the Apple Pay capability.
- Google Pay: Google approved your app for production.
- Live sessions are refused until your account is approved.
- The rest of Before you go live, and the app store rules if you sell anything used inside the app.
Troubleshooting
- The
configerror "Vezmo checkout needs a FlutterFragmentActivity": yourMainActivityextendsFlutterActivity. Make it extendFlutterFragmentActivity. - After Cash App, a bank app or a pay-later provider the buyer stays in the browser: remove
android:taskAffinity=""fromMainActivityinAndroidManifest.xml. - iOS build: "plugin vezmo_checkout does not support CocoaPods": turn Swift Package Manager back on with
flutter config --enable-swift-package-manager.