Skip to main content
This quickstart is for a React Native app. The wallet is one component: you give it a wallet link your server created, it renders the wallet, and you get the same events the web SDK fires. By the end, a test user has added a card inside your app, and their agent has run a real purchase conversation at Amazon right up to the sandbox wall. About fifteen minutes, all in sandbox, so no email is sent, no money moves, and the verification code is always 111111. If your app is native Swift, use the iOS quickstart instead; Choose a quickstart has the rest.

Prerequisites

  • An Agentcard organization with sandbox credentials. In the dashboard, open Settings → Developers → Credentials; if there’s no client yet, Implement Agentcard in the same menu creates one.
  • curl, Node 18+, or Python 3.8+ with requests, whichever you prefer. Every call on this page is shown in all three.
  • A React Native project with react-native-webview, and access to the @agentcard/wallet-react-native package. The package is private while the SDK is in early access, so the install fails until your team has access: write to us and we’ll set you up.
1

Get your sandbox credentials

Your sandbox client_id and client_secret are in the dashboard under Settings → Developers → Credentials. Sandbox or production follows the credential, not the URL: there is one API at api.agentcard.sh, and a sandbox credential makes every call on this page a sandbox call, so nothing is emailed, nothing is texted, and no money moves.Exchange the credentials for a bearer token. The request is form-encoded, per OAuth:
The token comes back with its lifetime:
Output
Export it as ORG_TOKEN; it’s the Authorization: Bearer on every server call below. It lasts an hour and there’s no refresh token, so when it expires you request a new one the same way.While you have the token, give the last step something to read: create a sandbox webhook destination. Events are only recorded when your organization has a destination to deliver them to, so a destination created after the fact shows nothing. Skip this if you already have one in sandbox.
url is any public https address you can watch: your own endpoint, or a request-inspection service while you test. It doesn’t have to answer 2xx for this walkthrough, because you’ll read the deliveries in the dashboard. The response carries the signing secret once, and livemode: false tells you the token was a sandbox one:
Output
You can do the same in the dashboard under Settings → Developers → Webhooks with Add destination, with the Live mode switch off so the destination is a sandbox one. Destinations belong to one mode and receive only that mode’s events.
2

Connect a test user

Start a connection for a test user. In sandbox nothing is actually sent, so any email works, and sandbox identities are isolated: connecting testuser@example.com here can never touch a real account with that address.
Send phone instead of email to connect by text message; the call takes exactly one of the two. external_user_id is optional: it’s your own id for the user, and it comes back on webhooks so you can match them up. The response is the attempt, good for ten minutes:
Output
Verify it with the sandbox code, which is always 111111:
The response is the connection: the user’s id, an access_token, and a refresh_token:
Output
Store all three. user.id is what you create wallet links for. The access_token is the user’s connection token: it’s the bearer the user’s agent buys with in step 4, over MCP or POST /buy, so export it as USER_ACCESS_TOKEN now. It lasts an hour; the refresh_token rotates it (POST /api/v2/connect/refresh), and each refresh returns a new pair and invalidates the old one. Your first webhook, connection.created, fires here.Then record the user’s authorization. Consent is what makes the user’s wallet available to your product: wallet links can’t be created for a user until it’s on file, and the call is idempotent, so a retry updates the record instead of duplicating it. In your product the wallet shows the user a consent screen; in this walkthrough you record it directly:
Output
That’s the whole server side of connecting a user. Connect users covers the same calls with production in mind: where each credential lives, refreshing sessions, and the errors you can get back.
3

Render the wallet

Install the component and its peer dependency:
The component needs a wallet link for the user who is opening it. Create links on your server and give the app only the url; the org token never ships in the app bundle.
Output
Links expire after 15 minutes by default (expires_in accepts 60 to 86400 seconds), so in your app the server creates a fresh one each time the wallet is about to render. For this walkthrough, paste the url into the screen that renders it:
The component accepts link as either the full URL or the raw token, and style sizes the view. Run the app and open that screen. Add a card with the test number 4242 4242 4242 4242, any future expiry, any CVC. onSuccess fires with card_attached, and the connected_card.updated webhook goes out. Treat the component event as a UI signal and the webhook as the record.When the link or its session dies, onTokenExpired fires: fetch a fresh wallet link from your server and swap the link prop rather than reusing the old one. A changed link is a new session, so the component remounts its view.The same component can open onto a pay sheet instead of the wallet home, by passing pay={{ amountCents: 1275, merchant: "Wandy's" }}. That’s a different job: the user approving one specific charge your app already priced, with a card from their wallet. What comes next is the agent going to a merchant and buying something for them, which is buy.
4

