If you sell an API and your traffic is now mostly agents, the abuse tooling you inherited from the web is aimed at the wrong target. It was built to find bots. Your paying customers are bots. The agent that calls your endpoint eight thousand times a day on a metered plan and the script that drains your free tier with rotated keys look identical to a CAPTCHA, a headless-browser check, or a "is this a real human" heuristic. Agent payments change the question from "is this automated" to "is this automation worth serving at this price".
That is a different problem, and a more tractable one. You can know four things about a machine customer, and none of them involve guessing whether a person is at the keyboard.
Bot detection is the wrong question when the buyer is a bot
The infrastructure now assumes the buyer is software. Coinbase's x402 protocol turns HTTP 402 into a live payment challenge: the server answers an unpaid request with a PAYMENT-REQUIRED header, the client retries with a signed authorization in PAYMENT-SIGNATURE, and a facilitator exposes /verify and /settle endpoints to check and broadcast the transfer, as described in the x402 specification. Coinbase's own docs say it plainly: the buyer can be "a backend consuming metered data, or an agent purchasing a tool call mid-task", and the CDP facilitator has processed more than 100 million x402 payments across Base and Solana.
Stripe built a card-side equivalent. The Agentic Commerce Protocol, released with OpenAI in September 2025, hands the merchant a Shared Payment Token, a scoped grant with usage and expiry limits instead of a raw card. The same post admits the part that matters for you: businesses need to "update their risk models to differentiate good bots from bad bots". Stripe's machine payments docs then go further down-market, with a $0.50 minimum for card payments through Shared Payment Tokens and a $0.01 minimum for USDC over MPP or x402. Visa's Agentic Directory is a registry of agents merchants can trust, and Mastercard's Agent Pay for Machines extends its trusted-agent program to sub-cent card and stablecoin transactions.
Registries help at the top of the market. They do nothing for the indie API whose caller is a script someone wrote last night, running from a residential proxy, presenting a fresh wallet. That caller might be a legitimate agent on its first task. It might be the front end of a relay.
The relay economy is the abuse shape to design against. Two Hacker News threads this year, on the relay market behind token resellers and on the AI credit resale economy, describe it from the inside. In the second thread, RALaBarge summarized where the inventory comes from: "Most of these are your standard botnet rings. Either accounts directly are taken over, and the attacker adds 2FA or carding rings take stolen #s and attempt to add credits." The resold access is then proxied to many downstream buyers through one upstream identity. Every request in that stream is automated, and so is every legitimate request from a paying agent. Automation is not the signal.
Four things you can know about a machine customer
Strip away the human-detection layer and four measurable properties are left. Every abuse decision on an agent-facing API is some weighting of them.
Identity. Who is paying. For x402 it is the payer wallet address in the signed authorization. For card rails it is the card fingerprint behind the token. For prepaid credits it is the account, and the email, device, and card that funded it. An API key is not an identity; it is a pointer to one, and a resold key is the same pointer in many hands.
Reputation. What that identity, and everything linked to it, has done before. Paid and settled without dispute. Disputed. Convicted of abuse. Never seen. This is the dimension web-era tooling throws away, because a CAPTCHA has no memory.
Velocity. Rate per identity, per device or IP behind the identity, and per endpoint. The per-endpoint split matters for APIs in a way it never did for signup forms. A relay tends to show as one identity hitting your most expensive endpoint at a flat, unhuman cadence.
Economics. Whether the price of the request exceeds what an abuser can extract from it. If a call costs the buyer $0.01 and returns data worth $0.01 to resell, the abuse case is thin. If a call costs $0.01 and returns a model completion that resells for $0.20, you have built a subsidy with a payment step in front of it.
Identity and reputation are the two most APIs get wrong, so that is where the rest of this post spends its words.
Identity is the cluster
The mistake is treating each key, wallet, or account as an independent customer. An abuser who is worth blocking will present you with many. The unit of trust has to be the cluster: every account that shares a wallet, a card fingerprint, a device, or an email with a known one.
IP does not belong in that list as a linking key. Agents run from cloud egress, and half your honest customers will share a /24 with each other and with the attacker. IP is a soft signal for velocity and never the join key for identity. Building this well takes a hash-keyed graph and a store that remembers outcomes per node and per cluster.
I built Portreeve to be that store. One call per event, at signup, trial, checkout, or login, returns allow, review, or block with reason codes in under 100 ms, and links accounts across hashed email, device fingerprint, card fingerprint, phone, and payer wallet so that confirmed abuse on one node marks the cluster. It fails open by default. The payer wallet is a live identity key today, so an x402 seller can pass identity.payer_wallet from their middleware and a convicted cluster blocks that wallet on sight. There is no dedicated x402 package; it is the same verdict call with an event_type of checkout_attempt and the request price in payment.amount.
The rest of the framework works without any specific vendor. What it cannot work without is memory.
Memory is the asset
A wallet that has paid you $40 across three thousand settled requests over two months is a different customer from a wallet created ninety seconds ago. A rate limiter treats them identically. That is the core inefficiency in most agent-facing APIs: they spend their false positives on the customers with the longest paid history and their generosity on the ones with none.
Reputation converts history into latitude. Concretely:
- An identity with paid, undisputed history gets higher per-endpoint velocity ceilings and a wider fail-open budget.
- An identity with a chargeback or a confirmed-abuse mark, or a cluster-mate with one, gets blocked at the challenge step, before you spend compute.
- An identity with no history gets served, but metered hard and priced as if it will not come back.
Two details make this work in practice. First, the feedback loop has to be cheap. When a card payment turns into a dispute or you catch a relay, that outcome must flow back to the identity store as a single call, or nobody will do it. The right shape is an event id plus one of three outcomes, confirmed abuse, false positive, or chargeback, idempotent per outcome so a retried webhook cannot double-count; the feedback docs show one version of it.
Second, reputation is cluster-wide or it is worthless. A relay operator with fifty wallets and one funding card will happily let you burn one wallet at a time. Convict the card fingerprint and the fifty wallets go with it.
The fresh-cluster problem
Everything abusive starts as a fresh identity. So does every good customer. You cannot tell them apart on request one, and any system that claims to is guessing from IP reputation and user agent strings.
So do not try. Design the first N requests from a fresh cluster to be safe to serve whether or not the buyer is honest.
For pay-per-request, that means the unit price on a cold identity must cover cost of goods plus the expected resale margin. Charge the first hundred calls at the list price with no volume discount, settle each one before serving, and let history earn the cheaper tiers. CoinGecko's x402 endpoints, which charge a flat $0.01 USDC per request with no account or API key, are the simplest version of this: the identity is the wallet, every request settles, and there is no credit balance to drain.
For prepaid credits and metered billing, the fresh-cluster problem is sharper, because you are extending credit. Cap the unbilled balance on any identity younger than a threshold. Do not let a day-one account run a $2,000 tab against a card you have only seen authorize. Card testers use exactly this window, and the tell is the same as on a normal checkout: a ladder of $0 or small-amount authorizations from one device, across several distinct cards, before any tab gets run.
The threshold for "no longer fresh" should be settled money and elapsed time together. One large payment on day one is what a stolen card looks like. Fifty small payments across three weeks with no disputes is what a customer looks like.
Failing open for machines
Agents retry. That single fact changes how you should think about the gate.
If a human sees a decline they stop, and you never learn whether they were honest. If an agent gets a 403 it retries with backoff, then switches to a competitor whose endpoint returned 200, and its operator never files a ticket. A wrongly blocked agent churns silently. That is worse than a false positive on a signup form, because you do not even get the support email.
Two rules follow.
The gate must never be the outage. If your abuse check times out, the request must proceed. Any vendor call in your hot path needs a hard time budget, a fail-open default that returns allow and marks the response as degraded so you can count how often it happened, and fail-closed only as a deliberate client-side choice. On a machine-facing API the alternative to failing open is a silent retry storm against your competitor.
Route uncertainty to review. A review verdict proceeds the request and queues it; a later deny reaches your server by signed webhook so you can revoke the key or reverse the balance. That lets the engine flag aggressively without ever blocking a good agent on a weak signal. The docs on handling verdicts describe the three-way split, but the principle stands regardless of tooling: for an agent, a delayed revoke costs you one request's worth of compute, while a wrong block costs you the customer.
On failure semantics for the agent side, prefer a 402 with a higher price to a 403. A 403 tells the agent nothing it can act on. A 402 with a fresh-identity surcharge tells it exactly what history would earn.
Pricing risk into a pay per request API
Most of the time the unit price can do the work that a fraud model would otherwise do.
The question for each endpoint is the fourth property above: does the price exceed what an abuser can extract? Work it through per endpoint, not per plan. Your cheap lookup endpoint and your expensive generation endpoint have different resale values and should carry different cold-identity prices and different velocity ceilings.
Then make history the discount. List price for a fresh identity. A lower tier once a cluster has settled a minimum amount over a minimum time without a dispute. Return to list price on any conviction in the cluster. This inverts the usual SaaS model, where the discount comes from a volume commitment made up front, and it removes the arbitrage that a relay depends on: the relay can only resell a discount it has earned, and earning it means becoming exactly the customer you wanted.
Where this does not work is anything with a per-request cost that dwarfs what the payment rails can carry. A $0.01 x402 minimum is fine for a data lookup. It is not fine for a request that costs you $0.30 in inference. There the price does not protect you, and identity and reputation have to.
One more piece of standard advice to drop: requiring a card up front. On an agent-facing API it filters out the wallets and prepaid buyers who are the least likely to charge back, while doing nothing about the carding rings who arrive with a fresh stolen card each time.
A first design for an agent-facing API
Putting the four properties together, this is the shape I would ship first.
On every paid request, before serving, resolve the payer to an identity cluster: wallet for x402, card fingerprint for tokenized cards, funded account for credits. Look up the cluster's reputation. Fresh clusters get list price and a low per-endpoint ceiling. Convicted clusters get a 402 at a price you never expect them to pay, or a 403 if you would rather not serve them at any price. Established clusters get their earned tier.
For x402 specifically, the check sits in the middleware after the payment payload verifies and before you settle:
import { Portreeve } from "portreeve";
const portreeve = new Portreeve(process.env.PORTREEVE_SECRET_KEY!);
const result = await portreeve.verdict({
event_type: "checkout_attempt",
external_user_id: payerWallet,
ip,
identity: { payer_wallet: payerWallet },
payment: { amount: 1, currency: "usd" }, // $0.01 in minor units
});
if (result.verdict === "block") {
return c.text("Payment Required", 402);
}
The event payload reference lists the rest of the fields; for a wallet-paid API most of them are optional.
Then close the loop. When a payment disputes, when you find a relay, when a customer complains they were throttled wrongly, report it against the event. Reputation without feedback decays into a static blocklist, and static blocklists are what the relay operators already know how to rotate past.
Meter the fresh, remember the paid, and never let the gate be the thing that fails. That is the whole framework. The rest is tuning per endpoint.
If you want the cluster memory and the allow/review/block call without building the graph yourself, Portreeve's free tier screens 1,000 events a month with no card required.