# Getting started for agents

> Make an agent pay only bonded x402 services with @lopw/buyer-sdk: install, set a policy, fetch with warranty checks before and after payment, and claim when a promise is broken.

*LOPW documentation · Guides.* Canonical page: https://lopw.com/docs/guides/agents.html · This Markdown twin: https://lopw.com/docs/guides/agents.md · Index of all pages: https://lopw.com/llms.txt · Everything in one file: https://lopw.com/llms-full.txt

The buyer SDK wraps x402’s fetch. Before paying it verifies the seller’s signed offer, reads the service’s on-chain state, stake and terms, and applies your policy. After paying it verifies the receipt against what you actually sent and received, evaluates every predicate locally, and files a claim in one call.

## 1. Install

```sh
npm install @lopw/buyer-sdk   # access for approved integrators
```

Your agent needs a Stellar key (`S...`) with USDC on the same network as the contracts it talks to. The same key pays via x402 and signs claim transactions.

## 2. Create a buyer with a policy

The policy is what your agent insists on before it pays. If any check fails, the x402 payment is aborted before money moves. Here: at least 100 USDC of stake, the service must offer P6 (oracle deviation), and a single receipt must be able to pay out at least 1 USDC.

```ts
import { LopwBuyer, FileReceiptStore } from "@lopw/buyer-sdk";

const agent = new LopwBuyer({
  secret: process.env.AGENT_SECRET,                // Stellar secret key; pays via x402 and files claims
  policy: { minStake: 100n * 10_000_000n, requiredPredicates: [6], minMaxClaim: 10_000_000n },
  store: new FileReceiptStore("./receipts.json"),  // receipts survive restarts until their claim windows close
});
```

| `BuyerPolicy` field | Type | Meaning |
| --- | --- | --- |
| `minStake` | bigint | Refuse services whose stake is below this (asset base units) |
| `requiredPredicates` | number[] | Refuse unless the warranty covers all of these predicate IDs |
| `requireWarranty` | boolean | Refuse sellers that offer no LOPW warranty at all. Default `true` |
| `minMaxClaim` | bigint | Refuse offers whose single-receipt cover (`max_claim`) is below this |

| `LopwBuyerConfig` field | Meaning |
| --- | --- |
| `secret` | Stellar secret key that pays and files claims (required) |
| `binding` | A `StellarBinding`; defaults to testnet. Use `new StellarBinding(getNetwork())` to follow `LOPW_NETWORK` |
| `policy` | The `BuyerPolicy` above |
| `store` | Where receipts are kept: `FileReceiptStore(path)` or `MemoryReceiptStore` (default). Any `ReceiptStore` with `put`, `list`, `hasPaidOffer` works |
| `fetch` | A custom `fetch` implementation, if needed |

## 3. Fetch a paid resource

```ts
const { response, body, warranty } = await agent.fetch("https://fx.example.com/v1/quote?pair=EUR-USD");
// response: the HTTP Response   body: Buffer   warranty: WarrantyRecord | undefined
```

**Before paying**, the SDK decodes the offer from `extensions.lopw` and refuses to pay, throwing `WarrantyRefused` through x402’s abort hook, when:

- the offer names a registry other than the binding’s (*offer names an unknown registry*)
- `valid_until` has passed (*offer expired*)
- the store already holds a receipt for this `offer_nonce` (*offer already paid*)
- the offer’s `price` or `asset` differ from the x402 payment requirements (*offer does not match the payment requested*)
- the service is not `Active` (*service is Suspended*, and so on)
- `offer.terms_hash` is not the service’s current terms
- stake or `max_claim` are below the policy minimums
- the offer signature does not verify against the key at `offer.key_version`
- the terms lack a required predicate (*warranty lacks predicate P6*)

**After paying**, it reads the receipt from `PAYMENT-RESPONSE` and checks the signature, that the receipt cites this offer, names your address as buyer and the settlement transaction as payment, and that `request_hash`, `response_hash`, `response_bytes` and `status` match what was sent and received. Then it evaluates every predicate in the terms, reading the oracle for P6.

| `WarrantyRecord` field | Meaning |
| --- | --- |
| `offer`, `receipt` | The signed offer and receipt, decoded |
| `duplicate` | A second receipt for the same payment, if the seller sent one (P1 evidence) |
| `terms`, `service` | The terms paid under and the service’s state at payment time |
| `problems` | Receipt checks that failed. Non-empty means the response is **untrusted** and not claimable |
| `breaches` | Predicate IDs the receipt proves were breached |
| `claimableUntil` | Unix seconds after which no claim is possible: `served_at + claim_window` |

## 4. Claim when a promise is broken

```ts
if (warranty?.breaches.length) {
  const result = await agent.claim(warranty);      // uses the first breach unless you pass a predicate ID
  // result: { outcome: { paid: 50000000n } | { rejected: "not_proven" | "not_verifiable" }, transaction: "…" }
}
```

A proven breach pays your agent from the seller’s stake in the same transaction: `min(max_claim, stake left)`. The SDK waits one ledger if needed so the claim is never rejected for landing in a ledger closed before `served_at`. Contract errors read as names (`WindowClosed`, `AlreadyClaimed`, `SlashRateLimited`) rather than numbers.

> **What your agent gets**
>
> A paid call either matches what the seller promised, or produces evidence that pays out automatically. A service whose stake falls below its minimum is suspended, and agents with a policy stop paying it at once.

Next: [tune the policy](https://lopw.com/docs/guides/bonded-only.html), [file a claim](https://lopw.com/docs/guides/file-claim.html), or read the [predicates](https://lopw.com/docs/protocol/predicates.html) your agent evaluates.
