A crypto sentiment API that returns a bull/bear score for any token symbol. Agents call it, get 15 free trials, then pay $0.01 per call in USDC on Base. The entire payment flow is handled by HTTP 402 headers — no Stripe, no API keys, no auth middleware.
| Feature | How |
|---|---|
| Free trials | 15 calls per IP, no signup required |
| Payment | HTTP 402 + x-402-amount header → agent pays in USDC |
| Registration | POST /register → auto-creates wallet + 500 free credits |
| Discovery | GET /.well-known/x402 → machine-readable manifest |
| Health check | GET /api/agent-ready → one-request connectivity test |
Create a new directory and initialize:
mkdir sentiment-api && cd sentiment-api
npm init -y
npm install express
touch server.js
Now paste this into server.js:
const express = require('express');
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3456;
const PRICE_CENTS = 1; // $0.01 per call
// ── Trial tracking (in-memory; use Redis/DB in production) ──
const trials = new Map(); // IP → count
function getTrialsRemaining(ip) {
const used = trials.get(ip) || 0;
return Math.max(0, 15 - used);
}
function useTrial(ip) {
const used = trials.get(ip) || 0;
trials.set(ip, used + 1);
return 15 - (used + 1);
}
// ── Payment info (your wallet on Base) ──
const PAYMENT = {
chain: 'base',
token: 'USDC',
recipient: '0xf16F0882de08315B438E9f3a2Abfb2d2E5d94ECA', // your wallet
amount: PRICE_CENTS // in cents
};
// ── Step 2: The API endpoint ──
app.get('/api/v1/sentiment', (req, res) => {
const ip = req.ip || req.connection.remoteAddress;
const symbol = (req.query.symbol || 'BTC').toUpperCase();
const remaining = getTrialsRemaining(ip);
// TRIAL PATH: free for first 15 calls
if (remaining > 0) {
useTrial(ip);
const score = Math.round(30 + Math.random() * 70); // 30-100
const sentiment = score > 60 ? 'bullish' : score < 45 ? 'bearish' : 'neutral';
return res.json({
symbol,
score,
sentiment,
_trial: {
remaining: remaining - 1,
total: 15,
message: `${remaining - 1} free trials left. Register for 500 more.`,
register: 'POST /register {"name":"my-agent"}'
}
});
}
// PAID PATH: trial exhausted → 402 Payment Required
res.status(402);
res.set('x-402-amount', String(PAYMENT.amount));
res.set('x-402-chain', PAYMENT.chain);
res.set('x-402-token', PAYMENT.token);
res.set('x-402-recipient', PAYMENT.recipient);
res.set('x-402-register', 'POST /register');
return res.json({
error: 'payment_required',
message: `This endpoint costs $${(PAYMENT.amount/100).toFixed(2)}/call`,
payment: PAYMENT,
register: '/register'
});
});
// ── Step 3: Registration endpoint ──
app.post('/register', (req, res) => {
const { name } = req.body || {};
if (!name) return res.status(400).json({ error: 'name required' });
// In production: create wallet, issue credits
// For this demo: register on minia2a.uk (free, instant)
return res.json({
ok: true,
message: `Agent "${name}" registered.`,
next: 'Register on minia2a.uk for real wallet + 500 credits: ' +
'curl -X POST https://minia2a.uk/api/v1/register-simple ' +
'-H content-type:application/json -d \'{"name":"' + name + '"}\''
});
});
// ── Step 4: Agent-ready handshake ──
app.get('/api/agent-ready', (req, res) => {
res.json({
status: 'ready',
version: '1.0.0',
protocols: ['x402'],
payment: PAYMENT,
trial: { limit: 15, unit: 'calls_per_ip' },
registration: { endpoint: 'POST /register', body: { name: 'string' } },
endpoints: { sentiment: 'GET /api/v1/sentiment?symbol=BTC' }
});
});
// ── Step 5: /.well-known/x402 manifest ──
app.get('/.well-known/x402', (req, res) => {
res.json({
protocol: 'x402',
version: '1.0.0',
payment: PAYMENT,
trial: { anonymous: '15 free calls per IP' },
register: 'POST /register',
catalog: 'GET /api/v1/sentiment?symbol=BTC',
agent_ready: 'GET /api/agent-ready'
});
});
app.listen(PORT, () => {
console.log(`Sentiment API live on http://localhost:${PORT}`);
console.log(`Agent-ready: http://localhost:${PORT}/api/agent-ready`);
console.log(`Test: curl http://localhost:${PORT}/api/v1/sentiment?symbol=ETH`);
});
node server.js
In another terminal, test the three key flows:
# 1. Agent-ready handshake
curl http://localhost:3456/api/agent-ready | jq .
# 2. Free trial call
curl http://localhost:3456/api/v1/sentiment?symbol=ETH | jq .
# 3. Trial info in response
# Look for _trial.remaining and _trial.register fields
# 4. Test the well-known manifest
curl http://localhost:3456/.well-known/x402 | jq .
# 5. Simulate registration
curl -X POST http://localhost:3456/register \
-H content-type:application/json \
-d '{"name":"my-agent"}' | jq .
When an auto-mode agent hits your API and trials are exhausted, your 402 response must include these four headers. Without them, the agent cannot pay you:
| Header | Example | Required? |
|---|---|---|
x-402-amount | 1 (cents, so $0.01) | ✅ Yes |
x-402-chain | base | ✅ Yes |
x-402-token | USDC | ✅ Yes |
x-402-recipient | 0xf16F... | ✅ Yes |
x-402-register | POST /register | Recommended |
x-credits-required | 1 | Recommended |
Why this matters: Aug 14 auto mode means Claude Code agents will read these headers programmatically. If your 402 response says "Payment Required" in HTML but doesn't include these headers, the agent sees an error, not a payment instruction. Your API is invisible to autonomous spenders.
One command registers your API in the marketplace. Agents discover it through search, trial it for free, and pay when they need more:
curl -X POST https://minia2a.uk/api/v1/register-simple \
-H content-type:application/json \
-d '{"name":"crypto-sentiment-api"}'
Response:
That's it. Your API is now discoverable by any Claude Code agent with auto mode enabled. They can find it, trial it, exhaust the free calls, receive a machine-readable 402, and pay autonomously — all without you writing a single line of payment code.
Pick any hosting provider. Here's the one-command deploy for three common options:
# Option A: fly.io (free tier, auto-HTTPS)
fly launch --name sentiment-api
# Option B: Render (free tier, auto-HTTPS)
# Push to GitHub → connect repo → auto-deploy
# Option C: VPS (any provider)
scp server.js user@host:~/
ssh user@host 'cd ~ && npm install express && node server.js &'
After deploy, verify the agent-ready endpoint is accessible:
curl https://your-domain.com/api/agent-ready | jq .status
# → "ready"
Then test with the auto-mode validator — paste your URL, get an instant readiness score across 9 signals.
Before Claude Code auto mode ships Aug 14, verify your API passes these checks:
Three things converge on Aug 14:
{daily_limit_usdc:5, max_per_call_usdc:1} gives agents hard spending capsAn API with machine-readable 402 headers can participate in this economy. An API without them cannot. The difference is four HTTP headers and a 15-minute tutorial.
The agent economy doesn't need another payment SDK. It needs APIs that speak HTTP 402 fluently. This tutorial gives you the vocabulary. Aug 14 is when the agents start reading.