---
name: fast-shop
version: 1.8.0
description: >
  Buy real physical products and have them delivered to your door.
  Use for: "buy X", "order X", "purchase X", "shop for X", "find product",
  "search for X", "compare prices", "track my order", "cancel order",
  "how much does X cost". Triggers on product shopping, purchasing, price
  lookup, order tracking, and cancellation requests.
  US shipping only.
  NOT for: digital products, gift cards, international shipping,
  unsupported retailers, FAST SDK setup (use fast-skill).
---

# Fast Shop

Buy real physical products and have them delivered to your door.

## Before You Start

Always check for the latest version of this skill before proceeding:

```bash
curl -fsSL https://walmart.shop.fast.xyz/skill.md
```

Compare the `version` in the frontmatter (currently `1.8.0`) with your local copy. If a newer version is available, replace your saved file with the latest version. This ensures you have the most up-to-date API endpoints, payment flow, and pitfall warnings.

## Getting Started

### MCP

`@fastxyz/mcp@0.1.13` — add as MCP server.

Search, quote, pay, track, and cancel — all available as tools.

### HTTP

Base URL: `https://walmart.shop.fast.xyz`
OpenAPI: `https://walmart.shop.fast.xyz/openapi.json`

```bash
npm install @fastxyz/sdk@0.2.5 @fastxyz/x402-client@0.1.3
```

```typescript
import { FastProvider, FastWallet } from "@fastxyz/sdk";
import { x402Pay } from "@fastxyz/x402-client";
import { readFileSync } from "fs";
import { join } from "path";
import { homedir } from "os";

const provider = new FastProvider({ network: "mainnet" });
const wallet = await FastWallet.fromKeyfile({ key: "default" }, provider);
const keyfile = JSON.parse(
  readFileSync(join(homedir(), ".fast", "keys", "default.json"), "utf8")
);

const x402Wallet = {
  type: "fast" as const,
  privateKey: keyfile.privateKey,
  publicKey: keyfile.publicKey,
  address: wallet.address,
};

// Fresh every call. 60s TTL.
async function buildAuthToken(): Promise<string> {
  const ts = Math.floor(Date.now() / 1000).toString();
  const msg = `${wallet.address}:${ts}`;
  const { signature } = await wallet.sign({ message: msg });
  return `${Buffer.from(msg).toString("base64")}.${Buffer.from(signature, "hex").toString("base64")}`;
}
```

**Include on every HTTP request:**

```
X-Fast-Wallet-Address: {wallet.address}
```

This header links all your activity (search, quote, order, tracking) to your wallet for a seamless session. Required on all requests, even unauthenticated ones like search and product details.

No wallet yet?

```typescript
const wallet = await FastWallet.generate(provider);
await wallet.saveToKeyfile("~/.fast/keys/default.json");
```

Fund: `https://allramp.fast.xyz/?fastAddress=<address>&ref=shop-api`

---

## Flow

```
search → details → quote → confirm → pay → track → delivered
```

## 1. Search Products

```
GET /search?q={encodeURIComponent(query)}&retailer={retailer}&max_results={n}
X-Fast-Wallet-Address: {wallet.address}
```

`retailer`: `walmart` | `homedepot`
`max_results`: default 10, max 20

Walmart can be quoted and ordered. Home Depot is currently search/product-details only.

Response:
```json
{
  "results": [{
    "product_id": "5236782001",
    "title": "Matcha Green Tea Powder",
    "url": "https://www.walmart.com/ip/Matcha-Green-Tea-Powder/5236782001",
    "price": 1828,
    "image": "https://...",
    "num_reviews": 450,
    "stars": 4.5,
    "retailer": "walmart"
  }]
}
```

`price` is in **cents** (`1828` = $18.28).

## 2. Product Details + Offers

```
GET /products/{product_id}?retailer={retailer}
```

Returns description, images, features, and seller offers. Useful for checking availability and price before quoting.

## 3. Create Quote

```
POST /quote
Content-Type: application/json
```

Quote/order supported retailer: `walmart`.

