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

# Agent pack (x402)

> Buy match credits with USDC on Base. No account, no card, no email.

An agent can buy its own credits. Pay \$1 in USDC on Base and the response
carries an API key with 12 match credits behind it.

```
POST https://walletlink.social/api/x402/buy
```

That is roughly 51 resolvable addresses at our measured rate, which is one full
[`/v1/batch`](/api-reference/batch) call: the smallest purchase that is still a
whole unit of work. One settlement can buy up to 25 packs at once; see
[quantity](#buying-more-than-one-pack) below.

One pacing rule matters before spending it: a batch call spends one
request-unit per address of the per-minute rate window, and a full batch fills
most of a minute on every plan (60 units and 50-address batches on the default
plan a fresh key starts on), so a second full batch inside the same minute is
refused rather than queued. Pace multi-batch runs a minute apart and read the
reset time from the response headers. See
[rate limits](/api-reference/rate-limits).

## How it works

The endpoint speaks [x402](https://x402.org). Post with no payment and it
answers `402` with a `PAYMENT-REQUIRED` header describing what to pay:

```json theme={null}
{
  "scheme": "exact",
  "network": "eip155:8453",
  "amount": "1000000",
  "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "payTo": "0x58a5…Fee9C",
  "maxTimeoutSeconds": 120,
  "extra": { "name": "USD Coin", "version": "2" }
}
```

Sign it and post again with a `PAYMENT-SIGNATURE` header. Any x402 client does
this for you. On success:

```json theme={null}
{
  "api_key": "wts_live_…",
  "shown_once": true,
  "matches_added": 12,
  "quantity": 1,
  "matches_available": 12,
  "pack": "Agent",
  "newly_granted": true
}
```

<Warning>
  `shown_once` is literal. The key is stored only as a hash, so nobody can
  produce the original again, including us. Persist it before the process exits.
  If you lose it, [recover a new one](#lost-your-key) by signing with the wallet
  that paid.
</Warning>

## What you are buying

The same match credits a card buys, metered the same way. **A wallet that
resolves to nothing costs nothing**, so the pack stretches further on a list
that matches well and is not wasted on one that does not. See
[credits](/api-reference/introduction#credits).

The key works on the whole [REST API](/api-reference/introduction) and on the
[MCP server](/mcp-server), including [async jobs](/api-reference/jobs): with
the pack’s 12 matches live, it can submit a job of up to 120 wallets that
resolves unchecked addresses against live sources, billed only on what
completes. When the pack runs dry, the metered endpoints answer
`402 NO_CREDITS`, but [`/v1/usage`](/api-reference/usage),
[`/v1/stats`](/api-reference/stats) and the job status poll keep answering at
zero balance: a drained key can always read its own meter and collect a
finished job, and that zero reading is the signal to buy again.

|                        |                            |
| ---------------------- | -------------------------- |
| Price                  | \$1.00 USDC per pack       |
| Matches                | 12 per pack                |
| Per resolvable address | \~\$0.0198                 |
| Quantity               | 1 to 25 packs a settlement |
| Network                | Base mainnet               |
| Credits last           | 12 months                  |

## Buying more than one pack

Send `{"quantity": N}` in the request body, 1 to 25, and one settlement buys N
packs at linear price: the `402` challenge asks for N dollars, and the grant is
N × 12 matches. There is no volume discount; what quantity saves is
signatures. Send the same body on the paid retry (an x402 client does this by
itself), because the payment is verified against the amount the quantity
decided: a payment signed for one pack does not verify against a three-pack
request.

```bash theme={null}
curl -X POST https://walletlink.social/api/x402/buy \
  -H "Content-Type: application/json" \
  -d '{"quantity": 5}'
```

## Topping up an existing account

A buy that carries a valid `wts_live_` key in the `Authorization` header is a
top-up: the credits land on **that key’s** account instead of the paying
wallet’s, and no new key is minted. This is how an agent recovers from a
`402 NO_CREDITS` mid-session without a second credential to manage: pay with
whatever wallet it holds, present the key it is already using, keep working.

```bash theme={null}
curl -X POST https://walletlink.social/api/x402/buy \
  -H "Authorization: Bearer wts_live_YOUR_KEY" \
  -H "PAYMENT-SIGNATURE: ..."
```

The response says which account was credited by the key’s own prefix
(`credited_to_key_prefix`) and carries `api_key: null`; the account is proven
by the key alone, and nothing in the request body can name one. Two refusals
happen **before any money moves**: an OAuth token (`wts_mcp_`) answers `403
OAUTH_CANNOT_BUY`, because an [OAuth connection](/mcp-server) is promised
never to buy or spend, and an `Authorization` header that does not validate as
a key answers `401 INVALID_TOPUP_KEY` rather than silently crediting the
wallet account, because guessing at intent after settlement would put paid
credits where the buyer cannot see them.

## Every tenth purchase is on us

Every 10th settled purchase from the same wallet grants one bonus Agent pack
of matches, on top of what the settlement bought, to whichever account that
settlement credited. The count is the wallet’s own settlement history: bonus
credits carry no settlement record, so they never count toward the next bonus,
and a replayed payment cannot add to the count. The response names it when it
happens (`loyalty_bonus`, with the running purchase count).

## Paying twice for the same thing

You cannot. The pack is recorded against the EIP-3009 authorization you signed,
not against the transaction hash, so replaying a payment reports the credits it
already bought rather than charging again. A response with
`"newly_granted": false` means exactly that.

**A replay does not return a key.** Once a payment settles, every field of it is
public: the authorization is in USDC's `AuthorizationUsed` event and the
signature is in the settlement transaction's calldata. Nothing in a payment can
prove who is holding the wallet afterwards, so serving a key to anyone who
presents one would serve anyone who reads the chain. Proving current control of
a wallet needs a challenge this server issued, which is exactly what
[key recovery](#lost-your-key) does.

## No free allowance

An account created this way does not get the free 100 matches per 30 days that
an email signup does. That allowance exists to show a person their real match
rate before they pay, and this account has already paid.

## Lost your key

Sign a challenge with the wallet that paid, and a new key is issued against the
same credits.

```bash theme={null}
# 1. Ask for a challenge
curl "https://walletlink.social/api/x402/recover?wallet=0xYOURWALLET"
```

That returns a `message`, an `issued_at`, a `token` and five minutes to use
them. Sign `message` with `personal_sign`, then:

```bash theme={null}
# 2. Redeem it
curl -X POST https://walletlink.social/api/x402/recover   -H "Content-Type: application/json"   -d '{"wallet":"0xYOURWALLET","issued_at":…,"token":"…","signature":"0x…"}'
```

The credits are untouched: they belong to the account, not to the key. Up to
three active keys per wallet.

At the cap, ask for a clean slate instead: request a fresh challenge, sign it,
and POST it with `revoke_others_and_reissue: true`. That revokes every active
key the account holds and issues one new key in a single atomic step, and the
response lists the revoked prefixes:

```bash theme={null}
curl -X POST https://walletlink.social/api/x402/recover   -H "Content-Type: application/json"   -d '{"wallet":"0xYOURWALLET","issued_at":…,"token":"…","signature":"0x…","revoke_others_and_reissue":true}'
```

The signature is the authority for the revocation, the same way it is for the
reissue: a wallet account has no email session to revoke keys from, so wallet
control is the only proof there could be. Send the flag only when you mean it;
every previously issued key stops working the moment it runs. A plain recovery
at the cap answers `409 KEY_CAP_REACHED` and names this flag as the way out.

**Why signing is required, and why replaying your payment is not enough.** Once
a payment settles, every field of it is public: the authorization is in USDC's
`AuthorizationUsed` event and the signature over it is in the settlement
transaction's calldata. Anyone reading Base could present those. Only a
challenge issued now, signed now, shows that you still hold the wallet.

## If something goes wrong

A `500` with a `settlement` reference means the payment settled and the pack
could not be recorded. Send that reference to
[help@walletlink.social](mailto:help@walletlink.social) and it will be issued by
hand; it cannot be issued twice.
