> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentcard.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Add the Vault to a React Native app

> Open the Vault's pages in the system browser from your React Native app, where the user's passkey works.

Your React Native app opens the Vault's links in the system browser: the add-a-card page and the approval page open in Safari or Chrome, where the user's passkey works.

## Open the Vault from your app

Create a vault session on your server, hand the `url` to the app, and open it with `Linking`.

```bash theme={null}
curl -X POST https://api.agentcard.sh/api/v2/vault_sessions \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

```tsx theme={null}
import { Button, Linking } from "react-native";

async function addCard() {
  const session = await fetch("https://your-server.example.com/agentcard/vault-session", { method: "POST" })
    .then((r) => r.json());
  await Linking.openURL(session.url);
}

<Button title="Add a card" onPress={addCard} />
```

Open the link in the system browser, not in a `WebView` you control. The Vault saves the user's card behind a passkey, and the system browser is where that passkey lives, so a returning user unlocks with Face ID or fingerprint. Inside a `WebView` the page asks the user to open the link in Safari or Chrome instead. On iOS, `expo-web-browser` or a Safari view gives the same result without leaving your app.

Create the session on your server and give the app only the `url`. Your `client_secret` never ships in the app bundle.

Open the approval link the same way. When your agent reaches the payment form, `onApprovalUrl` fires with a link; open it with `Linking`, or send it by push notification if the user is not in the app.

When the user finishes, you receive `vault.session_linked` with their `user_id`, then `vault.card_stored`. Store the `user_id`: it is what you pass as `user` on every checkout. Without webhooks, [poll the session](/vault/adding-a-card#option-b-poll-the-session) instead.

## Confirm with webhooks

The user returning to your app is a claim. Your server should act on webhooks, because the browser can close before your app hears anything:

* `vault.card_stored` when a card lands in the vault.
* `checkout_authorization.approved` and the other `checkout_authorization.*` events when purchases are approved or declined.

## Test it

A sandbox token creates a sandbox session. Open the link on your own device, store any of [Stripe's published test cards](https://docs.stripe.com/testing), any future expiry, any CVC. Rehearse a purchase against [shop.agentcard.sh](https://shop.agentcard.sh), a demo store on Stripe test mode.

Next: [Create a cart](/vault/creating-a-cart).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.