Verify an EIP-3009 payment signature
Paste an x402 payment requirement and the PAYMENT-SIGNATURE that answers it. Settlens rebuilds the EIP-712 domain, recovers the signer and checks that the authorization pays the advertised recipient the advertised amount inside its time window.
Free and offline: no RPC, no wallet, no payment key.
In short
The Settlens EIP-3009 verifier is a free browser tool for x402 exact EVM payments: paste the payment requirement and the PAYMENT-SIGNATURE payload, and it rebuilds the EIP-712 domain, recovers the signer and checks the recipient, amount and validAfter/validBefore window. Offline: no RPC, no wallet.
Verify a payment signature
The sample pays the example request of the x402 checker. It was signed with a public test key, never a real wallet, for a 60-second window; the sample sets the check time inside it.
Where to find the values
The requirement is one entry of accepts in the resource's PAYMENT-REQUIRED header. The payload is the PAYMENT-SIGNATURE header the client sent with its retry. Check the requirement the server advertised, not the copy in the payload's accepted field.
What happens to what you paste
Your browser sends it to the Settlens MCP endpoint, which runs the offline verify_payment_signature tool in memory and keeps no copy. A signed authorization can be submitted on chain by anyone who holds it until validBefore, so prefer expired captures. Pilot participants can run the same check locally with settlens verify-payment. Details in the privacy notice.
The verdict, the recovered signer and each binding and time check appear here.
How the signature is checked
Everything needed is in the requirement and the payload: no RPC call, no block explorer and no private key.
| Domain field | Taken from | In the sample |
|---|---|---|
name | requirement.extra.name | USDC |
version | requirement.extra.version | 2 |
chainId | The number in eip155:<id> | 84532 |
verifyingContract | requirement.asset | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
-
Recover the signer
The EIP-712 digest of the
TransferWithAuthorizationmessage is computed and the signer recovered from the 65-byte signature. A high-s signature is refused (see EIP-2). The signer must equalauthorization.from. -
Check the binding
authorization.tomust equalpayToandauthorization.valuemust equalamount. The asset is bound through the domain: a signature for another token does not recover to the payer. -
Check the time window
The check time must be strictly after
validAfterand strictly beforevalidBefore, as the EIP-3009 reference implementation requires.
{
"x402Version": 2,
"resource": {
"url": "https://api.example.com/premium-data",
"description": "Access to premium market data",
"mimeType": "application/json"
},
"accepted": {
"scheme": "exact",
"network": "eip155:84532",
"amount": "10000",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
"maxTimeoutSeconds": 60,
"extra": {
"name": "USDC",
"version": "2"
}
},
"payload": {
"signature": "0x891a819dc49005e71effabe634613e1369899c3560b2c8528f6683e3ec8720fa28978b59ff09405aa6ca9a89712b7cb02d171443a755027d8d2a66dab29be3b61b",
"authorization": {
"from": "0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a",
"to": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
"value": "10000",
"validAfter": "1791885570",
"validBefore": "1791885630",
"nonce": "0xaf4e5ec1828f3f4bde1bd708e9cfa238f4336b2f95736111a4b591ea3c916d07"
}
}
}
payload.authorization holds the signed TransferWithAuthorization fields and payload.signature the 65-byte r || s || v signature over them. accepted is the client's copy of the requirement it chose; the verifier checks against the requirement you paste.
The nonce is 32 random bytes. The token contract records it when the authorization is used, which is how replays fail on chain.
What a rejection looks like
Each check is reported on its own, so the reasons say what to fix: an expired window, a changed amount or the wrong recipient.
- verified
The sample, checked at 2026-10-13T10:00:00Z
Recovered 0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a: every check passed.
- rejected
The same payment one minute after validBefore
authorization is outside its validAfter/validBefore window (EIP-3009 requires validAfter < now < validBefore).
- rejected
The value raised to 25000 after signing
Recovered signer 0x1b20ee3930a9b2d8fd2f70548b3d84decd3d332d does not match authorization.from 0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a. authorization.value does not match requirement.amount.
- rejected
Checked against a requirement with another payTo
authorization.to does not match requirement.payTo.
Raising the value after signing breaks two checks at once: the amount no longer matches the requirement, and the signature no longer recovers to the payer because the signed message changed.
The same verification runs in the Verify stage of a Settlens assessment, which also checks Solana signers and facilitators.
What the verifier does not check
- No chain state. No balances, so a verified authorization can still fail to settle for lack of funds.
- No replay detection. It does not check whether the nonce was already used on chain (
authorizationState). - No settlement. A verified signature does not prove a transfer happened.
- Not the token contract. The domain name and version come from the requirement; Settlens does not confirm they match the contract deployed at
asset. - EOA signatures only. Only 65-byte ECDSA signatures are recovered. Smart contract wallet signatures (EIP-1271) are rejected.
- EIP-3009 only. Permit2 payloads of the exact EVM scheme are not verified, and the requirement's scheme is not checked to be
exact. - EVM only here. Solana transactions are checked by the
verify_solana_transactionMCP tool.
Use it from your agent or a terminal
The verifier is a page in front of a public MCP tool. An auditor or an agent can call it directly.
curl -s https://settlens.com/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"verify_payment_signature","arguments":{"requirement":{"scheme":"exact","network":"eip155:84532","amount":"10000","asset":"0x036CbD53842c5426634e7929541eC2318f3dCF7e","payTo":"0x209693Bc6afc0C5328bA36FaF03C514EF312287C","maxTimeoutSeconds":60,"extra":{"name":"USDC","version":"2"}},"payload":{"signature":"0x891a819dc49005e71effabe634613e1369899c3560b2c8528f6683e3ec8720fa28978b59ff09405aa6ca9a89712b7cb02d171443a755027d8d2a66dab29be3b61b","authorization":{"from":"0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a","to":"0x209693Bc6afc0C5328bA36FaF03C514EF312287C","value":"10000","validAfter":"1791885570","validBefore":"1791885630","nonce":"0xaf4e5ec1828f3f4bde1bd708e9cfa238f4336b2f95736111a4b591ea3c916d07"}},"now":"2026-10-13T10:00:00Z"}}}'
claude mcp add --transport http settlens https://settlens.com/mcp
Every argument and output field is in the verify_payment_signature reference. Pilot participants run the same check offline with settlens verify-payment, documented in the CLI reference.
Check the request first
Before a payment is signed, the x402 checker decides whether the request should be paid at all.
Questions about the EIP-3009 verifier
Does the verifier need my private key or an RPC node?
No. It recovers the signer from the signature and the signed fields alone. It never asks for a key, never connects to a chain and never pays or settles anything.
Why is the signature valid but the payment rejected?
The signature only proves who signed. The payment is verified when the authorization also pays the requirement's payTo the exact amount and the check time is inside the validAfter to validBefore window. Without a check time, the current time is used, so an old capture is outside its window.
Does a verified result mean the payment settled?
No. It means the authorization is correctly signed and bound to the requirement at the check time. Balances, nonce reuse and settlement are decided on chain.
Are smart contract wallets and Permit2 supported?
No. Only 65-byte ECDSA signatures from externally owned accounts and EIP-3009 TransferWithAuthorization payloads are verified. EIP-1271 signatures and Permit2 payloads are rejected or out of scope.
Sources
Verify payments as part of an assessment
A pilot checks one paid endpoint or facilitator end to end, including how its facilitator handles a forged signature, with evidence your partners can verify.