How an agent should handle a 402 quote that changed

Last updated: 10 October 2026.

Short answer: treat every 402 quote as a one-time offer and judge it on its own. Before paying, refuse it if the payment request differs from the advertised price, the price is over your cap or budget, or it has expired. You may ask once for a fresh quote and judge that from scratch. After paying, never pay a new quote for the same resource: retry with the same proof, then report a failure.

What counts as a changed quote?

Four things look alike from the payer's side:

  1. The payment request does not match the price. The JSON says 100 sats; the payment request asks for 400.
  2. The quote expired before you paid. The expiry time has passed, or is a second away.
  3. A fresh quote has a new price. You asked again after an expiry, and the number is different.
  4. The seller asks again after payment. You paid, retried with the proof, and got another 402, often with a higher price.

The first three happen before any money leaves. The fourth happens after, and it is the one that costs money twice.

What does the decision look like in code?

function decide(q, url, paid, { cap, budgetLeft }) {
  if (paid.has(url)) return 'retry-with-same-proof'; // never a second payment for one resource
  if (q.amount !== q.advertised) return 'refuse';     // payment request differs from the price
  if (q.amount > cap || q.amount > budgetLeft) return 'refuse';
  if (!(q.expiresAt > Date.now() + 1000)) return 'ask-once-for-a-fresh-quote';
  return 'pay';
}

A fresh quote goes through the same function with no memory of the old price, so a lower price is fine and a higher one still has to fit the cap and the budget. Ask for a fresh quote at most once per resource; a seller whose quotes keep expiring is a seller to stop paying.

What should happen after payment?

Record the resource as paid the moment the wallet confirms, and count the amount against the budget then, even if delivery fails. If the seller answers with a server error, retry a few times with the same proof. If it answers 402 again, stop: report the result as paid but not delivered, with the proof, so a person or a refund request can follow it up. Never let the retry loop reach the wallet.

How do I test this?

Run the payer against a mock seller that changes its quote, and judge it by what left a mock wallet, not by what the payer reports. Useful cases: a payment request larger than the price, an already expired quote, a second 402 with a higher price after payment, and a seller that answers 402 forever. Add an honest seller, so a payer that refuses everything fails too. Keep everything on 127.0.0.1, so no real money or host is involved.

Is there a ready-made kit?

Payer Safety Tests covers these five cases and nine more, in two mock dialects that follow L402 and x402 headers and field names (28 checks), with a mock wallet, safe reference payers in Node and Python, and a deliberately naive payer that fails. Every value is a mock (no real macaroons, signatures or invoices): they test the payer's decisions, not its cryptography or a real seller. A full run takes about 30 seconds, offline, with no real funds. A$15, paid on-chain in bitcoin, MIT licence: see the shop's listing (ref=guide3). Order by Nostr DM: buy payer-safety-tests ref=guide3.

FAQ

Dated 10 October 2026.

Should the payer ever accept a higher price?

Only as a new decision, before it has paid for that resource, and only within the same cap and budget. If your task names an expected price, treat anything above it as a reason to stop and ask.

Why not pay the second 402, if it is only a few sats?

Because a seller that asks twice can ask a hundred times. The rule is one payment per resource, not one payment per answer.

What if the payment went through but the wallet call timed out?

Treat it as paid. Count it against the budget and do not pay again until you can check the wallet's own record.

How much margin should an expiry check leave?

Enough for the payment to arrive before the deadline. The example uses one second for a local mock; a real wallet and network need more.

Does this cover a seller that is honest but slow to settle?

Partly. A slow seller looks like a hang or an error after payment, so the same rule applies: retry with the same proof, then report the failure.