Someone actually paid for it

  • ai
  • agents
  • x402
  • crypto
  • tooling

A few weeks ago I shipped extract.dkta.dev — a pay-per-call web extraction API for AI agents. I’ll be honest: I treated it like a demo. Something to point at when explaining x402. I didn’t expect anyone to actually pay for it.

Then my monitoring cron fired:

💰 Balance: $5.002000 USDC
📊 Requests (24h): 0  |  All time: 1
💵 Revenue (24h): $0.000  |  All time: $0.001
🟢 Service: active

💸 You have earnings to celebrate!

All-time revenue: one thousandth of a dollar. I celebrated anyway.

What actually happened

The transaction came in at 12:58 AM on May 22. A wallet I’d never seen — 0x3A0AA040... — hit GET /v1/extract, paid the x402 toll, and got content back. The request log confirmed it:

{"ts":"2026-05-22T00:58:34.812Z","ip":"xxx.xxx.xxx.xxx","event":"success","url":"https://example.com/","length":111,"paid":true}

They extracted example.com. Probably just testing the API before using it for real. But the payment rail worked exactly as intended — no API key exchange, no account creation, no billing dashboard. Wallet paid, content delivered, $0.001 USDC settled on Base.

One thing worth understanding about the gas economics: the transaction fee to settle the payment was actually higher than the $0.001 I received. That’s not a bug in my setup — it’s because Coinbase’s CDP facilitator submits the transaction and absorbs the gas cost. The customer signs a transferWithAuthorization (gasless from their side), the facilitator broadcasts it, the full amount lands in my wallet. At $0.001 per call that’s not a sustainable economic model for Coinbase — they’re clearly subsidizing it as adoption infrastructure for x402. At higher price points it works out. I need to think about pricing more carefully.

What was broken

Getting a real customer also made me look at the service honestly. A few problems:

Output quality. The original implementation used Mozilla Readability to strip HTML down to plain text. That’s fine for basic extraction but it’s not what agents actually want — they want markdown. Headings, links, code blocks. Readability strips all of that.

The landing page was also pointing at 404. Caddy was routing everything except /v1/* to a different service on the same VPS. The landing page existed in the service code, it just wasn’t reachable from the public internet. The one customer who paid never saw it.

The GitHub link on dkta.dev went to the repo, not the live site.

None of these were dealbreakers, but they’re the kind of thing that tells a visitor you’re not serious.

What I rebuilt

Switched extraction to crawl4ai. I already had a crawl4ai instance running locally for other projects — it’s a Playwright-backed extractor that returns clean markdown. Now the /v1/extract endpoint calls crawl4ai first and falls back to Readability if it fails. The difference in output quality is significant. You get real markdown with structure preserved, not a wall of collapsed text.

Added a ?format=markdown|text param. Default is markdown. Text is there if you need it.

Did a full design pass. Brought in a designer agent that researched what Firecrawl, Jina Reader, Exa, and Browserbase are doing visually, then produced a new landing page from scratch. The coder agent deployed it. The page is heavier now — 33KB vs the original 9KB — but it actually communicates what the service does and who it’s for.

Added discoverability files. /llms.txt follows the standard LLM documentation format. /.well-known/ai-plugin.json is the OpenAI plugin manifest. The idea is that an agent encountering the domain for the first time should be able to figure out how to use it without reading docs. The files are small and static — there’s no reason not to have them.

Fixed the Caddy routing. The landing page is now reachable. The dkta.dev project card links to the live site.

What’s still missing

Batch extraction is the obvious next endpoint. Right now if an agent wants to extract 10 URLs it makes 10 requests and pays 10 times. That’s fine at $0.001 but the friction is real — x402 has a roundtrip overhead on each request. A single batch call with one payment makes sense. I haven’t done it yet because I don’t know how to price it — $0.001 × N? A flat rate per batch? A discount for volume? I want more usage data before committing to a pricing model.

Caching is the other obvious one. Same URL, same content, charged twice. Easy to fix with a short TTL cache keyed on URL. I’ll add it once I understand the usage patterns better.

Key rotation. The wallet keys are in a secrets file on the VPS. That’s fine for now, but the right answer is Coinbase CDP’s managed wallet so the private key never touches my server at all. I’ll migrate when the service is making real money.

The real takeaway

I shipped this as a throwaway demo and got a real customer. The x402 payment flow worked on the first try, end to end, with a wallet I’d never seen before. That’s the thing worth noting — not the $0.001.

The protocol just works. No coordination, no API keys, no accounts. An agent with USDC can use a service that accepts x402. That’s the whole model. I’m increasingly convinced this is how agent infrastructure gets priced — not subscriptions, not rate limits, not per-seat billing. Just wallets and HTTP.

The service is live at extract.dkta.dev. Hit it if you’re building something that needs to read the web.