Know the minute a seller you pay changes
We check up to 50 sellers every few minutes and tell you when a price, payout address or payment request changes.
$19 / month + any tax, renews monthly until you cancel at /billing.
What it watches
- Price
- Payout address (payTo)
- Payment request (402)
- Listing and freshness
Alerts go to a signed webhook, Slack, Discord or email.
Will my sellers fit?
Hostnames only. Never paste a key or seed phrase.
For developers
Preview an alert Example
The service left (or came back to) the public directories we read. Example host seller.example.
{
"type": "botsrated.alert",
"subscription_id": "sub_0123456789abcdef0123456789abcdef",
"plan": "alerts-50",
"sent_at": "2026-10-27T19:40:05.000Z",
"events": [
{
"type": "listing_state_changed",
"host": "seller.example",
"field": "listing",
"from": "listed",
"to": "delisted",
"measured_at": "2026-10-27T19:38:12.000Z",
"receipt_id": "example-receipt-id",
"host_page": "https://botsrated.com/host/seller.example"
}
],
"note": "Measured facts from unpaid probes; every value links to a signed receipt. Not a judgement of the seller."
}
Webhooks are JSON, ed25519-signed with key botsrated-prober-1. Slack and Discord get plain text, not signed. Email: confirm once; sent from alerts@botsrated.com.
Headers and Slack / Discord text
X-BotsRated-Key-Id: botsrated-prober-1
X-BotsRated-Timestamp: <timestamp>
X-BotsRated-Signature: <base64 ed25519 over JSON.stringify({ m: timestamp + "." + rawBody })>
X-BotsRated-Signed: canonical JSON {"m":"<timestamp>.<raw body>"}Slack / Discord text:
BotsRated alert (alerts-50, 1 change)
• seller.example: listing state changed (listing: listed → delisted) at 2026-10-27T19:38:12.000Z UTC. Receipt: https://botsrated.com/receipt/example-receipt-id?host=seller.example&day=2026-10-27 · https://botsrated.com/host/seller.example
Measured facts from unpaid probes; every value links to a signed receipt. Not a judgement of the seller.Every event type
Event type | Sent when |
|---|---|
payto_changed | The payTo in the seller's 402 differs from the one we recorded before, seen on two separate checks. Hosts that rotate deposit addresses per request are compared as one pattern and don't trigger it. |
quoted_price_changed | The amount the seller's 402 asks for changed (atomic units; USDC has 6 decimals), seen on two separate checks. |
valid_402_changed | The route stopped (or started again) answering with a parseable x402 payment request, seen on two separate checks. |
listing_state_changed | The service left (or came back to) the public directories we read. |
freshness_changed | Our latest check of the host became older than 24 hours (or fresh again). |
paid_test_buy_recorded | Only for hosts where we record paid test-buys: a new one was recorded, with its outcome. |
Facts before → after.
Set up with USDC
- Webhook: public https, no redirects; echo our
{"type":"botsrated.verify","challenge":"..."}with a 2xx within 5 s. (Or Slack/Discord, or"email".) - Raise your cap to $29 for this call (
@x402/fetchdefaults to $1). - Subscribe:
POST https://botsrated.com/v1/subscribe/alerts-50with{"hosts":[...],"webhook_url":"https://..."}; pay the 402 (29000000atomic USDC on Base); save the token (shown once). Errors are free. - Verify each alert with /.well-known/botsrated-key.
TypeScript (pay and subscribe)
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
const client = new x402Client();
client.setSpendControls({ maxAmountPerPayment: "$29" }); // default cap is $1: raise it for this call
registerExactEvmScheme(client, { signer: privateKeyToAccount(process.env.BUYER_KEY) });
const pay = wrapFetchWithPayment(fetch, client);
const r = await pay("https://botsrated.com/v1/subscribe/alerts-50", { method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ hosts: ["blockrun.ai", "x402.tavily.com"], webhook_url: "https://you.example/botsrated-hook" }) });
console.log(await r.json()); // save "token" now: it is shown once
Verify an alert (Node 20+)
// Public key: botsrated-prober-1 at https://botsrated.com/.well-known/botsrated-key (base64, raw ed25519)
const key = await crypto.subtle.importKey("raw", Buffer.from(PROBER_PUBKEY_B64, "base64"), { name: "Ed25519" }, false, ["verify"]);
const signed = JSON.stringify({ m: req.headers["x-botsrated-timestamp"] + "." + rawBody });
const ok = await crypto.subtle.verify("Ed25519", key, Buffer.from(req.headers["x-botsrated-signature"], "base64"), new TextEncoder().encode(signed));
Plans
| Plan | Price | Hosts | Delivery |
|---|---|---|---|
| Pro by card | $19 / month plus any tax | 50 | A few minutes after a change |
alerts-50 (Pro, USDC) | $29 / 30 days | 50 | Same as Pro by card |
alerts-10 (legacy) | $9 / 30 days (USDC) | 10 | A few minutes after a change |
Coming: All-Access $39 / month, Team $499 / month, Fleet from $2,500 / month (plans). Pro keeps $19 / month.
USDC on Base: one payment = one 30-day period, no auto-renewal. Refunds only for our faults (terms). Token also reads /v1/check + /v1/report for your hosts (60/min).
Manage
GET https://botsrated.com/v1/subscription # Authorization: Bearer <token>
POST https://botsrated.com/v1/subscription/update # {"hosts":[...],"webhook_url":"..."}
POST https://botsrated.com/v1/subscription/cancel
Reference: /v1/plans, /docs, openapi.json.
Questions
What counts as a change?
payTo, price or valid-402 changes seen on two separate checks; delisting/relisting; data going stale.
Rotating deposit addresses?
Hosts that issue a new address per request are compared as one pattern, so no false payTo alerts.
Does it renew?
By card, monthly until you cancel at /billing. USDC is one 30-day period, no renewal.