Skip to main content
Use useSignUpForCard to open card onboarding, useGetCardsForUser to find existing cards, and CardSummaryView to display and manage a card. Import these APIs from @privy-io/expo/cards. Card signup runs in the PrivyElements modal. CardSummaryView renders inside the app’s own screen. For an approved Earn-backed card program, follow Spend from vault balances. The same hooks and components handle vault-share approval and available balances.
These APIs are experimental and may change in a minor version. React Native card signup supports embedded EVM wallets.

Set up the SDK

Complete the cards setup, React Native SDK installation, and Privy UI setup, including the UI dependencies and fonts. Use @privy-io/expo version 0.76.4 or later for signup, card management, and card-detail reveal:
Mount PrivyElements once inside PrivyProvider, alongside the app’s navigation. Use the app ID and mobile client ID from the Privy dashboard.
Authenticate the user and create an embedded Ethereum wallet before starting signup. The wallet must be connected to approve spending. Enable gas sponsorship for the funding chain, or fund the wallet with the chain’s gas token.

Add the card flow

The example below checks every page for an existing open card before starting signup. It uses Tempo Moderato and PathUSD in sandbox.
The SDK opens PrivyElements when signUp runs. The modal handles disclosures, bank and provider terms, identity verification, card creation, and spend approval. Hosted terms and identity verification open in the in-app browser through expo-web-browser. The funding walletId is the Privy wallet ID from the user’s linked accounts. getAllUserEmbeddedEthereumWallets(user) returns those accounts, including their IDs. CardSummaryView fills its parent and scrolls internally. Give it available height, such as a screen with flex: 1. It uses the appearance configured on PrivyElements.

Find returning users’ cards

getCardsForUser returns one page for the authenticated user in the selected environment, ordered newest first. Pass next_cursor as cursor until it is null. The default page size is 5; the maximum is 20. Select the first active or inactive card for the funding wallet. An inactive card is frozen and can be unfrozen in CardSummaryView. Keep canceled and replaced cards for history.
A failed list request does not mean the user has no cards. Show the error and retry. Start signup only after a successful search finds no open card.
onReplaced receives the replacement card’s ID. Update the selected ID to display it, as shown above. Otherwise, the view stays on the closed card. If signup closes before spend approval succeeds, the card can already exist. The example’s Finish card setup action calls signUp again with the same wallet, chain, asset, and environment. Signup reuses the existing card and resumes the approval flow.

Configure production spend approval

Sandbox uses built-in approval targets for Ethereum Sepolia, OP Sepolia, Polygon Amoy, Base Sepolia, Arbitrum Sepolia, Avalanche Fuji, and Tempo Moderato. Tempo Moderato supports PathUSD (pathusd) and OUSD (ousd); the other listed testnets use USDC (usdc). Production requires the stablecoin contract and Bridge spender for the card program’s funding chain. Obtain these addresses from the Privy account manager. The stablecoin must match asset, and the spender must belong to the app’s card program.
The spendApproval object contains stablecoinAddress: string and spenderAddress: string. Sandbox uses its built-in targets and does not accept this option.
Pass the same environment when signing up, listing cards, and rendering CardSummaryView. Cards are scoped by app, user, and environment.

API reference

useSignUpForCard

Returns signUp, close, and isOpen. signUp(options) requires PrivyElements to be mounted and returns Promise<{id: string}>. isOpen is true while signup is in progress. Only one signup can run at a time. close() dismisses the flow and settles its pending promise. Closing before a card exists rejects the promise. Applications under review or rejected also reject when closed. If a card already exists at the ready or approval-error step, closing resolves with its ID. A returned card ID alone does not guarantee that spend approval succeeded. An unsupported funding chain, another active signup, or an unmounted PrivyElements causes signUp to reject. Catch rejections to handle cancellation and errors in the app.

useGetCardsForUser

Returns getCardsForUser(options), which resolves to a page with data and next_cursor.

CardSummaryView

Displays the card’s balance, paginated activity, transaction details, and dispute contact. The details screen reveals the card number and CVC and supports freezing, replacement, and cancellation. Card details render in Stripe Issuing Elements inside a react-native-webview. The app’s configured Stripe publishable key is loaded through Privy. Keep Stripe and Bridge secret keys in the Privy dashboard.