All posts
x402September 11, 2026·8 min read

Inside EVIDIQ's x402 Pay-Per-Call MCP Server

Inside EVIDIQ's x402 Pay-Per-Call MCP Server

The first time a developer sees HTTP 402 in production, they usually assume it's a misconfigured proxy. It's not. It's a deliberate challenge: "the resource exists, but you haven't paid yet." We've spent the last several months building EVIDIQ around that one status code, and what follows is the actual wire protocol our x402 pay-per-call MCP server speaks — every header, every field, every failure mode we've debugged ourselves.

The Wire Protocol, Byte by Byte

An x402 pay-per-call MCP server is an HTTP endpoint that gates Model Context Protocol tool calls behind an on-chain micropayment. A client POSTs to /mcp, gets a 402 challenge, signs an EIP-3009 transferWithAuthorization off-chain, retries with an X-PAYMENT header, and the server verifies, settles on X Layer in USDT0, then runs the call. EVIDIQ operates exactly this flow at evidiq.dev/mcp.

The short version: HTTP 402 stops being a joke the moment it carries a settlement path.

Here's the round-trip as it actually happens on our server:

  1. Client opens a JSON-RPC request — tools/call for verify_agent, with { agent_url: "..." }.
  2. We respond 402 Payment Required with a WWW-Authenticate header containing a base64-encoded payment challenge.
  3. Client parses the challenge, signs a transferWithAuthorization for the quoted amount, and sends the same request again — this time with X-PAYMENT: <base64-signed-payload>.
  4. Our settler verifies the signature, pulls the funds on X Layer, runs the trust probe, and returns the JSON-RPC result.

No session cookies. No API keys sitting in .env. Every call is a fresh, atomically-priced transaction. Our settler either succeeds in full — payment cleared, probe ran, signed report returned — or it fails closed and the client gets a clean 402 with an error code.

If you want to try it without writing a client first, the EVIDIQ playground lets you paste a challenge, sign it, and watch the retry happen in the browser. Honest take: most people learn the protocol fastest by breaking it once on purpose.

Reading an accepts[] Object

The challenge that comes back in WWW-Authenticate is x402 v2, and its body is an accepts array. We send exactly one entry today, but a client should still loop over the array — that's the spec, and ignoring the [] has bitten integrators more than once.

Each accepts[i] object looks roughly like this:

{
  "scheme": "exact",
  "network": "x-layer",
  "amount": "10000",
  "asset": "USDT0",
  "payTo": "0xEVIDIQ...settler",
  "extra": {
    "name": "USD₮0",
    "version": "1"
  }
}

Field by field:

  • scheme — "exact". The only scheme we accept right now. Anything else ("upto", "stream", custom) gets a hard reject before we even look at the signature. If a client blindly signs, it pays for a call that will never run.
  • network — "x-layer". The chain id. Don't infer it from a chainlist lookup — read it from the challenge. We chose X Layer for sub-cent fees and a USDT0 contract that's already deployed and audited.
  • amount — base-10 string of the smallest unit. For USDT0 that's 6 decimals, so 10000 is $0.01. Off-by-decimal bugs here are catastrophic; a client that treats this as a float will eventually pay $10,000 for a $0.01 probe.
  • asset — "USDT0". The token symbol. The real on-chain address is the EIP-712 domain, not this string — never resolve a token from asset alone.
  • payTo — the recipient. This is our settler address on X Layer. The funds land here and are then routed per our settlement policy.
  • extra.name / extra.version — used to construct the EIP-712 domain separator (USD₮0, 1). If your client hardcodes "USDT" from a copy-paste, the signature will verify against the wrong domain and fail settlement.

The biggest mistake we've seen in integration logs: clients treat accepts[] as a single object. It isn't. Loop it, prefer the lowest-amount match, and only sign when scheme === "exact" is in the set.

EVIDIQ blog illustration 1

EIP-3009 Without the Cryptography Lecture

EIP-3009 gives us transferWithAuthorization, a message that says: "I, the holder of this balance, authorize address X to move N units of token T from me, at any time before timestamp Y, exactly once, identified by nonce Z." The signature is over an EIP-712 typed struct, which means the client can produce it offline with no gas and no chain access. That's the entire trick — the payer doesn't need ETH on X Layer, just USDT0.

