> ## 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.

# Purchase API

> Agents send one call with plain text, and we place the real order. This is how agents actually buy things.

A card alone doesn't finish a checkout. Someone still has to find the merchant, log in, and place the order, and that's what the Purchase API does. It's one endpoint: the agent sends plain text, and we find the merchant, build the cart, and place the order with the user's card.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.agentcard.sh/buy \
    -H "Authorization: Bearer $BUY_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"ask": "two boxes of Pampers size 4 from Amazon"}'
  ```

  ```javascript Node theme={null}
  const res = await fetch("https://api.agentcard.sh/buy", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${BUY_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ ask: "two boxes of Pampers size 4 from Amazon" }),
  });
  const result = await res.json();
  ```

  ```python Python theme={null}
  import requests

  res = requests.post(
      "https://api.agentcard.sh/buy",
      headers={"Authorization": f"Bearer {BUY_TOKEN}"},
      json={"ask": "two boxes of Pampers size 4 from Amazon"},
  )
  result = res.json()
  ```
</CodeGroup>

The same call is the `buy` tool on the MCP server. Same behavior, same states.

## Where agents can buy

Amazon and more than a dozen other large retailers, DoorDash, Uber Eats, Walmart, Sephora, TaskRabbit, Rinse, Good Eggs, Rappi, Locale, and flights. The list grows; `buy` itself tells the agent when a merchant needs the user to link their account first.

## How a purchase actually flows

Every response has a `status`, and there are only four:

| Status             | What it means                                                                    |
| ------------------ | -------------------------------------------------------------------------------- |
| `needs_input`      | The `reply` is a question. Send the answer back with the same `conversation_id`. |
| `order_placed`     | The order is in. The `reply` carries the confirmation.                           |
| `partially_placed` | A multi-merchant confirm placed some orders; each cart reports its own outcome.  |
| `declined`         | We refused: over budget, unsupported merchant, or a failed check.                |

Money never moves on a plain `ask`. When a cart is ready, the response includes the cart with an exact total and a `hash`. To place the order, the agent sends the hash back:

```json theme={null}
{ "conversation_id": "...", "confirm": "9f2c4a1b8e3d5f07" }
```

The hash covers the exact items and total that were shown. If anything about the cart changed since, the confirm fails safely instead of charging something the user never saw.

## Give an agent access

Create a buy token for the user. It lasts 30 days and only works as that one user:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.agentcard.sh/api/v1/cardholders/CARDHOLDER_ID/buy_token \
    -H "Authorization: Bearer $ORG_TOKEN"
  ```

  ```javascript Node theme={null}
  const res = await fetch(
    "https://api.agentcard.sh/api/v1/cardholders/CARDHOLDER_ID/buy_token",
    { method: "POST", headers: { Authorization: `Bearer ${ORG_TOKEN}` } },
  );
  const buyToken = await res.json();
  ```

  ```python Python theme={null}
  import requests

  res = requests.post(
      "https://api.agentcard.sh/api/v1/cardholders/CARDHOLDER_ID/buy_token",
      headers={"Authorization": f"Bearer {ORG_TOKEN}"},
  )
  buy_token = res.json()
  ```
</CodeGroup>

The same thing is available as `mint_buy_token` on [MCP](/tools/mcp) when connected as your organization. Hand the token to the agent; it's the bearer for every `buy` call.

## What it costs

Purchases carry a service fee, 2.5% of the merchant total, shown to the user in the cart before any confirm. The totals in `needs_input` replies are all-in: what the user sees is what the card is charged.

## Spending controls and approvals

Budgets cap what an agent can spend. Cards can be locked to one merchant or one purchase. And when a purchase needs a human, the user gets an approval prompt and you receive `approval.requested`; the purchase waits for the yes.

## Webhooks you will receive

* `transaction.authorized`, then `transaction.cleared` as the payment settles
* `approval.requested` when a purchase is waiting on the user
* `merchant.connected` when a user links a merchant account

## When it fails

A `declined` status always says why in the `reply`. A confirm with a stale hash returns a conflict instead of charging; re-ask to get a fresh cart. If the user has no usable card, `buy` says so and the fix is the wallet, not the Purchase API.

## Sandbox behavior

Sandbox conversations run the same loop with no real orders and no real money. Use the org server's `test_charge` to watch settlement events end to end.

Next: [Test in sandbox](/ship/test-in-sandbox)
