Skip to main content
This quickstart is for products where your company pays. Your users never open an Agentcard wallet, never add a card, and never add balance. Instead you create a cardholder for each user, request a buy token that lets their agent act as that one user, and every purchase draws on your company balance. By the end, you have a cardholder, a 30-day buy token, test money in the company balance, and an agent that has run a real purchase conversation at Amazon right up to the sandbox wall. About fifteen minutes, all in sandbox, so no money moves. If your users pay with their own cards or their own balance, pick a wallet shape in Choose a quickstart instead; the web app quickstart is the default.

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.
  • The Agentcard CLI, signed in and pointed at your organization: npm install -g agent-cards, then agent-cards login and agent-cards companies use ORG_ID. In sandbox the company balance is funded from the CLI. CLI has the details.
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

Create a cardholder and a buy token

A cardholder is the person your company pays for. Create one with the org token; firstName, lastName, and dateOfBirth are required, and so is at least one of email or phoneNumber, because every cardholder needs a reachable identifier to complete onboarding later. The credential decides whether the cardholder is sandbox or live.
Output
Keep the id. Creating the same email twice in one organization returns a 409 that carries the existing cardholderId, so a retry can pick up where it left off instead of dead-ending. Your first webhook, cardholder.created, fires here.Now request a buy token for the cardholder:
Output
The buy token lasts 30 days and works only as that one user: it’s the bearer the agent buys with, in exactly the place a connection token goes for wallet shapes, so export it as USER_ACCESS_TOKEN now. Store it keyed by your user and request a fresh one any time; there’s no refresh. agentcard_user_id is the Agentcard user the cardholder is linked to, which is who the token acts as. From your coding agent, mint_buy_token on the organization MCP server does the same thing.
3

Fund the company balance

There’s no end-user wallet in this shape. The company balance is what stands behind every purchase: in production you fund it and allocate spending power to cardholders from it, and the one-time card each confirm issues draws on that allocation. In sandbox you fund it with test money from the CLI:
Output
Read it back with agent-cards companies balance get; the sandbox pool is its own line, separate from the live balance:
Output
This walkthrough never draws on the pool, because sandbox stops every purchase before anything is reserved; funding it here is what makes the shape complete, and it’s what sandbox card issuing spends from when you get to that. If the CLI answers that the company balance isn’t enabled on this environment, write to us and we’ll switch it on.In production the mechanics are the same with real money: you fund the balance, allocate to a cardholder, and read their remaining company-funded spending power as headroomCents on GET /api/v1/cardholders/:id. A confirm that outruns the allocation declines rather than drawing on any other source; allocate more and send the same confirm again. How the money moves on the Purchase API page walks that funding path.
4

Let the agent buy

Wherever this step says the user’s token, it’s the buy token you exported as USER_ACCESS_TOKEN. It behaves identically as the bearer: one user, one conversation, and the same hash-bound confirm. Purchases made with it draw on your company balance, not a personal wallet.Your server sends what the user wants as plain text. The bearer is the user’s token from step 2, so everything that follows runs as that user: the agent searches the merchant, asks follow-up questions, and stops each turn at needs_input until it has enough to build a cart.
Give the client a timeout of at least 120 seconds: each turn runs against a live merchant. The first turn usually asks a question. Yours will differ, because sandbox conversations are live, not scripted:
Output
needs_input is not an error; it’s how a purchase progresses. Show the reply to the user and send their answer back as the next ask on the same conversation_id:
Keep answering until the response carries a cart with a totalCents and a hash. That’s the agent showing the exact all-in price before anything happens:
Output
Confirm by echoing the cart’s hash, not the word “yes”. The hash binds the approval to exactly this cart at exactly this price: if anything drifted since the cart was shown, the confirm returns a 409 with the fresh carts instead of charging something the user never saw.
The hash verifies, the confirm gate passes, and then sandbox refuses the one thing it exists to refuse. Before any money is reserved or any card is created, the checkout denies with the sandbox wall:
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.
Branch on status, never on the reply text: the prose varies run to run, the status and the cart don’t. The Purchase API page has the full envelope, multi-merchant confirms, and the rules a production integration needs.
The buy token is also the bearer for the MCP server. Connect a client exactly as a wallet shape would, with the buy token in place of the connection token, and the agent gets the same buy tool:
Buy through MCP has the wiring 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 created a cardholder, gave their agent a buy token, funded the company balance, and the agent ran a real purchase conversation to the confirm. In production the same five steps are your integration; only the credentials and the money change.

Purchase API

How the money moves for org-owned accounts, the full envelope, and the rules a production caller needs.

MCP

The organization server from your coding agent: cardholders, mint_buy_token, the company balance tools, and test_charge.

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.