Let the agent buy

Your agent runs behind the app, on your server, and holds one MCP client per user with that user’s connection token from step 2. The app never sees the token.The user’s agent talks to Agentcard directly over MCP: one MCP client per user, pointed at https://mcp.agentcard.sh/mcp with that user’s connection access_token from step 2 as the bearer. The bearer decides whose cards and purchases the agent can see, so a client shared across users would let one user’s session act as another. Don’t configure OAuth on the client: the connection token is the sign-in, and a user who ever sees a “Connect your account” page at mcp.agentcard.sh is a sign the client was wired for OAuth discovery instead.The fastest way to watch the loop is to add the server to Claude Code with the token:
In your own agent runtime the same thing is a client constructor, and any spec-compliant MCP client over Streamable HTTP works:
listTools() returns the user’s tools with buy among them; register whatever it returns rather than a hardcoded list, so tools Agentcard ships later appear without a deploy. Now ask the agent for something:
Prompt
The agent calls buy with that request. The tool runs the same purchase loop as POST /buy, except that it’s conversational: each call returns the assistant’s turn as prose and a conversation_id to thread back.
Output
The agent shows you the message and sends your reply back, word for word, on the same conversation_id. Answer until it shows the cart with the exact total and asks whether to place the order, then say yes. Over HTTP that confirmation is a cart hash; over MCP the user’s yes is relayed in words, which is why the agent must never rewrite a reply into a fresh order command. Your yes is where sandbox stops. The tool’s last turn explains why, in its own words each time:
Output
That refusal is the finish line, not a failure. You ran the whole purchase contract: an ask, a real cart at a real merchant with an exact total, and a confirmation that verified before anything moved. Sandbox stops at the money on purpose, because its test cards can never charge a real merchant, so no sandbox call ever places an order, and retrying this confirm on a sandbox connection always returns the same refusal. On a production connection this exact confirm is the one that places the order: Agentcard reserves the amount, issues a one-time card funded from the wallet, pays the merchant, and returns the receipt.
That’s the whole wiring for the agent: one client per user, the connection token as the bearer, and buy as the surface. Buy through MCP carries the rest of what a production agent needs: the other tools it gets, approvals, token refresh on 401, and the rules for relaying the conversation.
5

See what happened

Open the dashboard with the Live mode switch off, go to Settings → Developers → Webhooks, pick the sandbox destination from step 1, and open its Deliveries tab. Every event from this walkthrough is there with its payload and the response code your destination answered. From the terminal, agent-cards companies webhooks deliveries ENDPOINT_ID lists the same rows.Every event arrives in the same envelope, and livemode is false because the credential behind it was a sandbox one:
connection.created
What you’ll find, in order: connection.created from step 2, wallet_link.opened the first time the wallet opened from its link, and connected_card.updated when the card was added. On the company-funded quickstart it’s cardholder.created from step 2 instead. Nothing arrived from the purchase, and that’s correct: sandbox stopped the confirm before a card existed, so the transaction.* events a live order produces never fired. To rehearse those in sandbox, test_charge on the organization MCP server simulates a full charge against a sandbox card and sends transaction.authorized, transaction.cleared, and card.closed; Test in sandbox has every knob.In production your server listens for these instead of reading them in the dashboard. The SDK callbacks and the conversation are UI signals; webhooks are the record. Deliveries are at least once, so deduplicate on id, and verify the AgentCard-Signature header against the raw request body: Webhooks shows the scheme and lists every event.

Next steps

You connected a user, they added a card inside your app, and their agent ran a real purchase conversation to the confirm. In production the same five steps are your integration; only the credentials change.

React Native

The full component surface, bank approvals in the system browser, and the rules for your agent.

Buy through MCP

Everything the agent’s buy loop needs in production: tools, approvals, token refresh, and relay rules.

Webhooks

Verify signatures and handle every event on your server instead of reading them in the dashboard.

Go live

Subscribe, switch to production credentials, and run the loop once with real money.