/v1/buyer/* endpoints
break the buyer flow down into discrete primitives that mirror the
TypeScript @leash/buyer-kit one-to-one:
| Endpoint | Purpose | IO |
|---|---|---|
POST /v1/buyer/quote | Probe a URL, decode payment-required, return accepts[] | HTTP |
POST /v1/buyer/policy/evaluate | Pure RulesV1 gate (host / budget / per-call ceiling) | None |
POST /v1/buyer/payment/prepare | Build an unsigned SPL TransferChecked from buyer ATA | None |
POST /v1/buyer/payment/execute | Replay the seller request with X-PAYMENT + ingest receipt | HTTP |
POST /v1/buyer/receipt/finalize | Compute receipt_hash for a draft (pure) | None |
POST /v1/buyer/receipt/verify | Verify a chain (hashes / nonces / prev_receipt_hash links) | None |
GET /v1/buyer/networks | Buyer-side network catalog | None |
GET /v1/buyer/currency | Stablecoins payable on the caller-scoped network | None |
Flow at a glance
You can also stop afterpayment/prepare, sign locally, and
broadcast yourself via POST /v1/submit if
you want to skip the API’s seller proxy. payment/execute is the
convenience path; prepare + your own broadcaster is the bare-metal
path.
POST /v1/buyer/quote
Probes a URL with no payment header and decodes the seller’s
payment-required response into a structured accepts[] plus a
network-aware “chosen” pick.
chosen is the entry from accepts[] whose network matches the
caller’s API key, optionally filtered by preferred_currency. When
the seller does not accept the caller-scoped network at all,
chosen is null and you should switch keys (and treasury) to
match the seller’s cluster.
requirements_hash is the SHA-256 of the canonical JSON form of
chosen — the same value the receipt’s
payment_requirements_hash will hold after settlement. Pre-compute
it client-side to fail loudly when the seller’s offer changes
between quote and execute.
502 rpc_error if the probe target is unreachable (DNS, TLS,
timeout). The seller_error field carries any error string the
seller embedded in the payment-required payload — useful when the
seller refuses to quote without authentication.
POST /v1/buyer/policy/evaluate
A pure HTTP wrapper around evaluate from @leash/core. No IO, no
state writes, just the policy gate from
RulesV1.
reason values for a deny decision: replay,
denyHost, allowHost, priceCeiling, dailyBudgetExceeded,
perCallMax. Recording request_hash in your local state and
passing it back via recent_request_hashes is what makes replay
detection work — the API never sees your state between calls.
POST /v1/buyer/payment/prepare
Builds an unsigned SPL TransferChecked from the buyer’s source ATA
to the seller’s payTo ATA. The shape mirrors every other prepare
endpoint — see Prepare → Submit for the
contract.
- Derives
source_token_accountasATA(payer, mint, token_program)— passsource_token_accountexplicitly to override (e.g. when spending as the SPL delegate of an agent treasury). - Derives
destination_token_accountasATA(destination, mint, token_program). - Builds a
TransferCheckedforamountatomic units (the integrity check uses yourdecimalsso the API doesn’t have to fetch the mint). - Drops a
buyer.payment.prepareevent row withphase=preparedso the explorer shows the in-flight transfer. - Auto-watches the destination’s owning agent treasury via
ensureWatchedso any subsequent on-chain activity for that agent shows up in the explorer feed.
POST /v1/submit (if you don’t need the
seller-kit replay) or wrapped into the X-PAYMENT header for
/v1/buyer/payment/execute below.
POST /v1/buyer/payment/execute
The convenience path. The API replays the original seller request
with the buyer-supplied X-PAYMENT header attached, parses the
PAYMENT-RESPONSE, finalizes a spend ReceiptV1, and ingests it
into the receipt store + explorer feed. You get back the seller’s
response body verbatim plus the receipt and tx signature.
402, the facilitator errors, etc.), the API still writes a receipt —
with decision: "rejected" and a non-null failure_reason. The
receipt is the audit trail; you can show it to the user without
guessing what happened.
The expected_payment field is optional but recommended: if the
seller’s settled paymentRequirements (decoded from
PAYMENT-RESPONSE) doesn’t match what you quoted, the receipt’s
price will reflect the actual charged amount, and you can compare
against expected_payment client-side to alert on dynamic-pricing
mismatches.
Indexer follow-up after See Explorer tracking → Sequence 2
for the full buyer-side flow.
/payment/execute. This call
auto-registers the buyer agent (body.agent) on the indexer
watchlist, so the buyer’s spend receipts and any future on-chain
activity for the buyer surface on the explorer automatically.It does not register the seller’s treasury. If the seller
is a Leash payment link (/x/{id}), the paywall already handles
this on its end. If the seller is a third-party x402 endpoint and
you want the matching agent.treasury.fund event for the seller’s
receiving agent to also show up on the explorer, run one
GET /v1/agents/{seller_agent}/treasury/balances call after your
first successful payment to that seller. It’s read-only,
idempotent, free, and registers the PDA + every ATA in one shot.POST /v1/buyer/receipt/finalize
Pure helper that computes receipt_hash for a draft receipt. Useful
when you want to chain receipts client-side without holding the
whole @leash/core library in your runtime.
finalizeReceipt from @leash/core. Idempotent.
POST /v1/buyer/receipt/verify
Verifies a chain of receipts: each receipt_hash is recomputed,
each prev_receipt_hash link is checked, and nonce strictly
increases.
verifyReceiptChain from @leash/core —
identical results, no JS dependency.
GET /v1/buyer/networks
Buyer-side network catalog. Same shape as the seller side, but
named for symmetry with @leash/buyer-kit.
GET /v1/buyer/currency
Just the stablecoins the buyer can settle in on the caller-scoped
network. Ideal for a “Pay with: [USDC ▾]” dropdown.
See also
@leash/buyer-kit— the TypeScript surface these endpoints mirror, including failure-classification ergonomics for the SDK use case.- Payment links — the seller-side endpoint buyers most often pay against.
- Receipts API — what
receipt.publishedmeans and how to query the resulting feed. - Prepare → Submit — alternate flow when you want to broadcast the prepared transfer yourself.

