---
title: "EIP-3009 signature verifier for x402 (free) | Settlens"
description: "Free EIP-3009 signature verifier for x402: recover the signer of a PAYMENT-SIGNATURE and check its recipient, amount and time window offline. No RPC, no wallet."
url: https://settlens.com/tools/eip-3009-verifier
last_updated: 2026-10-13
---

# Verify an EIP-3009 payment signature

> **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.

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.

[Verify a payment signature](https://settlens.com/tools/eip-3009-verifier#verifier) [How EIP-3009 works](https://settlens.com/learn/eip-3009)

Free and offline: no RPC, no wallet, no payment key.

## Verify a payment signature

The sample pays the example request of the [x402 checker](https://settlens.com/tools/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](https://settlens.com/privacy#mcp-endpoint).

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.

_Where each EIP-712 domain field comes from_

| 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` |

1. **Recover the signer**

   The EIP-712 digest of the `TransferWithAuthorization` message is computed and the signer recovered from the 65-byte signature. A high-s signature is refused (see EIP-2). The signer must equal `authorization.from`.

2. **Check the binding**

   `authorization.to` must equal `payTo` and `authorization.value` must equal `amount`. The asset is bound through the domain: a signature for another token does not recover to the payer.

3. **Check the time window**

   The check time must be strictly after `validAfter` and strictly before `validBefore`, as the EIP-3009 reference implementation requires.

**The sample PAYMENT-SIGNATURE, decoded**

```json
{
  "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.

verify\_payment\_signature the sample, four inputs

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

_Real answers computed with the Settlens server code when this page was built._

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](https://settlens.com/product/verify) 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_transaction` MCP 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, with the sample**

```shell
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 Code**

```shell
claude mcp add --transport http settlens https://settlens.com/mcp
```

Every argument and output field is in the [verify_payment_signature reference](https://settlens.com/docs/mcp#verify_payment_signature). Pilot participants run the same check offline with `settlens verify-payment`, documented in the [CLI reference](https://settlens.com/docs/cli).

> **Check the request first**
>
> Before a payment is signed, the [x402 checker](https://settlens.com/tools/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.

## 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.

[Request a pilot](https://settlens.com/contact) [See offline verification](https://settlens.com/product/verify)

## Sources

1. [EIP-3009: Transfer With Authorization](https://eips.ethereum.org/EIPS/eip-3009) — Ethereum Improvement Proposals
2. [EIP-712: Typed structured data hashing and signing](https://eips.ethereum.org/EIPS/eip-712) — Ethereum Improvement Proposals
3. [EIP-2: Homestead hard-fork changes (low-s signatures)](https://eips.ethereum.org/EIPS/eip-2) — Ethereum Improvement Proposals
4. [x402 exact scheme on EVM](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md) — x402 Foundation
5. [x402 V2 HTTP transport](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md) — x402 Foundation
6. [CAIP-2: Blockchain ID Specification](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) — Chain Agnostic Standards Alliance
