"The charge succeeded but the API still says payment is not finished." If you are checking the transfer record on a block explorer, those two pieces of information are not on the same timeline.
Yesterday someone in a group posted a screenshot: USDC was sent, confirmed on-chain, but the data API still returned 402. He thought he was overcharged. I asked him to post the full request and response logs. It turned out that after signing, he did not return the PAYMENT-SIGNATURE header to the original server.
x402 is not "transfer first, then get the content." It is a pending signed authorization that travels with the request. The server must confirm it before settlement is triggered. Your wallet may show the USDC deduction on-chain, but the server never received proof of payment. Many people get confused here because their wallet balance really did drop, so they think the flow is complete.
Step 1: Confirm whether you are missing the "receipt" step
Open the Network tab in the browser developer tools (F12) and find the request to that API.
Check two things:
Does the request header contain
PAYMENT-SIGNATURE?Does the response header contain
PAYMENT-RESPONSE?
Completion check: You see settlement-related fields in PAYMENT-RESPONSE. Only then did the server accept the payment. (Source: x402 protocol specification, GitHub, 2026-04-01)
If only the on-chain transfer succeeded but these header interactions are missing, it is like putting money into a mailbox without telling the seller how much you put in.
Step 2: Troubleshoot why the wallet was charged but the API did not accept it
Case A: You did not send the signature back to the original request (most common)
What happens: The wallet popup asks you to sign. You click it, see a successful transfer, and close the page.
What is wrong: Signing only gives authorization. The rest of the flow happens on the facilitator side. The correct x402 flow is: first get the 402 quote -> second sign but do not broadcast -> third retry the original request with PAYMENT-SIGNATURE -> the server verifies it and only then triggers on-chain settlement. (Source: Cloudflare x402 protocol explainer, 2025-09-22)
What to do: Use a wallet companion client such as purl or an SDK to send the request. It automatically completes the "retry with signature" step. A hand-written curl command often misses this return step. (Source: Stripe x402 documentation, 2026-03-04)
Case B: The signature expired (validBefore)
What happens: The charge succeeded, but the API returns 402 and the logs contain invalid_exact_evm_payload_authorization_valid_before.
What to do: Use the x402trace explain tool to analyze the captured logs and check the exact expiration timestamp. (Source: x402trace NPM package documentation, 2026-05-29)
Completion check: If you see a hint like validBefore expired 97s ago, fix: re-sign with later validBefore, you need to start a complete 402 flow again. Do not reuse the old signature.
Case C: Wrong network (testnet signature sent to mainnet)
What happens: The wallet charged testnet USDC, but the API connects to the mainnet facilitator.
What to do: Check whether the network the wallet is connected to matches the network field required by the API. A typical root cause of invalid_payload in x402-relay lasting more than 15 days is a network mismatch: the client signs for testnet but sends the result to the mainnet settlement endpoint. (Source: x402-sponsor-relay Issue #110, 2026-02-22)
Case D: The origin returned 4xx/5xx, so settlement was skipped
What happens: The signature verification passed, but the data source itself returned an error, such as 500. When this happens, the x402 protocol skips settlement and does not really charge. (Source: AWS WAF documentation, Amazonaws, 2025-10-15)
What to do: Check the HTTP status code returned by the original API. If it is a 500-class error, the on-chain "charge" was not actually completed and will roll back later. Do not sign again. Fix the API first.
High-risk reminder: x402 payment authorization is single-use. If the same PAYMENT-SIGNATURE is submitted again, the protocol returns a new 402 refusal. (Source: AWS WAF documentation, Amazonaws, 2025-10-15) If your script retries automatically after an error and creates a new signature each time, it may create multiple pending settlement authorizations. Check the facilitator's "pending settlements" list to make sure there is no buildup.
Final verification
Open your facilitator's /settle or /verify API log, or the corresponding dashboard, and check the status of your payment-identifier.
Completion check: The status changes from pending to settled, and the upstream API returns a 2xx response with content. If there is only an on-chain record but no settlement record, you are stuck at the "sign and send back" step. Repeat the retry with PAYMENT-SIGNATURE.
Next step: Add a check in your proxy logic. After receiving 402, wait until the settlement field in PAYMENT-RESPONSE is true. Only then is the payment complete. Do not treat the wallet's "success" popup as final confirmation. Expected waiting time: about 650ms per block on Injective. Other EVM chains depend on network congestion. (Source: Injective x402 documentation, 2026-08-03)