Our settler takes that signed blob and calls transferWithAuthorization on the USDT0 contract on the payer's behalf. The contract checks the signature against ecrecover, verifies the nonce hasn't been used, checks validBefore, and moves the tokens. One transaction, fully on-chain, atomic with the MCP call's settlement.

The sequence our settler runs:

  1. Decode the base64 X-PAYMENT header into the EIP-3009 payload.
  2. Reconstruct the EIP-712 domain from accepts[].extra.
  3. Call transferWithAuthorization on USDT0 with the payer's signature.
  4. Wait for receipt.status === 1 on X Layer.
  5. Only then run verify_agent() and return the JSON-RPC result.

If step 4 fails, step 5 never happens. The client gets a 402 with an error sub-code, and the funds either stayed put (revert) or were moved but never settled against a tool call — that path is logged and surfaced in the EVIDIQ Sentinel docs, our tamper-evident audit trail.

Worth noting: EIP-3009 is what makes x402 viable for sub-cent calls. Without it, every probe would burn more on gas than the probe itself costs. With it, $0.01 is a real, profitable price point for an agent operator to charge — and the math on a $0.01 verification is what makes our x402 pay-per-call MCP server worth running as a service at all.

What Happens on a Bad Signature or Late Nonce

Things go wrong. Most of the time, they go wrong in the client's signer, not on our side. Here's a field guide so you can debug without pinging us.

  • Expired validBefore — the EIP-3009 message included a deadline. If the client retries too late, the USDT0 contract reverts with authorization is expired. We surface this as a 402 with error: "expired". Fix: set validBefore to now + 60 seconds, and re-fetch the challenge if you're outside that window.
  • Reused nonce — EIP-3009 nonces are single-use, on-chain. A client that retries the same signed blob twice will see the first call succeed and the second revert with authorization already used. Fix: every retry must use a freshly signed payload with a fresh nonce. Don't cache.
  • Wrong domain separator — the EIP-712 hash includes name, version, chainId, verifyingContract. Our challenge uses name: "USD₮0", version: "1", chainId: 196 (X Layer). Hardcode any of those wrong and ecrecover returns a garbage address. The USDT0 contract then reverts on invalid signature. Fix: read every domain field from accepts[].extra and the chain id from accepts[].network — never from a constant.
  • Insufficient balance or allowance — transferWithAuthorization still needs the payer to hold USDT0. If the wallet is empty, you get a clean ERC-20 revert. Fix: top up and try again; this isn't an x402 issue.
  • Amount mismatch — our settler checks that the signed amount matches accepts[].amount exactly. If the client signs 9999 against a challenge for 10000, the call is rejected before any gas is spent. Fix: sign the amount from the challenge, character for character.

We log all of these (without payload content) so integrators can correlate. For the full forensic flow including how we anchor evidence on 0G Storage, see the EVIDIQ Notary docs. If you're the operator of the agent being verified, the EVIDIQ Operator docs walks through the other side of the call.

The signature we return — an EIP-191 signed trust score report — is itself verifiable. Any client can recover the EVIDIQ public key from it, re-hash the canonical report, and confirm the contents match. We made it deterministic on purpose. A trust score that nobody can re-derive is just an opinion.

EVIDIQ blog illustration 2

Frequently Asked Questions

The Agent Skill at evidiq.dev/skill.md and the MCP install tools (how_to_install, get_evidiq_skill) are MIT-licensed and free. The verify_agent tool — the one that actually runs the live probe and returns the trust score — is paid per call via x402. We think this is the only honest pricing: the cheap metadata stays free, the expensive truth costs what it costs to produce.

Give your agent the trust skill:

curl -s https://evidiq.dev/skill.md
E

EVIDIQ Team

The EVIDIQ team builds the trust layer for the AI agent economy — verifying agent identity and capability, scoring risk, and anchoring every verdict on-chain so agents can decide who to trust before value moves.

More from EVIDIQ Team →
Inside EVIDIQ's x402 Pay-Per-Call MCP Server — EVIDIQ