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

# Adding a card for a new shopper

> Connect a new shopper to your company and save their card with one Vault link, with no account and no code to type.

A shopper who has not connected to your company yet asks for something. Your agent sends one link, the shopper opens it, saves a card with Face ID or Touch ID, and returns to the chat. The chat hears "card saved" without the shopper typing anything, and the purchase moves on.

You build no sign-up screen. The Vault link is the sign-up, and your own `externalUserId` is the shopper's identity in your app.

## Send the link on the first ask

On a new shopper's first call, the tool asks Agentcard for a Vault link and hands it to `sendLink`. The model reads `status: needs_card`, and it tells the shopper a link is waiting. Agentcard returns the same link while it has time left, so a shopper who asks twice gets one link.

```ts chat.ts theme={null}
const turn = buyFor(shopper.id).turn(message, {
  sendLink: (link) => {
    if (link.kind === 'vault') return sendStep(shopper.id, 'Add a card', link); // your code
    return deliverLink(shopper.id, link);
  },
});
```

A shopper who is connected but has no card gets the add-card link Agentcard returned with its answer, and the model reads `needs_card` as well. A Vault link works for about 24 hours.

If you keep your own list of shoppers, name each by a stable id. Two of your shoppers that share one `externalUserId` make Agentcard refuse the call with `external_user_id_ambiguous`.

### Pass the delivery address you hold

When your app already holds the shopper's address, pass it once when you build the tool. The order goes there, and Agentcard never asks the shopper for it.

```ts agentcard.ts theme={null}
const buy = buyTool({
  agentcard,
  externalUserId: shopper.id,
  deliveryAddress: {
    street: '1900 Jefferson St',
    address2: 'Apt 4',
    city: 'San Francisco',
    state: 'CA',
    zip: '94123',
    phone: '+14155550100',
    name: 'Ada Lovelace',
  },
});
```

`street`, `city`, `state`, and `zip` are required. `address2`, `phone`, `name`, `country`, and `can_leave_at_door` are optional. The model can change neither the address nor the shopper. When the address changes after Agentcard built a cart, the tool answers that the address changed, and the model asks for the cart again so Agentcard prices it for the new address.

## Hear that the card is saved

When the shopper saves a card, Agentcard sends a `purchase.message` with `kind: card_added`, and its `text` reads like:

```text theme={null}
Your Visa ending 4832 is saved, so you're ready to check out.
```

`listen` and the webhook handler deliver it to your `onMessage`. Post `message.text` into the chat, as the Quickstart shows. Pass `turn.messages(history)` to your model on the shopper's next message so the model reads the same words. Without them, a model answers "ok lets checkout" with "did you save your card?" and never calls the tool.

A sandbox card link sends no `card_added` message. With sandbox credentials the shopper's own next message carries the purchase on, and the message arrives with nothing typed once you switch to live credentials.

A `card_added` message has `advances` set to true. Run `buy.nextStep(message)` so the agent takes the next step on its own instead of waiting for the shopper to say "ok". "Taking the next step once the shopper finishes outside the chat" shows how.

A shopper who was not connected yet when they asked gets their own first ask run, in their words, once their card is saved.

### Handle a card link that goes unfinished

Two more messages cover a link the shopper does not finish:

| `kind` | When it arrives | What to do |
| - | - | - |
| `card_link_unfinished` | The shopper has not added a card from their card link. `text` carries the link again. | Send `text` as it is, so the link arrives exactly as Agentcard wrote it. |
| `card_link_expired` | The card link expired before the shopper added a card. | Tell the shopper, and let the next ask send a new link. |

`card_link_expired` ends the Vault step as `expired`, and `card_link_unfinished` leaves it open, as "Sending each link" describes.

## Check it in the sandbox

1. Send "two packs of AA batteries from Amazon" as a test shopper nobody connected. Check that a `vault` link arrives and that the model reads `needs_card`.
2. Send the same ask again. Check that you receive the same link.
3. Open the link, connect with the code `111111`, and save a card.
4. Send "ok lets checkout". Check that the agent moves to the next step and sends no second card link.

The sandbox sends no `card_added` message, so the test shopper sends step 4 themselves. Check the "card saved" that arrives with nothing typed once you run the same steps with live credentials.

The scripted walkthrough covers step 2: it asks as a shopper nobody connected, twice, and fails unless Agentcard returns the same Vault link both times.


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