```json
{
  "products": [{
    "url": "https://www.walmart.com/ip/Matcha-Green-Tea-Powder/5236782001",
    "quantity": 1,
    "price_cents": 1828,
    "variant": [{ "label": "Flavor", "value": "Unflavored" }]
  }],
  "shipping_address": {
    "first_name": "Jane", "last_name": "Doe",
    "address_line1": "123 Main St", "address_line2": "Apt 4B",
    "city": "New York", "state": "NY", "postal_code": "10001",
    "phone_number": "2125551234", "country": "US"
  }
}
```

Response:
```json
{
  "quote_id": "uuid",
  "product_total_cents": 1828,
  "max_price_cents": 2011,
  "order_fee_cents": 100,
  "total_cents": 2111,
  "price_usdc": "21.11",
  "fast_address": "fast1...",
  "network": "fast-mainnet",
  "expires_at": "2026-04-01T12:10:00Z"
}
```

`max_price_cents` is the maximum budget for product + shipping + tax.
`total_cents` = `max_price_cents` + `order_fee_cents` ($1). This is what the user pays upfront.
Any excess after the retailer charges the actual amount is refunded automatically.

## 4. Confirm with User

Show product, price, address, and total cost from the quote.
Explain that the total includes a budget for shipping and tax — any unused amount is refunded after delivery.
Wait for explicit confirmation before proceeding.

## 5. Pay and Place Order

```
POST /orders
Content-Type: application/json
```

```json
{ "quote_id": "uuid" }
```

Response (202):
```json
{ "order_id": "uuid", "status": "pending" }
```

## 6. Track Order

```
GET /orders/{order_id}
Authorization: Bearer {authToken}
```

Response:
```json
{
  "id": "uuid",
  "status": "placed",
  "price_components": { "subtotal": 1828, "shipping": 0, "tax": 122, "total": 1950 },
  "tracking_numbers": [{ "carrier": "ups", "tracking_number": "1Z...", "tracking_url": "https://..." }],
  "refund_status": "sent",
  "refund_amount_usdc": "0.61"
}
```

Poll every 30s. Terminal states: `placed`, `failed`, `cancelled`.
Status page: `/orders/{order_id}/view`

## 7. Cancel Order

```
POST /orders/{order_id}/cancel
Authorization: Bearer {authToken}
```

Response: `{ "order_id": "uuid", "status": "cancelled", "refund_status": "pending" }`

## 8. List Orders

```
GET /orders?limit=20&offset=0
Authorization: Bearer {authToken}
```

Response: `{ "orders": [...] }`

---

## Pitfalls

- Always include `X-Fast-Wallet-Address: {wallet.address}` header on every request.
- `price` from search is **cents**. Copy to `price_cents` directly. Do not divide.
- Auth tokens expire in 60s. Generate fresh every call.
- Quotes expire in 10 minutes.
- All products in a quote must be from the same retailer.
- Quote/order currently supports Walmart. Do not quote Home Depot results.
- `phone_number`: exactly 10 digits. Strip formatting, drop leading 1 if 11.
- Never overwrite `~/.fast/keys/default.json` if it exists.
- Never log `x402Wallet` or keyfile contents.
- URL-encode search queries.
- Check balance before payment.
- Quotes are single-use. On 409, use the returned `order_id`.

## Verification

| Step | Assert |
|---|---|
| Search | `results` non-empty, has `product_id` and `price > 0` |
| Details | `offers` has at least one entry |
| Quote | Has `quote_id`, `expires_at` in future, `total_cents > 0` |
| Confirm | User confirmed |
| Balance | Wallet balance >= `price_usdc` |
| Order | HTTP 202, has `order_id` |
| Track | `status` in: `pending`, `processing`, `placed`, `failed`, `cancelled` |
| Cancel | `status` is `cancelled` |

## Errors

| Code | Action |
|---|---|
| 400 | Fix request body |
| 401 | Fresh auth token |
| 402 | x402Pay handles it |
| 404 | Check order ID |
| 409 | Use returned `order_id` |
| 410 | New quote, re-confirm |
| 429 | Wait, retry |
| 502 | Handled automatically |
