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

# Agentic Purchases

> Let AI agents buy from major retailers and pay per order with Link, MPP, or x402. No Zinc account required.

`POST /agent/orders` lets an AI agent place an order and pay for it in the same request flow. The agent doesn't need a Zinc account, an API key, or a pre-funded balance: payment travels with the request over HTTP `402 Payment Required`, and Zinc ships the order once it's paid.

One `402` advertises every payment rail Zinc accepts, so the same endpoint works for whatever wallet your agent already has:

| Rail | Who it's for | Settles in | Protocol |
| - | - | - | - |
| **Link** | Consumer agents paying with a card saved in the user's [Link](https://link.com/agents) wallet | USD (card) | MPP, `method="stripe"` with a Shared Payment Token (SPT) |
| **Tempo** | Agents holding stablecoins on Tempo | USDC | [MPP](https://mpp.dev), `method="tempo"` |
| **x402** | Agents holding USDC on Base or Solana | USDC | [x402](https://x402.org) |

## How It Works

**1. Request without payment**

The agent sends `POST /agent/orders` with the order body and no payment.

**2. Receive the payment challenge**

Zinc checks the body, then responds `402 Payment Required` with one challenge per rail:

* **MPP** — one `WWW-Authenticate: Payment ...` header per method (`stripe`, `tempo`)
* **x402** — a single `PAYMENT-REQUIRED` header (base64 x402 v2 envelope)

A client reads whichever it understands and ignores the rest.

**3. Pay**

The agent pays on its chosen rail and gets a payment proof: an SPT credential for Link, a signed transfer for Tempo or x402.

**4. Resubmit with the proof**

The agent repeats the same request with the proof attached:

* **MPP** (Link, Tempo) — `Authorization: Payment <credential>`
* **x402** — `PAYMENT-SIGNATURE` (x402 v2) or `X-PAYMENT` (x402 v1)

**5. Order confirmed**

Zinc verifies the payment and returns `201` with the order and an `X-Api-Key` header for following the order afterward. MPP payments also return a `Payment-Receipt` header; x402 payments return `PAYMENT-RESPONSE`.

> [!TIP]
>
> **Only want one rail?** Add `?method=stripe`, `?method=tempo`, or `?method=x402` to get a `402` with just that challenge. Many HTTP clients fold repeated `WWW-Authenticate` headers into one comma-joined string and can't pick the right one out. An unknown method returns `400` listing the available ones.

## What You Pay

The challenge amount is **`max_price` + the \$1.00 API fee**. `max_price` is the most you're willing to spend on the order (product, shipping, and tax), in cents. Zinc charges the full amount upfront, then returns whatever wasn't used:

* **Partial refund** — when the retailer's actual total comes in under `max_price`, Zinc refunds the difference. You effectively pay `actual_total + $1.00`.
* **Full refund** — if the order ends in `failed` (the retailer rejects it, the item is out of stock, and so on), Zinc refunds everything you paid.

Refunds go back to the original payment on every rail. No action is needed on your side.

### Validation runs before payment

A malformed or incomplete body returns `422` before any challenge is issued. An order Zinc can't fulfill (unsupported retailer, unreachable product URL, unsupported shipping country, invalid address) is checked on the paid retry, **before** the proof is charged, and returns `400`. Either way nothing is charged, so you can fix the body and retry with the same payment.

### Retrying safely

Pass an `idempotency_key` in the body. If a timeout made you lose the `201`, retry with the same key: Zinc checks for an existing order *after* verifying your payment but *before* settling it. A duplicate returns `409` with the existing order's id in `error.details.order_id` and an `X-Api-Key` to read it, and the new payment is never taken.

## Pay with Link

[Link](https://link.com/agents) lets an agent pay with a card the user has already saved in their Link wallet. The agent mints a one-time **Shared Payment Token** (SPT) for the purchase, the user approves the spend in the Link app, and Zinc charges the token as the merchant. The card number never reaches the agent or Zinc, and there's no checkout page to open.

Consumer agents with Link built in, and anything using [`link-cli`](https://www.npmjs.com/package/@stripe/link-cli), can pay Zinc this way.

### With link-cli

`link-cli mpp pay` runs the whole flow: it requests the challenge, creates the spend request, waits for the user to approve it in the Link app, and resubmits with the SPT.

```bash theme={null}
npx @stripe/link-cli mpp pay "https://api.zinc.com/agent/orders?method=stripe" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "products": [{"url": "https://www.amazon.com/dp/B0EXAMPLE", "quantity": 1}],
    "max_price": 5000,
    "shipping_address": {
      "first_name": "Jane",
      "last_name": "Smith",
      "address_line1": "123 Main St",
      "city": "Seattle",
      "state": "WA",
      "postal_code": "98101",
      "country": "US",
      "phone_number": "2065551234"
    }
  }' \
  --context "Buying one pack of white crew socks from Amazon for Jane, shipped to her Seattle address. Total is capped at \$50 plus Zinc's \$1 fee."
```

The amount comes from the challenge (`max_price` + \$1.00). `--context` is shown to the user when they approve, and must be at least 100 characters.

> [!NOTE]
>
> Link caps a single spend request at \*\*$500**, so set `max_price` to $499 or less on this rail.

### Wire-level

If you're minting the SPT yourself, here's the flow `link-cli` automates.

**1. Get the challenge.** `POST /agent/orders?method=stripe` with your order and no `Authorization` header. The `402` carries:

```
WWW-Authenticate: Payment realm="zinc", method="stripe", id="...", intent="charge", request="<base64>", ...
```

`request` decodes to JSON whose `methodDetails.networkId` is Zinc's Stripe agentic-commerce profile. Pass it as the SPT's network ID.

**2. Mint the SPT** for `max_price + 100` cents against that network ID, and have the user approve it.

**3. Resubmit** the identical request with `Authorization: Payment <credential>`. The credential is an MPP `Credential`: an echo of the challenge plus a payload of `{"spt": "<spt_xxx>"}`. Build it with `pympp` rather than by hand:

```python theme={null}
from mpp import (
    ChallengeEcho, Credential, format_authorization, parse_www_authenticate,
)

challenge = parse_www_authenticate(stripe_www_authenticate_value)
credential = Credential(
    challenge=ChallengeEcho(
        id=challenge.id,
        realm=challenge.realm,
        method=challenge.method,
        intent=challenge.intent,
        request=challenge.request_b64,
        expires=challenge.expires,
        digest=challenge.digest,
    ),
    payload={"spt": spt},
)
auth_header = format_authorization(credential)
```

> [!WARNING]
>
> SPTs are single-use. If the request fails after the token is charged, mint a new one to retry. If it fails validation (`400`), the token wasn't charged and you can reuse it.

## Pay with MPP (Tempo)

The [Machine Payments Protocol](https://mpp.dev) client libraries handle the 402 flow for you. Install one:

```bash npm theme={null}
npm install mppx viem
```

```bash pip theme={null}
pip install pympp
```

The quickest test is the `mppx` CLI:

```bash theme={null}
npx mppx "https://api.zinc.com/agent/orders?method=tempo" \
  --method POST \
  --body '{
    "products": [{"url": "https://www.amazon.com/dp/B0EXAMPLE"}],
    "max_price": 5000,
    "shipping_address": {
      "first_name": "Jane",
      "last_name": "Smith",
      "address_line1": "123 Main St",
      "city": "Seattle",
      "state": "WA",
      "postal_code": "98101",
      "country": "US",
      "phone_number": "2065551234"
    }
  }'
```

Or from code:

```typescript TypeScript theme={null}
import { Mppx, tempo } from "mppx/client";
import { privateKeyToAccount } from "viem/accounts";

const mppx = Mppx.create({
  methods: [
    tempo({
      account: privateKeyToAccount("0x..."),
      maxDeposit: "1",
    }),
  ],
});

const response = await mppx.fetch("https://api.zinc.com/agent/orders", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    products: [{ url: "https://www.amazon.com/dp/B0EXAMPLE" }],
    max_price: 5000,
    shipping_address: {
      first_name: "Jane",
      last_name: "Smith",
      address_line1: "123 Main St",
      city: "Seattle",
      state: "WA",
      postal_code: "98101",
      country: "US",
      phone_number: "2065551234",
    },
  }),
});

console.log(await response.json());
```

## Pay with x402

Any [x402](https://x402.org) client can pay. The `402` carries a `PAYMENT-REQUIRED` header (a base64 x402 v2 envelope) with one `accepts[]` entry per chain Zinc currently takes: USDC on **Base**, and on **Solana**. Pick a chain your wallet holds USDC on, sign the payment, and resubmit with the proof in `PAYMENT-SIGNATURE` (or `X-PAYMENT` for x402 v1 clients).

Settlement uses the scheme's sponsored flow. On Base you sign an EIP-3009 `transferWithAuthorization`. On Solana you sign a partial SPL transfer that the facilitator co-signs as fee payer, so you don't need SOL for gas.

## After the Order

The `X-Api-Key` header on the `201` is an API key for the paying agent. Store it. It's the only way to follow the order without paying again. With it you can:

* **Check status** — `GET /orders/{id}`
* **Cancel** while the order is still pending — see [Cancel order](/docs/v2/api-reference/orders/cancel-order)
* **Get push updates** — register a webhook URL with [`PUT /webhooks/endpoint`](/docs/v2/api-reference/webhooks/set-webhook-endpoint)

```bash theme={null}
curl https://api.zinc.com/orders/{order_id} \
  -H "Authorization: Bearer <X-Api-Key value>"
```

## Agent Data Endpoints

The product data endpoints under `/agent/*` (such as [search](/docs/v2/api-reference/agent/search) and [product details](/docs/v2/api-reference/agent/product-details)) use the same `402` flow at **\$0.01 per call**. That's below the card network minimum, so these endpoints only offer the stablecoin rails (Tempo and x402), not Link.

## Next Steps

> **[Agent Playground](https://agent.zinc.com)**
>
> Place an agent order in the interactive playground.

> **[API Reference](/docs/v2/api-reference/agent/create-order)**
>
> Full spec for `POST /agent/orders`.

> **[Link for Agents](https://link.com/agents)**
>
> Set up a Link agent wallet.


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