Skip to content
Under development · Early accessAgorean is live in preview. Come break things.
Put capabilities to work

The x402 review artifact

The open v1 format for a review signed by the wallet that paid an x402 endpoint. Twelve exact lines the client builds itself, one plain message signature, and what a review provider publishes so anyone can check it again. Free for any provider to use.

  • What is it? The exact text a paying wallet signs to review an x402 payment, and what a review provider publishes next to it, so anyone can check the signature without trusting the provider.
  • Who is it for? People who run a review provider, people who write x402 clients, and anyone who wants to re-verify a review they are shown.

The x402 reviews extension carries links: where to read reviews of a resource before paying, and where to review a payment after. It leaves the rest to each provider: what the wallet signs, how the provider checks it, and what it shows. This page is that rest, written once so every provider can use the same one. It names no company. Any provider may adopt it, and anyone may copy this page: it is under the same MIT license as the rest of these docs. This is version 1. Agorean's own position is at the end of this page: Agorean accepts v1 as of 2026-10-02, and its tools write it.

The message#

A review is one message of twelve lines. The client builds it from values it already has: the settlement response it got when it paid, the payTo and price it agreed to in the 402, and its own wallet. Then the wallet signs it. Nobody hands the client this text; the client writes it.

x402 review v1
provider: <host of the write URL, lowercase>
network: <CAIP-2 id, e.g. eip155:8453 or solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp>
payment: <the settlement transaction hash; or the scheme's payment id when there is no transaction>
payer: <the paying wallet: lowercase 0x on EVM, base58 as-is on Solana>
pay_to: <the seller wallet the payment reached, written the same way>
amount: <atomic units paid, an integer>
asset: <the asset's contract address or mint, e.g. the USDC address on that network>
stars: <1 to 5>
note_sha256: <hex sha256 of the note, as UTF-8>
issued_at: <ISO 8601 UTC with seconds, e.g. 2026-10-01T12:00:00Z>
This signature posts a review. It cannot move money or approve spending.

The byte rules. A signature covers bytes, so the bytes have to be the same on both sides.

  • The text is UTF-8. Lines are joined with one line feed (\n, byte 0x0A). No carriage returns, no trailing newline after the last line, no byte order mark.
  • Each field line is the key, a colon, one space, the value. No other spaces or tabs, no blank lines, no extra lines, keys in this order.
  • The first line and the last line are fixed, character for character.
  • provider is the host of the write URL in lowercase, with no scheme, port or path. For https://reviews.example/r/abc it is reviews.example.
  • On EVM networks, addresses and hashes are 0x followed by lowercase hex. On Solana they are base58, exactly as the chain shows them, and payment is the transaction signature.
  • amount is a plain integer in the asset's smallest unit: 10000 for 0.01 USDC. No decimal point, no sign, no leading zeros.
  • stars is one digit from 1 to 5.
  • note_sha256 is the SHA-256 of the note's UTF-8 bytes, as 64 lowercase hex digits. An empty note hashes too.
  • issued_at is UTC to the second, YYYY-MM-DDTHH:MM:SSZ. No fractional seconds, no time zone offset.

Why each line is there#

  • **provider** ties the signature to one site. A message signed for reviews.example is worthless at any other host, so no provider can copy a review from another provider and show it as its own.
  • **network and payment** together name one payment on one chain. One payment gets one review: a provider refuses a second message for the same pair, and the same hash on another chain is a different pair.
  • **payer, pay_to, amount and asset** say who paid whom, how much, and in what. Readers can weigh a review by what it cost, and a provider can check all four against the chain.
  • **stars and note_sha256** fix the rating and the text at signing time. Nobody can raise the stars or swap the note afterwards, not even the provider.
  • **issued_at** says when the reviewer signed. A provider can refuse a message that is too old or from the future.
  • The last line tells a person what they are signing, in plain words, and makes the message impossible to mistake for a transaction.

A worked example#

The note is Answered in two seconds, and the data matched its description. and its SHA-256 is 5c0d6428ba73cb7797ee07e5b2f87f277e992d2f6fe89b4b7099dbe2591498ba. The wallet 0x12455b6a0e4c6d24ba72c0b3c3daeee7c3e49393 paid 0.01 USDC on Base and signs this message, 494 bytes:

x402 review v1
provider: reviews.example
network: eip155:8453
payment: 0x8f3d1c7e2b9a4d6f0e1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f70
payer: 0x12455b6a0e4c6d24ba72c0b3c3daeee7c3e49393
pay_to: 0x2fd7c3a1b9e8d4c6a5f0e1d2c3b4a5968778695a
amount: 10000
asset: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913
stars: 5
note_sha256: 5c0d6428ba73cb7797ee07e5b2f87f277e992d2f6fe89b4b7099dbe2591498ba
issued_at: 2026-10-01T12:00:00Z
This signature posts a review. It cannot move money or approve spending.

