Lumière PayCheck For agent buildersFor facilitatorsDocsPlansAccountPayments on Base + Solana

For sellers: make your x402 API verifiable

Lumière PayCheck already monitors every endpoint listed in the x402 Bazaar, including yours. Buyers and their agents check your grade before they pay. A few minutes of setup makes that grade more accurate, protects your customers if your endpoint is ever hijacked, and gives you a badge that shows buyers you're independently checked.

Nothing here costs anything, and no one can pay for a better grade: grades come from the same published formula for everyone. (Sellers of endpoints above $0.05 per call can fund a test of their own endpoint, at their own price, which goes straight back to their payout wallet; the grade still comes only from what the test finds, and every funded test is listed publicly. See [Seller-funded tests](#6-seller-funded-tests).)

Get your endpoint tested

  • Priced at $0.05 or less per call: we pay-test it ourselves for free. Fixed something, or think the grade is wrong? Use Request a free re-test on your endpoint's page (it opens a pre-filled GitHub form; see [section 5](#5-if-you-think-a-grade-is-wrong)).
  • Priced above $0.05: use Verify your endpoint on your endpoint's page to fund a test at your own price; it's held for your test, the money goes back to your payout wallet, and anything unspent is returned (see [section 6](#6-seller-funded-tests)).
  • Needs its own sign-in: fill in the private test account form, or let our tester sign in with its own wallet (see [section 8](#8-sign-in-tests)).
  • Changed your paycheck.json? Use Check my setup: we read it again right away, show what we found, and queue a paid re-test.

Every endpoint page has a Run this endpoint? Get it tested link at the top. It shows the one next step that fits your endpoint.

What we check, and what never counts against you

Every endpoint is checked every 30 minutes for uptime, response time, a valid 402 price quote, and a stable price and payout wallet. Many also get real test payments, where we pay and check that the response has the advertised shape and, where tests exist, the right values.

Some failures are about our monitor, not you, so they never affect your score:

  • We were rate-limited, or blocked by a firewall or bot challenge
  • Your endpoint rejected the format of our test request (HTTP 400, 405, 415, or 422) before quoting a price
  • You asked for payment on a network our monitor can't read yet
  • Our own network had a problem

A failed paid test only counts if a re-test about 2 hours later fails too. If your endpoint needs its own sign-in on top of x402 (an account, API key or wallet signature) and answers our paid call with 401/403 without collecting the payment, that isn't a failure: the grade is C (caution, delivery not confirmed) with a "needs its own sign-in" note until a test can get in ([section 8](#8-sign-in-tests) shows how). The same goes for refusing our test wallet or serving only your own customers (C, with that reason). But if the 401/403 asks for a header or input your listing doesn't mention (say, "provide X-Agent-Id"), buyers can't call it as listed either, so it's D until you document it or [declare a test request](#7-declare-a-test-request). We test with your listing's own example input, so make it real: if it returns 404 "not found" (a placeholder like owner/name, example.com or a made-up ID), it can't be called as listed, so it's D (caution) with a note asking for a working example. Any other error after payment that doesn't collect the money is D too; if you collect the payment and fail, it's F (avoid). Grades: A delivered cleanly, B delivered with a caveat, C unconfirmed, D doesn't work as listed but no money lost, F costs money or unsafe. Each paid test sends a fresh value for request keys in your example (requestKey, idempotencyKey, nonce), so de-duplication never treats our test as a repeat. Every failed check is public on your endpoint's page, with its time and whether it counted, and the Recent paid tests section shows each paid test: what came back, whether money was taken, and whether it counted. If your endpoint answers a paid call with HTTP 202 ("accepted, processing"), include a link to the job (a Location header, or a status_url field in the JSON): we check it for up to 45 seconds and grade the finished result. A 202 with no link, or no result in time, can't be judged either way; after two in a row we re-test weekly. If you refund a failed paid call (USDC back to the payer within an hour), we detect it and count the failure as "no money lost" (D), not F. Our monitor's user agent is shown there too, so you can allowlist it.

1. Declare your payout wallets

This is the most important step. When a wallet changes, buyers can't tell a normal rotation from a hijack, so an undeclared change is treated with caution. Declare your wallets and switching between them is never flagged, while any wallet you haven't declared is blocked immediately.

Publish a file on the domain that serves your endpoints, at https://<your-host>/.well-known/paycheck.json:

{ "payTo": ["0xYourBaseWallet", "YourSolanaWallet"] }

Or a DNS TXT record at _paycheck.<your-host>: payto=0xYourBaseWallet,YourSolanaWallet

The parent domain is checked too (api.example.com → example.com), except on shared hosting such as vercel.app, workers.dev, or onrender.com. Only someone who controls your domain can publish either record. If you issue a new payout address on every request, you don't need to declare anything: we detect that pattern and don't flag it.

Declarations are re-read every 6 hours. To have yours read right away, use Check my setup, or from code:

curl -X POST https://lumierepaycheck.org/v1/declaration -H "content-type: application/json" \
  -d '{"url":"https://api.example.com/your-endpoint"}'

2. Add known-answer tests (optional)

A schema check confirms a response has the right shape, not that the values are right. If you add tests to the same paycheck.json, our paid checks call your endpoint with a request whose answer is known and check the values:

{
  "payTo": ["0xYourBaseWallet"],
  "tests": {
    "/v1/convert": [
      { "name": "100 USD in cents",
        "query": { "amount": "100", "unit": "cents" },
        "expect": [ { "path": "$.result", "equals": 10000 } ] }
    ]
  }
}

Checks can be equals, oneOf, min/max, approx, matches, nonEmpty, or a live reference to an independent public source. When every check passes, your endpoint page shows "values checked against known answers." Full format: API reference.

3. Add your badge

Every monitored endpoint has a public page and a badge that updates itself. Copy the code from the "Run this endpoint?" section of your endpoint's page, or build it from your URL (URL-encoded):

[![Lumière PayCheck](https://lumierepaycheck.org/badge?url=YOUR_ENDPOINT)](https://lumierepaycheck.org/e?url=YOUR_ENDPOINT)

Put it in your README or API docs so buyers can see your live grade before they integrate.

4. Make your listing match your response

When we pay your endpoint, we compare the response with the example or schema in your x402 Bazaar listing. If your data arrives reshaped (fields nested under data, a list where the listing shows one item, example fields you never return), buyers' agents get a note telling them where to read the fields, and the grade is capped at B. Update the listing's example to match your real response, then request a re-test with the Dispute link on your endpoint page. Minor gaps, like one optional field, get a note but don't affect the grade.

How to reach an A: a passed paid test, 95%+ uptime, a stable payout wallet (declare it, step 1) and a listing that matches your response.

5. If you think a grade is wrong

Every endpoint page has a Dispute link to a pre-filled GitHub form. A bot replies with your current score and queues a paid re-test. When the re-test has run, the bot posts the result on the issue (grade before and after) and closes it if the grade is fixed; if not, it leaves the issue open for a reply. Only our own re-test can change a grade, and that applies to reports from buyers too: reports from agents can trigger a re-test but never change a grade by themselves.

Free re-tests are for endpoints priced at $0.05 or less per call. Above that, our tester doesn't pay on its own, so the bot posts a link to fund a test instead (see [section 6](#6-seller-funded-tests)).

When a free re-test runs. We pay for a re-test whenever one could change your grade:

  • a failed or untested endpoint
  • a test that was refused for a sign-in or missing input
  • a response reshaped compared with your listing
  • a value warning

When a test can't change it, the reply says why instead, and nothing is spent:

  • Your B or C comes from uptime: it rises by itself as our free checks see it up (an A needs 95% over 7 days).
  • It comes from a payout-wallet change: declare your wallets in paycheck.json and the review re-runs.
  • It's already an A: there's nothing to re-test.

Limits, so the free tests stay free for everyone:

  • One request per endpoint per day, and at most 10 paid re-tests per seller per day (by domain or payout wallet). Extra requests wait their turn and are never refused, and waiting never affects a grade.
  • A daily total for all dispute re-tests across sellers. When it's reached, the rest run the next day.
  • Re-tests that anyone can request (disputes and buyer reports) pay one payout wallet at most $1 a week, so disputes can't be used to drain our tester. Past that, your re-test waits until the 7-day total drops, and the bot offers a funded test in the meantime.
  • If our last 2 paid tests in 7 days took the payment and failed, the next one is a seller-funded test.

If a re-test will be held for more than a day (your endpoint costs more than $0.05, or your wallet reached the weekly limit), the bot says so on the issue right away, with a link to fund a test. A funded test that runs answers the dispute, and the bot posts its result the same way.

6. Seller-funded tests

Our tester pays endpoints up to $0.05 per call on its own. If yours costs more, it stays C (unconfirmed) until a paid test confirms it delivers. You can get it verified yourself:

  1. On your endpoint's page, click Verify your endpoint (or open a Seller test issue).
  2. A bot replies with your endpoint's price and a payment link: POST https://lumierepaycheck.org/v1/seller-test?url=<endpoint>&issue=<n>, paid once with any x402 client (USDC on Base).
  3. Your payment goes to our tester wallet (the wallet that runs the test) and is held for your test: our free tests can't spend it.
  4. Our tester pays your endpoint that same price at a random time within about 3 hours, so the money goes back to your payout wallet. The random time means nobody can serve the tester a special answer at a known moment.
  5. The bot posts the result on the issue and closes it. The grade comes only from what the test finds, pass or fail.

Where your money goes, exactly:

  • The test is capped at what you funded. If it costs less (your price dropped) or your endpoint answers without charging, the unspent part is returned automatically to the wallet that paid.
  • If the test can't run within 3 days (endpoint down, or the price went up after funding), the whole funding is refunded to the wallet that paid it.
  • Refunds and results are public: GET /v1/seller-tests?url=… shows each test with what it spent and anything returned.
  • A refund is sent exactly once: it's signed and saved before it's sent, and if anything interrupts it (a restart, a network error), the same transaction is re-sent or confirmed from the chain, never sent a second time. Until it's confirmed, the money stays set aside for you.

How often: as often as you like. There's no cooldown, only one funded test waiting per endpoint at a time. Fixing something over a few tries? Fund one, read the result, fix, fund the next.

Why paying for tests can't buy a grade: every seller-funded test from the last 7 days and its result is listed on your endpoint's page ("3 funded: 2 delivered, 1 didn't"). Buyers and their agents see the whole record, not just the last pass.

Endpoints at $0.05 or less don't need this: they're tested automatically. API: GET /v1/seller-test/quote?url=… (free) and GET /v1/seller-tests?url=… for results.

7. Declare a test request

If your endpoint needs a header or input that your listing doesn't show (an agent ID, a tenant, a required parameter), tell us what a working test request looks like, in the same paycheck.json:

{
  "payTo": ["0xYourBaseWallet"],
  "requests": {
    "/v1/jobs": { "headers": { "X-Agent-Id": "lumiere-paycheck-test" } },
    "*": { "query": { "region": "us" } }
  }
}

Keys are an endpoint URL, a path, or "*" for every endpoint on your host. Each can set method, headers (up to 10), query and a JSON body. Then click Check my setup: we read it right away and queue a paid re-test. (From code: POST https://lumierepaycheck.org/v1/declaration with {"url": "<endpoint>"}.)

Our paid tests send that request, and each test using it is labeled "with the seller's declared test request" on your page. It's checked exactly like any other test. Put the same input in your listing too, so buyers' agents know to send it.

Don't put credentials here: the file is public. Headers that look like one (Authorization, Cookie, or any name with key, token, secret, session, auth or signature in it) are ignored. For a sign-in, use [section 8](#8-sign-in-tests).

8. Sign-in tests

If your endpoint needs its own sign-in on top of x402, it stays C ("needs its own sign-in") until a paid test can get in. Two ways to let it in:

Wallet sign-in (recommended). Our tester signs in with its own wallet, the same way any buyer's agent would, so a passing test can earn any grade with no label beyond "signed in with our tester's wallet".

  • The x402 standard (nothing to set up on our side): if your 402 response declares the sign-in-with-x extension (SIWX, EIP-4361), our tester signs the challenge with the wallet that pays and sends the SIGN-IN-WITH-X header with the payment.
  • Treat the payment as the sign-in: the x402 payment already proves which wallet is calling. If you create an account for a paying wallet automatically, our tester gets in like any new customer.
  • Your own signed-header scheme: describe it in paycheck.json and we sign each paid call with EIP-191 (personal_sign):
{
  "signIn": {
    "*": {
      "type": "eip191",
      "message": "{method} {path} {timestamp}",
      "headers": { "X-Address": "{address}", "X-Signature": "{signature}", "X-Timestamp": "{timestamp}" }
    }
  }
}

Placeholders: {address} {signature} {timestamp} (unix seconds) {timestampMs} {isoTime} {nonce} {method} {path} {pathWithQuery} {host} {url} {bodySha256} {chainId}. The message must include a timestamp or nonce, so every signature is fresh. We only ever sign plain messages for your own endpoint: never typed data or transactions, and never a sign-in message for another site.

A private test account. For sign-ins that need a real account (an API key, a bearer token, a session cookie):

  1. Fill in the private test account form: your endpoint's URL and the sign-in header(s), for example Authorization: Bearer <test key> (up to 3 headers; choose "every endpoint on this host" to cover them all).
  2. Prove you run the host: add the one line it gives you, "testAccount": "<code>", to your /.well-known/paycheck.json.
  3. Click Check now. We activate the account and queue a paid re-test.

From code instead: POST https://lumierepaycheck.org/v1/test-account with {"url", "headers", "scope"?: "host"} returns the code, and POST /v1/declaration with {"url"} activates it.

The details are stored encrypted, sent only to your host on our paid tests (redirects aren't followed), and never shown anywhere. The grade comes from what the test finds, up to an A, and your page notes it was tested with a seller-provided account, so buyers know they need their own account with you. Use a test account with the same access a paying customer gets. To revoke it, remove the code from paycheck.json: the next read deletes the stored details. Check its status at GET /v1/test-account/<id>.

Until a test gets in, verified buyer reports still show on your page: agents that have an account and pay can report what they got, checked against the on-chain payment. They don't change the grade, but buyers can see them.

9. Withdraw an endpoint

Stopped selling an endpoint? List it in your paycheck.json so it's retired instead of showing as down:

{ "withdrawn": ["/v1/old-route", "https://api.example.com/v1/another"] }

Then use Check my setup. Withdrawn endpoints aren't tested, graded, ranked or counted; their page says "Withdrawn by the seller" and agents are told not to pay them. Remove an entry to put it back on sale. We also retire endpoints automatically when they've been gone from the x402 Bazaar and answering "not found" for 3 days; they come back on their own if they start answering with a payment quote again.

10. Accept PayCheck-verified agents

Companies on Lumière PayCheck can let their agents prove they belong to a verified company (it's off unless the company turns it on). Such an agent sends an X-PayCheck-Agent header on its paid request. You can use it to give verified agents higher limits, better prices, or access you don't give anonymous wallets. Checking it is free and needs no account.

import { verifyAgentCredential } from "x402-paycheck";

const v = await verifyAgentCredential(req.headers["x-paycheck-agent"], { audience: "api.yourservice.com", payer: walletThatPaidYou });
if (v.valid) { /* v.level: "workspace" | "domain" | "business"; v.org: { name, domains } when the company chose to be named */ }

What a valid credential tells you:

  • Level: workspace (a PayCheck workspace), domain (the company proved a domain by DNS), or business (a company we reviewed).
  • Company name and domain, only if the company chose to be named (which requires a verified domain).
  • An agent ID only you see. Each seller gets a different ID for the same agent, so you can recognize returning agents without anyone tracking them across sites.
  • The agent's paying wallets. Pass the wallet that paid you as payer: a credential copied to another wallet fails.

It never tells you the company's limits, people, other agents or payment history. Credentials last 15 minutes. If the company turns credentials off or pauses the agent, the status check fails immediately (online: false skips that call; then you rely on the 15-minute expiry). Without our library: POST /v1/credentials/verify with { "credential", "audience", "payer" }, or verify the Ed25519 JWT yourself with /.well-known/jwks.json (key paycheck-agents-1) and call GET /v1/credentials/status/<jti>.

Why it's worth it

  • Buyers trust you faster. A grade backed by real test payments answers "does this work?" before anyone asks.
  • Your customers are protected if you're hijacked. With declared wallets, an agent checking through PayCheck refuses to pay an attacker's wallet on the first call.
  • Fair treatment. Problems on our side never count, every failed check is public, and disputes get a real re-test.

Questions: hello@lumierepaycheck.org

Questions? Email hello@lumierepaycheck.org or talk to us about Enterprise.