Mobile
React Native SDK
Release candidate: the SDK is published to npm with Vezmo's mobile launch. Until then, use Checkout for apps.
@vezmopay/react-native adds the Vezmo payment sheet to your React Native or Expo 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, drawn natively on iPhone and Android in Vezmo's design. Your server keeps your API key; the app only ever gets a session token. The same sheet is in the iOS, Android and Flutter SDKs.
What your buyers see
- Your business name, what they are paying for and the total, with a choice of their own currency where offered.
- Apple Pay or Google Pay as one tap at the top, when the phone has it and you have turned it on.
- The other ways to pay as one list: Card (with the card's own logo once it is typed), pay-later methods, Cash App, and UPI or Pix for buyers in India or Brazil.
- One Pay button, 3D Secure when the bank asks for it, and a receipt: who was paid, with what, and a reference.
Requirements
- React Native 0.79 or later with the New Architecture. Expo SDK 53 or later (React Native 0.79) with a development build (not Expo Go).
- iOS 15.1 or later, Android 7.0 (API 24) or later.
- Your app added under Developers → Mobile apps, with its return link for iPhone (see Take payments in your mobile app).
1. Install
npx expo install @vezmopay/react-native
# or, in a bare React Native app
npm install @vezmopay/react-native && cd ios && pod installIn Expo, add the plugin. It turns on Apple Pay with your Apple Merchant ID and adds the camera text for scanning a card.
// app.json (Expo)
{
"expo": {
"scheme": "acme",
"plugins": [
["@vezmopay/react-native", { "merchantIdentifier": "merchant.com.acme" }]
]
}
}Bare React Native apps
- Add your return link's scheme (
acme) under your iOS target's Info → URL Types. - In
AppDelegate, returnRCTLinkingManager.application(app, open: url, options: options)fromapplication(_:open:options:), so the link reaches the sheet. - In Xcode, add the Apple Pay capability with your Merchant ID, and add
NSCameraUsageDescriptiontoInfo.plistso buyers can scan a card.
// ios/<YourApp>/AppDelegate.swift
import React
func application(_ app: UIApplication, open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
RCTLinkingManager.application(app, open: url, options: options)
}2. Wrap your app
The sheet is drawn inside VezmoProvider, so put it near the top of your app.
import { VezmoProvider } from "@vezmopay/react-native";
export default function App() {
return (
<VezmoProvider
returnUrl="acme://vezmo" // registered under Developers → Mobile apps
applePay={{ merchantId: "merchant.com.acme" }} // Apple Pay shows only with your Merchant ID
appearance={{ colors: { accent: "#503AF2" } }} // optional
>
<Root />
</VezmoProvider>
);
}3. 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.
4. Take the payment
import { useVezmoCheckout } from "@vezmopay/react-native";
function CheckoutButton({ orderId }: { orderId: string }) {
const { prepareCheckout, presentCheckout } = useVezmoCheckout();
const pay = async () => {
// Your server creates the session with your API key and returns its clientToken.
const { clientToken } = await myApi.createVezmoSession(orderId);
const prep = await prepareCheckout({ clientToken });
if (prep.error) return showError(prep.error.message);
const result = await presentCheckout(); // never throws
switch (result.status) {
case "succeeded": return showPaid(result.paymentId);
case "processing": return showPaymentReceived(); // e.g. UPI or Pix still settling
case "canceled": return; // the buyer closed the sheet
case "failed": return showError(result.error.message);
}
};
return <Button title="Pay" onPress={pay} />;
}Fulfil the order from the webhook (payment.success), not from the result alone. The result tells your app what to show.
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 with your API key and sends its checkoutToken to the app.
POST https://api.vezmo.com/api/v1/merchant/subscription
Authorization: Bearer <access token>
{ "planId": "<plan_id>", "customerEmail": "ana@example.com", "trialDays": 7 }
→ 201 Created
{
"success": true,
"data": {
"subscriptionRef": "VS7K2P9Q4FXM",
"status": "TRIALING",
"checkoutToken": "…",
"checkoutPath": "/checkout/subscription/…",
"charge": null
}
}In the app, pass it as subscriptionToken; everything else is the same as a payment.
const prep = await prepareCheckout({ subscriptionToken: checkoutToken });
if (prep.error) return showError(prep.error.message);
const result = await presentCheckout();
if (result.status === "succeeded") {
// result.subscription → { ref: "VS7K2P9Q4FXM", status: "trialing" | "active" }
// result.paymentId → the first payment, or null when a free trial started
}The sheet shows what is due today, the plan after it (“7-day free trial, then $9.99 / month from 23 Oct 2026”), the authorization the buyer gives, and Start free trial or Subscribe. Cards, Apple Pay and Google Pay; on iPhone, Apple Pay shows the plan as a recurring payment and lists it in the buyer's Wallet with their page to manage it. Vezmo charges the renewals; your server hears about each one from the subscription webhooks.
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.
Apple and Google require their own in-app purchase for digital goods and services used inside the app (subscriptions to app features or content). Use Vezmo subscriptions for real-world goods and services: deliveries, memberships, classes, rentals. See App store rules.
Results and errors
presentCheckout() resolves with one of these. prepareCheckout() returns { error } with the same error codes when a session can't be opened.
succeeded | 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. |
processing | Paid, money on its way (a bank debit, UPI or Pix still settling). Wait for the webhook. |
canceled | The buyer closed the sheet. Not an error. |
failed | error.code is one of the codes below; error.message is written for the buyer and safe to show. |
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. |
already_paid | The session was already paid. Treat the order as paid. |
not_available | 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 presentCheckout() before prepareCheckout(). |
unknown | Anything else. Let the buyer try again. |
Appearance
The sheet follows Vezmo's checkout design in light and dark. You can bring it closer to your app. Each color takes one value or { light, dark }; the keys are accent, onAccent, surface, surface2, field, fieldLine, line, ink, ink2, ink3, good and bad. Setting your own accent replaces the Vezmo gradient on the Pay button.
<VezmoProvider
returnUrl="acme://vezmo"
style="automatic" // "light" | "dark"; default follows the phone
appearance={{
colors: { accent: "#0A84FF", surface: { light: "#FFFFFF", dark: "#1C1C1E" } },
cornerRadius: 12,
fontFamily: "Inter", // a font already loaded in your app
}}
>Apple Pay
- In your Apple Developer account, create a Merchant ID (Certificates, Identifiers & Profiles → Identifiers → Merchant IDs) and turn on Apple Pay Payment Processing for your app's App ID with it.
- In your Vezmo dashboard, open Developers → Mobile apps → Apple Pay in your iPhone app and add your Apple Merchant ID. We attach a request file; create the Apple Pay Payment Processing Certificate for your Merchant ID with it in your Apple Developer account and upload it on the same page. Apple Pay turns on once we've added it. Certificates last 25 months; the page reminds you to renew.
- Pass the Merchant ID to
VezmoProvider(applePay.merchantId) and, in Expo, to the plugin. Without it the sheet shows no Apple Pay.
Google Pay
Google Pay shows on Android phones where the buyer has it, with nothing to set up for testing: sandbox sessions use Google's test environment. Before your app takes live Google Pay payments, ask Google for production access in the Google Pay & Wallet Console: add your app, choose the gateway integration when asked how you take payments, and send the screenshots of your checkout that Google asks for.
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. In the sandbox, Apple Pay and Google Pay use the cards in the phone's wallet without charging them. 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.
In your own Jest tests
The package ships a mock with no native views and no network. presentCheckout() resolves with a successful payment unless you pick another result; mockPrepareError({ code, message }) makes prepareCheckout() fail. Both hook functions are jest.fn()s.
jest.mock("@vezmopay/react-native", () => require("@vezmopay/react-native/jest/mock"));
import * as vezmo from "@vezmopay/react-native";
beforeEach(() => (vezmo as any).mockReset());
it("shows the canceled state", async () => {
(vezmo as any).mockNextResult({ status: "canceled" });
// render your screen and press Pay…
});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 (see Apple Pay), and the app's App ID has Apple Pay turned on.
- Google Pay: Google approved your app for production.
- Live sessions are refused until your account is approved.
- The rest of the list in Before you go live, and the app store rules if you sell anything used inside the app.
Troubleshooting
- "VezmoPaymentElementView was not found in the UIManager": the app runs the old architecture, or Expo Go. Turn on the New Architecture and use a development build.
- No Apple Pay: no
applePay.merchantIdon the provider, no card in the phone's Wallet, or the Apple Pay certificate isn't Active (Developers → Mobile apps → Apple Pay in your iPhone app shows where it stands and when it ends). - The buyer doesn't come back to the app after 3D Secure or a bank app: the
returnUrlonVezmoProvidermust be registered under Developers → Mobile apps (iPhone; Android needs none), and your app must open that scheme.