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

# How to sell your API

> Wrap any route with @t2000/serve, list it on your Agent ID, and get paid USDC per call. 0% fee.

You end up with an API card on your public profile that any agent can pay per
call — ≤ \$5 a call, 0% fee, settled to your own wallet; your server never holds
a key or pays gas. You need a wallet ([get set up](/how-to/get-set-up)) — the
wallet that receives payments must be the one that lists (`payTo`) — and
somewhere to deploy (Vercel works in one click).

## Paste into your coding agent

```text theme={"dark"}
Help me sell a paid API on t2000 end-to-end with the official Vercel template.
Docs: https://docs.t2000.ai/how-to/sell-your-api
Template: https://github.com/mission69b/t2000/tree/main/templates/serve-vercel
Deploy: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmission69b%2Ft2000%2Ftree%2Fmain%2Ftemplates%2Fserve-vercel&env=T2000_PAY_TO&project-name=my-agent-api&repository-name=my-agent-api
Rules:
- I already have (or you help me get) a Sui address that will be payTo — same wallet must list later.
- x402 path: no settle fee; ≤ $5/call. Do not invent escrow/5% fees for this path.
- Confirm with me before any paid call or on-chain list. Never spend from my wallet without asking.
- Self-pay is blocked — verification pay must use a different funded wallet than payTo.
Do this in order; stop and ask when you need a secret, browser login, or a decision from me:
1) Deploy the template (Vercel clone or local clone + vercel). Set T2000_PAY_TO to my address. On Vercel add Upstash Redis so KV_REST_API_URL / KV_REST_API_TOKEN exist.
2) Confirm the live origin. Probe free: POST {origin}/haiku with empty JSON — expect HTTP 402 and a Sui x402 accepts[] envelope (not a bare/header-only 402).
3) Optional: swap/customize the demo handler — keep paid() validation-before-settlement; export OPTIONS; wire new routes into openapi.json + llms.txt if I add any.
4) List from the payTo wallet only: t2 agent sell {origin} (or the single-route URL). Dry-run/probe first; show me the buyer-facing price; list only after I confirm.
5) Prove it from a second wallet: t2 pay {origin}/haiku --data '{"topic":"sui"}' --max-price 0.10 (or equivalent). Confirm profile card + Activity, or say what blocked us.
If something fails, use the Stuck? section on the docs page — don't invent workarounds that bypass payTo matching or the 402 envelope.
```

## 1 — Deploy an x402 endpoint

**No API yet?** [Deploy the template](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmission69b%2Ft2000%2Ftree%2Fmain%2Ftemplates%2Fserve-vercel\&env=T2000_PAY_TO\&project-name=my-agent-api\&repository-name=my-agent-api) —
set `T2000_PAY_TO`, add Upstash Redis from Vercel's Storage tab, swap the demo route for your logic.

**Wrapping an existing API?** `npm install @t2000/serve`, then:

```ts app/api/search/route.ts theme={"dark"}
import { asNextRoute, createServeFromEnv } from '@t2000/serve';
import { z } from 'zod';

const serve = createServeFromEnv();           // reads T2000_PAY_TO
const input = z.object({ query: z.string().min(1) });

export const { POST, OPTIONS } = asNextRoute(
  serve.route({ path: 'search', description: 'Web search, paid per call' })
    .paid('0.02').body(input, z.toJSONSchema(input))
    .handler(async ({ body }) => yourExistingLogic(body)),
);
```

Serve discovery docs too — `serve.openapi()` at `/openapi.json`, `serve.llms()`
at `/llms.txt`. Not Next.js? Bun/Deno/Hono/Workers all mount `serve.fetch`.

| Env var                                               | Required            | What                                                                                                     |
| ----------------------------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------- |
| `T2000_PAY_TO`                                        | **yes**             | Your Sui address — every payment settles here                                                            |
| `KV_REST_API_URL` / `KV_REST_API_TOKEN`               | serverless: **yes** | Replay store (Upstash-compatible KV). In-memory is fine for one long-lived process, wrong for serverless |
| `T2000_BASE_URL` · `T2000_NAME` · `T2000_DESCRIPTION` | no                  | Public URL + listing copy in 402s and discovery docs                                                     |

Validation runs **before** settlement: invalid body → 422, handler throw → 500 — the buyer keeps their money either way. Money moves last.

## 2 — Probe the 402 (free)

```bash theme={"dark"}
curl -s -X POST https://<your-app>.vercel.app/haiku -H 'content-type: application/json' -d '{}'
```

Expect a `402` carrying an x402 `accepts[]` envelope (serve passes by construction). `/haiku` is the template's demo route — probe your own path if wrapping.

## 3 — List it on your Agent ID

<CodeGroup>
  ```bash In the terminal theme={"dark"}
  t2 init --import <payTo-secret>     # skip if this wallet IS payTo
  t2 agent sell https://<your-app>.vercel.app
  ```

  ```text Passport Connect theme={"dark"}
  Put my API on the t2000 marketplace: https://<your-app>.vercel.app. Probe it
  first (t2000_pay_probe), show me the buyer price, then list (t2000_agent_sell) once I confirm.
  ```
</CodeGroup>

An origin expands via `{origin}/openapi.json` — every paid route becomes a
store card; a single 402 URL lists just that route. Only the payTo wallet can
list; prices follow your 402; `t2 agent sell --remove` clears it.

## 4 — Check it worked: buy from a different wallet

```bash theme={"dark"}
t2 pay https://<your-app>.vercel.app/haiku --data '{"topic":"sui"}' --max-price 0.10
```

Expect `Paid via x402` · `200` + a receipt in `X-PAYMENT-RESPONSE`. Your profile shows the API card; paid calls appear on Activity; buyers find it with `t2 services`.

## Stuck?

* **Listing rejected at probe** — the URL must answer 402 with a complete Sui
  `accepts[]` envelope; header-only 402s and bare `exact` entries fail. Test step 2 first.
* **`PAYTO_LISTER_MISMATCH`** — the 402's payTo isn't your listing wallet: set
  `T2000_PAY_TO` to the wallet you list from and retry.
* **Paying yourself** — self-pay is blocked. Verify with a second wallet.

Deliverable work priced above \$5/call belongs in escrow — [list a Service](/how-to/list-a-service), no server needed.
