x402 · USDC on Base + Solana

x402-podcasts

Search four million podcast feeds and get back a playable audio URL — and, when the feed publishes one, a transcript you can read instead. $0.002 per query, in USDC, on Base or Solana.

git clone https://github.com/nirholas/x402-podcasts && cd x402-podcasts && npm install && npm run dev
GitHub Tutorial API Reference For AI Agents

Pricing

RoutePriceWhat lands in the 200 body
GET /search?q=…$0.002Matching shows — title, author, description, feed URL, artwork, categories, episode count, language, Podcasting 2.0 value block — each with its newest episode, including the enclosure (audio) URL and transcript files
GET /episode/:id$0.002The full record for one episode: audio URL, byte length, duration, episode/season numbers, artwork, transcripts, GUID, feed context
GET / · /health · /skill.md · /.well-known/x402 · /openapi.jsonfreeDiscovery, and which data source this deployment is serving

How a paid call works

Agent GET /resource 402 Payment Required accepts: [ two rails ] USDC on Base EIP-3009 signature USDC on Solana signed SPL transfer the client picks X-PAYMENT facilitator: verify → settle 200 artifact
One round trip of overhead. Every 402 quotes both rails; the client signs whichever chain it holds USDC on.

Two rails, one price

USDC on Base
network base-sepolia / base
scheme exact · EIP-3009 transferWithAuthorization
payTo 0x40252CFDF8B20Ed757D61ff157719F33Ec332402
USDC on Solana
network solana / solana-devnet
scheme exact · SPL transferChecked, fee sponsored
payTo WwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwW

Both rails appear in the accepts array of every 402. Settlement runs through the x402 facilitator, and the 200 carries an X-PAYMENT-RESPONSE receipt naming the rail and the transaction.

Quickstart

# 1. run it — .env.example already has working defaults, no signup needed
npm install && npm run dev              # http://localhost:4028

# 2. search without paying → the dual-rail challenge
curl -s 'localhost:4028/search?q=linux' | jq '.accepts[] | {network, payTo, maxAmountRequired}'
# { "network": "base-sepolia", "payTo": "0x40252CF…2402", "maxAmountRequired": "2000" }
# { "network": "solana",       "payTo": "WwwuGbqH…T3WwW", "maxAmountRequired": "2000" }

# 3. pay → shows, each with its newest episode and audio URL
const pay = wrapFetchWithPayment(fetch, wallet);
const res = await pay(`${BASE}/search?q=podcasting%202.0`);
const { shows } = await res.json();

shows[0].latestEpisode.enclosureUrl
// "https://op3.dev/e/mp3s.nashownotes.com/PC20-180.mp3"
shows[0].latestEpisode.transcripts[0].url
// "https://mp3s.nashownotes.com/PC20-180.srt"   ← read this, don't transcribe the MP3

Why the enclosure URL matters

Most podcast APIs give you titles and descriptions. This one gives you enclosureUrl — the actual MP3 — plus transcripts[], the Podcasting 2.0 transcript files a feed publishes.

That is the difference between “here are some podcasts about X” and a pipeline: search → audio URL → download, or better, search → transcript URL → read. An hour-long episode is a 78 MB download and several minutes of Whisper; its .srt is a few hundred kilobytes and one HTTP GET. When transcripts is non-empty, take it.

Live data, honest fixtures

The upstream is the Podcast Index, the open catalogue behind Podcasting 2.0. Its keys are free and instant — but they are still keys, so this service is env-gated and says which mode it is in.

credentialsbehavioursource field
PODCAST_INDEX_KEY + PODCAST_INDEX_SECRET setevery call hits the live API at request time"podcastindex-live"
unsetdeterministic samples, so the demo runs with zero signups"fixture"

Fixtures are labelled, never hidden: every paid response carries source, GET / and GET /health report the mode, and the service card lists the fixture episode ids so /episode/:id works without keys. The samples are three real shows with one episode each, filtered by your query, so the shapes match live mode exactly. Never present a fixture response as a real search result.

Why pay per query

Podcast search is spiky and occasional — an agent researching a topic runs five queries this week and none next month. A free API key is still an account, a secret to store, a rotation policy and a per-deployment signup. x402 charges a fifth of a cent at the moment of the question, from a wallet the agent already has, and the overhead of acquiring the right to ask drops to zero.