Skip to content

agentpay-x402 0.3.0 — payment-safety hardening

Latest

Choose a tag to compare

@romudille-bit romudille-bit released this 19 Jul 19:03
· 112 commits to main since this release

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 the 402 demands more than min(remaining, quote x 1.05).
    A gateway advertising $0.001 and demanding $0.50 is refused, not paid.
    AgentPayClient.call_tool raises BudgetExceeded (was ValueError).
  • New exported exception: agentpay.PrePaymentError.

Payment safety

  • Spend counts at broadcast, not at HTTP 200 — a payment whose tool call then
    fails still counts against spent()/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 as uncertain_settlement.
  • Policies apply to external x402 URLs tooallowed_tools / max_per_tool /
    rate_limit now run before routing, so URL targets can't bypass the allowlist.
  • Authorization validity clamped to 600s before signing — a hostile 402 can't
    request a year-long validBefore.
  • Base settlement records the signed amount, not the amount advertised in the
    402 body.

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-REQUIRED header 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.