# LVL Agent Shop SDK

**Module:** https://lvlltd.com/sdk/agent-shop.mjs  
**Class:** `LvlAgentShop`  
**Does not hold private keys.** You (or your facilitator) supply a verified Base USDC `txHash`.

## Install / import

```js
// Browser / Deno / Node 18+
import { LvlAgentShop, DEFAULT_BASE } from "https://lvlltd.com/sdk/agent-shop.mjs";

const shop = new LvlAgentShop();
// optional: new LvlAgentShop({ base: "https://lvlltd.com", fetch: customFetch })
```

Python agents: call the same HTTP endpoints (see [REFERENCE.md](./REFERENCE.md)); a thin `public/sdk/python/` helper may exist for samples.

## Methods

| Method | Purpose |
|--------|---------|
| `discovery()` | `GET /agent.json` |
| `shop()` / `shopWithQuery(q)` / `shopBudget(usd)` | Unified machine entry |
| `search({ q, category, max_price, limit, … })` | `GET /api/catalog` |
| `outline(skillId)` | Free outline JSON |
| `sample(skillId)` | Free sample markdown |
| `challenge(skillId)` | GET pay → expects **402**; normalizes amount/payTo |
| `unlock(skillId, txHash)` | POST pay with `X-PAYMENT` |
| `recover(skillId, txHash)` | Stuck payment safety net |
| `proof()` | Public ledger (honest) |
| `contracts()` | Treasury / escrow allowlist |
| `purchases(wallet)` | Buyer history |
| `buyerCredential(wallet)` / `verifyCredential(token)` | Credential surfaces |
| `recommendations(skillId)` | Related skills |
| `coverage()` / `pipelines()` / `priceHistory()` / `statusHistory()` | Ops helpers |

## Full purchase loop

```js
import { LvlAgentShop } from "https://lvlltd.com/sdk/agent-shop.mjs";

const shop = new LvlAgentShop();
const skill = "agent-x402-first-buy";

// 1 free eval
const outline = await shop.outline(skill);
console.log(outline.summary || outline.skill_id);

// 2 challenge
const ch = await shop.challenge(skill);
console.log({
  amountAtomic: ch.amountAtomic, // "50000"
  payTo: ch.payTo,
  network: ch.network,
  assetContract: ch.assetContract,
});

// 3 your code: ERC-20 transfer USDC on Base → ch.payTo for ch.amountAtomic
// const txHash = await myWallet.transferUsdc(...)

// 4 unlock (idempotent re-redeem with same txHash)
const pack = await shop.unlock(skill, txHash);
for (const [path, text] of Object.entries(pack.sealed_pack?.files || {})) {
  console.log(path, text.slice(0, 80));
}

// 5 optional proof
const proof = await shop.proof();
console.log(proof.confirmed); // never invent if missing
```

## Challenge return shape

```ts
{
  status: 402,
  challenge: object,       // raw body
  accept: object | null,   // accepts[0]
  amountAtomic: string,
  payTo: string,
  assetContract?: string,
  network: string,
  priceUsd?: number,
  skill: string,
  paymentRequiredHeader: string | null
}
```

## Errors

Methods throw `Error` with optional `.status` and `.body` (API JSON).  
On unlock failure with `PAYMENT_VERIFICATION_FAILED`, wait 2–5s and retry; or call `recover()`.

## Related

- [REFERENCE.md](./REFERENCE.md) — full HTTP contract  
- [AGENT-PURCHASE.md](./AGENT-PURCHASE.md) — sequence  
- OpenAPI: https://lvlltd.com/openapi.json  
