Skip to content

x402 V2 compatibility: V1-shaped requirements and PAYMENT-SIGNATURE decoding break @x402 SDK 2.25 clients #22

Description

@lpsmurf

We resell Cryptorefills products to AI agents over x402, fulfilled through x402.cryptorefills.com on Base. Our first mainnet purchase on 2026-09-13 used the official @x402/core and @x402/evm SDK at 2.25.0, and it hit two compatibility issues. We worked around both on our side. Posting here in case the fix belongs upstream and to help others who run into the same errors.

1. PAYMENT-REQUIRED says x402Version: 2, but its requirements use the V1 shape

POST /v1/orders (with X-Preferred-Network: base) returns a challenge whose accepts[] entries look like this:

{
  "x402Version": 2,
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "maxAmountRequired": "590000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo": "0x…",
    "extra": { "name": "USD Coin", "version": "2", "decimals": 6 }
  }],
  "resource": "",
  "expiresAt": ""
}

Compared with the V2 PaymentRequirements in the x402 spec:

  • maxAmountRequired is the V1 field name. V2 uses amount.
  • maxTimeoutSeconds is missing.

What happens with the SDK at 2.25.0:

  • x402Client.createPaymentPayload() throws Invalid amount: undefined — use decimal notation. The spend controls added in 2.23 read amount.
  • After copying the value into amount, EIP-3009 signing throws Cannot convert NaN to a BigInt, because validBefore is computed from maxTimeoutSeconds.

Suggested fix: include amount and maxTimeoutSeconds in V2 challenges. Keeping maxAmountRequired alongside would stay backward compatible.

2. The SDK's PAYMENT-SIGNATURE header is rejected

The header produced by x402HTTPClient.encodePaymentSignatureHeader() is standard base64 of the full V2 PaymentPayload, including accepted and resource. Retrying POST /v1/orders with it returns:

400 {"error":"processing_error","message":"Invalid PAYMENT-SIGNATURE: Failed to decode PAYMENT-SIGNATURE header"}

What the endpoint does accept is the same wrapper as the Solana flow: base64url of

{ "x402Version": 2, "scheme": "exact", "network": "eip155:8453", "payload": { "authorization": { }, "signature": "0x…" } }

We haven't isolated whether the decoder fails on the alphabet (base64 vs base64url) or on the extra V2 fields. Either way, a stock x402 V2 client can't pay this endpoint without a custom encoder.

Suggested fix: accept the standard V2 PaymentPayload: standard base64, with accepted and resource present.

3. Minor: gift cards and eSIMs also require beneficiary_account

Omitting beneficiary_account for a non-mobile product returns {"error":"processing_error","message":"item.beneficiary_account is required"}. We expected it to be optional there, since the voucher goes to email. Either documenting that it's required for every item, or defaulting it to email, would help agents get this right on the first try.


Environment: Node 22, @x402/core and @x402/evm 2.25.0, Base mainnet USDC. Happy to test a fix. Contact: info@hfsp.xyz

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions