agentpay-x402 0.3.0 — payment-safety hardening
Breaking release. The buyer SDK now refuses to overspend, double-pay, or
trust a hostile 402. It comes out of the July 2026 gateway code review. If you
relied on the budget cap silently clamping the amount you pay, you'll now get a
BudgetExceeded exception instead — that's the one behavior change to handle on
upgrade.
pip install --upgrade agentpay-x402 # or: agentpay-x402[base]Why upgrade
Every change closes a way an agent's wallet could have been drained faster than
its budget allowed.
Breaking
- The budget cap now binds the amount actually paid.
Session.call()hard-fails
before signing or paying if the402demands more thanmin(remaining, quote x 1.05).
A gateway advertising $0.001 and demanding $0.50 is refused, not paid.
AgentPayClient.call_toolraisesBudgetExceeded(wasValueError). - New exported exception:
agentpay.PrePaymentError.
Payment safety
- Spend counts at broadcast, not at HTTP 200 — a payment whose tool call then
fails still counts againstspent()/remaining(), so pay-then-fail loops can't
overspend the cap. - No fallback after funds move — a fallback tool is only retried on
PrePaymentError(nothing transmitted); post-payment failures propagate. One
session.call()can no longer pay twice. - Transmitted EIP-3009 authorizations are treated as potentially spent — a
non-200 after the signed auth left the wire never re-pays on Stellar and is
recorded asuncertain_settlement. - Policies apply to external x402 URLs too —
allowed_tools/max_per_tool/
rate_limitnow run before routing, so URL targets can't bypass the allowlist. - Authorization validity clamped to 600s before signing — a hostile
402can't
request a year-longvalidBefore. - Base settlement records the signed amount, not the amount advertised in the
402body.
Concurrency
- Budget is reserved before payment under a re-entrant lock — concurrent
session.call()s can no longer both clear the cap and jointly overspend. Fixes a
double-release bug that drove the reserved total negative under load
(regression-tested). - Timed-out submits are polled for their result instead of blindly retried,
removing a double-send window on slow settles.
Added
- x402 v2
PAYMENT-REQUIREDheader fallback — the SDK reads the v2 header form
in addition to the JSON body, and rejects endpoints it can't score rather than
paying blindly.
Full detail, per-issue, in CHANGELOG.md.