POST /buy — is the one-call purchase surface. Your agent
sends what the user wants in plain language; Agentcard’s shopping agent
handles every merchant’s flow — store selection, delivery address, carts,
per-merchant quirks — and hands back typed state your agent can verify. You
integrate one endpoint and get every merchant in the catalog, current and
future, without writing per-merchant logic.
Authentication. Every
/buy call is authorized with the user’s
connection access_token as the bearer — the token pair your backend stored
from user authentication. A purchase
always runs as one user (their carts, their address, their card), so the org
client secret and platform client_credentials tokens are rejected here. On
401, refresh the pair via POST /api/v2/connect/refresh and retry.Over MCP: the same loop is available as the
buy tool on the Agentcard MCP server, using the
same connection token — one surface, two transports.
Instructions for your agent
Paste this into your coding agent to integrate the Purchase API. It assumes users are already connected (you store their tokens — see user authentication).Instructions for your agent
How it works
1
Send the ask
POST /buy with the user’s request in plain language, authorized with
that user’s connection token. The first response returns the
conversation_id you thread through every follow-up.2
Answer questions
needs_input turns carry a question in reply — address, store choice,
which item. Relay it to your user and send the answer as the next ask.3
Verify the cart, confirm the hash
When a cart is on the table the response carries it as typed data with a
hash. Your agent verifies the items and total as types and confirms by
echoing the hash — never by parsing prose.4
The order places
order_placed carries the confirmation. Track and manage follow-ups over
the same conversation, or the MCP shopping tools.The response envelope
Every successful turn (HTTP 200) carries the same fields — always present,null when empty — so a typed client never guesses:
needs_input is the normal path, not an error: the agent asked a question
(address, choice, confirmation). Send the answer as the next ask with the
same conversation_id.
Non-200 responses are compact error objects, not the envelope:
The typed cart, and the deterministic confirm
A real purchase needs one thing to be exact: what gets charged. When the agent has a cart ready, the response carries it as data:items, qty, priceCents, and totalCents as
types — no prose parsing — and confirms by echoing the hash instead of
saying “yes”:
409
and the fresh cart:
"ask": "yes, place it") pass through the same checkout gate — the hash path
adds the deterministic first gate that makes the verification yours.
Money only moves after a cart has been shown and confirmed in a later
call — one-shot purchases are deliberately impossible. Checkout runs behind
the same spend controls as everything else: budgets, per-merchant policies,
approvals, and the order-markup disclosure.
Statuses
A purchase that needs an owner approval reports
needs_input — the reply
explains the pending approval, and once it is granted the next ask (or
confirm) proceeds.
Multiple merchants, one conversation
A conversation can hold a shown cart at several merchants at once — ask for sushi from DoorDash and batteries from Amazon in the same thread, andcarts carries one entry per merchant, each with its own hash. Confirm any
subset in one call by sending an array:
409 and the fresh carts — nothing places). Then the orders place
sequentially, each as its own turn, and the response reports each outcome:
placements entries, not just the top-level status:
order_placed = all placed, partially_placed = some, and a multi-cart
confirm cannot carry an ask (400) — send follow-ups as their own turns.
Conversation threading
conversation_id is returned on every successful turn, including the first
(error bodies carry it only when a conversation is involved — see the table
above). Thread every follow-up with it. A conversation keeps its cart,
address, and merchant context across turns; a placed order clears the cart.
Continuing a closed conversation returns 409.
Merchants
The catalog behind/buy is Agentcard’s merchant network — food delivery,
groceries, flights, retail, subscriptions — and it grows without any change on
your side: your integration is the endpoint, not the merchants. To shop with
your own retailer accounts on the retail catalog (order history, Prime and
loyalty benefits), see Retailer accounts.
Timeouts and confirm retries
A turn can take up to a few minutes when it searches and builds carts against live merchants — use a client timeout of at least 120 seconds. A lost confirm response leaves the outcome unknown to your client — and a turn’s server-side budget is 10 minutes, so your client timing out does not stop an in-flight placement. After a completed placement the cart is cleared, so a replayed confirm returns409 (“nothing to confirm”) and can’t
double-place. But while the outcome is unresolved — the first attempt still
running, or stopped before placing — the cart can still be live, and a
replayed hash re-attempts checkout rather than reporting status. There is
no idempotency key on confirm today.
So on a lost confirm response, send nothing to /buy — no replayed
confirm, and no fresh ask that rebuilds a cart (that’s a second order, not
a retry) — until you have verified the outcome out of band. Merchants with order history
expose it typed —
buy_order_history over MCP or
GET /buy/v1/merchants/<merchant>/orders (the retail catalog does not
support order history) — and every placement ultimately shows in the user’s
transaction feed. When the result
stays ambiguous, surface it to the human (“please check your orders before I
try again”) rather than guessing. A first-class idempotent confirm with a
typed placement lookup is on our roadmap.