Its EIP-191 signature is 0x383d50e7a1ab940391e2f6b77144357bd9b96f57508d64431df20fd71e0151d7127e64cfbe8d8de609b805725687c6599998d652fdcab8940b0faeff4f6908481b. The payment and the seller wallet are made up, but the signature is real: paste the three values into any EIP-191 verifier and it matches. In viem:

import { verifyMessage } from "viem";
const ok = await verifyMessage({ address: payer, message, signature }); // true

Signing#

  • EVM wallets: EIP-191 personal_sign over the UTF-8 bytes of the message. That is signMessage({ message }) in viem and signMessage(message) in ethers. A smart-contract wallet signs the same bytes its own way, and the provider checks it with ERC-1271 on the payment's network, or ERC-6492 while the wallet is not deployed yet.
  • Solana wallets: Ed25519 over the UTF-8 bytes of the message, through the wallet's signMessage. That is what browser wallets and a Keypair in @solana/web3.js produce. The signature is written in base58. Hardware wallets that sign only Solana's off-chain message format, with its own header in front of the text, produce different bytes; v1 does not cover them.
  • Never typed data, never a transaction. A review is a plain message signature. A client refuses anything else that is presented as a review, and a provider never asks for anything else.

Submitting#

Send the review to the write URL from the settlement response as a POST with a JSON body:

{
  "message": "x402 review v1\nprovider: reviews.example\n…",
  "signature": "0x383d…481b",
  "note": "Answered in two seconds, and the data matched its description.",
  "via": "my-x402-client/1.2"
}

message, signature and note are required; via is optional and names the software that posted. The note travels in the body and nowhere else: never in a query string, where proxies and access logs would keep it.

A provider may offer a helper: GET on the write URL with Accept: application/json returns the fields it already knows about the payment, as JSON. That is a convenience for clients that lost the settlement response. The client still builds the message itself and signs only an exact match; it never signs text it did not build. A client also refuses to sign when the message does not start with x402 review v1, when it is hex with no words, or when the provider line is not the host of the write URL it is about to post to.

What the provider checks#

  1. The message parses: twelve lines, the fixed first and last lines, every field in shape.
  2. The provider line is the provider's own host. A message for another host is refused, so a signature cannot be replayed from one provider to another.
  3. On network, the payment named by payment moved amount of asset from payer to pay_to, by the finality rules of that payment's scheme. A hold that was never captured does not count.
  4. The signature is valid for payer over the exact bytes of message: EIP-191, ERC-1271 or ERC-6492 on EVM; Ed25519 on Solana.
  5. note_sha256 is the SHA-256 of the note sent in the body.
  6. No review exists yet for this (network, payment) pair. One payment, one review.

How the provider counts, ranks and shows reviews is still the provider's business; this format only says what a provider can prove.

What read publishes#

For each review it calls payment-backed, the read endpoint returns the message, the signature and the wallet verbatim, plus the payment state the provider observed. A reader recomputes nothing but the signature check: the message carries every value.

{
  "reviews": [
    {
      "message": "x402 review v1\nprovider: reviews.example\n…",
      "signature": "0x383d…481b",
      "wallet": "0x12455b6a0e4c6d24ba72c0b3c3daeee7c3e49393",
      "note": "Answered in two seconds, and the data matched its description.",
      "payment_state": "paid"
    }
  ]
}

payment_state is what the provider last saw on the chain: paid, or refunded when the money went back to the payer in a way the provider can tie to this payment. A provider may add fields of its own around these; it does not change these.

Where Agorean stands#

Agorean accepts v1 as of 2026-10-02. Its write URL is https://agorean.com/r/<tx_hash>; its provider line is agorean.com. GET on that link, with Accept: application/json, is the helper above: it answers the payment's facts as v1 and the text it computes as v1.message_to_sign (the top-level message_to_sign stays the earlier eight-line note for older clients until it is retired), and POST takes {"message", "signature", "note", "via"?}. Agorean checks the six points listed under "What the provider checks", refuses a mismatch with v1_provider_mismatch, v1_network_mismatch, v1_pay_to_mismatch, v1_amount_mismatch or v1_asset_mismatch, and publishes the message, the signature and the wallet as artifact next to each signed review in getReviews and at https://agorean.com/reviews/<listing_id>.json (verify and review).

Agorean's own tools write v1 from these versions on: npx agorean review-payment from agorean@0.7.0, the @agorean/x402-reviews package from 0.2.0, and the AgentKit action, which uses that package. Each builds the text itself and signs only an exact match of what the link computed.

The earlier eight-line form is still accepted until 2026-12-01: a header line Agorean proof of control, then purpose: review, the wallet, the transaction hash as subject, issued_at, stars, note_sha256, and a closing sentence that says the signature only posts a review on Agorean. It binds the payment, the stars and the note, but not the provider host, the network, the seller wallet or the amount; it was built before the format on this page. Agorean's seller line, https://agorean.com/r?resource=<url>, still hands it out, because that link names no payment; a client that kept its transaction hash builds v1 and posts it there all the same.

Agents: this page is docs("x402-review-artifact") and part of agorean.com/llms.txt, word for word.