The signature has expired. Signing it again will not help. Your agent is stuck in a loop because every retry is reusing the same expired "check."
This loop—where the charge succeeds but the credential is not accepted—usually gets stuck in one of three places. Let's check them in order and find the exact problem.
Step 1: Check whether the authorization has expired
This is the most common loop trap. The authorization you signed contains a validBefore field. It shows the exact time when the authorization expires. Once that time has passed, the settlement provider rejects it, no matter how much money is in the wallet.
[What to do] Check the validBefore timestamp in the payment credential you submitted (in the PAYMENT-SIGNATURE header). See whether it is already in the past.
[How to do it]
If you are using the
x402tracediagnostic tool, run:x402trace explain ./x402trace.jsonl. If you see output likevalidBefore expired 97s ago, this is the problem. It will tell you how long ago it expired and suggest a fix:re-sign the authorization with a later validBefore (typical: now + 300s).If you are not using
x402trace, check the logs of the request sent by your agent. Find the full authorization JSON sent to the settlement provider, look at thevalidBeforefield, and compare it with the current time manually.
[Done when] The validBefore timestamp is in the future, with at least a few minutes of extra room.
Step 2: Check whether the server accepts the credential format
Another possible cause of your retry loop: some fields in the credential do not use the format the server expects, so every retry is treated as an invalid request.
[What to do] Check the network identifier and amount format in the payment credential you are submitting.
[How to do it]
Use a free diagnostic tool such as
three.wsto simulate verification. Send the failed authorization request body to its/api/x402/debugendpoint. It will return structured error details. For example, it may tell you:You submitted
x402Version: 1, but the server requiresVersion 2.You wrote
networkas"base", but the server requires the standard CAIP-2 format"eip155:8453".You wrote the amount as
"0.01", but the protocol requires an integer string in atomic units, such as"10000".
[Done when] The diagnostic tool returns verdict: valid, which means the credential format is accepted by the server.
Branch: The credential is valid, but the server does not recognize the payee
The credential itself is valid, but during its final check the server finds that it does not match what it expected.
Case A: The payee address (payTo) is wrong
What happens: The
recipientin the credential does not match thepayToaddress the server asked you to pay.Fix: Make sure you are signing to the
payToaddress given in the server's 402 response, not some other address.
Case B: You are using an outdated header name
What happens: The server returns 402, but your client cannot find the
x-payment-requiredheader needed for payment.Why: You are still using the x402 v1 header name
x-payment-required, but the server follows the v2 standard and returnspayment-required.Fix: Check your client code and change the header name it reads to
payment-required.
High-risk warning: A retry loop can really burn through your budget. If the server returns 402 even for invalid credentials, your agent will keep repeating the loop: receive 402 → sign → retry. One team's production system lost $47,000 in 11 days because of this kind of loop. Every loop spends money on verification, and that money does not come back.
Final check
After completing the checks and fixes above, run one full single payment test.
How to verify: Let the agent make one payment request in debug mode. Watch the logs. You should see:
The first request receives
402 Payment Required.The agent creates a new signature (make sure
validBeforeis in the future).The retry request is sent with the
PAYMENT-SIGNATUREheader.Finally, it receives
200 OKand the data you want, instead of another402.


