Earn Bitcoin passively by running pay-per-use API endpoints on the Spark Network.
Every time an AI agent or automated client calls one of your endpoints, they pay sats directly to your Spark wallet — zero fees, instant settlement.
Built on the S402 protocol which uses the HTTP 402 Payment Required status code.
Client → POST /api/price
← 402 + { quote_id, amount_sats, spark_address }
Client pays sats via Spark → gets txId
Client → POST /api/price
headers: X-Spark-Payment: <txId>
body: { ..., quote_id: "q_..." }
← 200 + result
| Endpoint | Method | Price | Description |
|---|---|---|---|
/api/echo |
POST | 100 sats | Echo test — confirms payment flow works |
/api/price |
POST | 200 sats | Live crypto prices (BTC, ETH, SOL, etc.) |
/api/text |
POST | 500 sats | AI text generation (GPT-4o-mini) |
/api/wallet/info |
GET | Free | Server info, endpoint list, payment instructions |
/api/wallet/balance |
GET | Free | Your current BTC balance |
npm installcp .env.example .envEdit .env:
SPARK_NETWORK=MAINNET # or REGTEST for testing
OPENAI_API_KEY= # optional — only needed for /api/text
PORT=3000
npm run setup-walletThis will:
- Generate a new Spark wallet (or load one from
SPARK_MNEMONIC) - Print your mnemonic — save this somewhere safe
- Print your Spark address (where clients pay you)
- Print your Bitcoin deposit address (to fund from L1)
- Auto-update your
.envfile
Send some BTC to your deposit address from any Bitcoin wallet. This isn't required to receive payments, but it proves the wallet is working.
npm start# In .env, set: SPARK_NETWORK=REGTEST
# Then:
npm run setup-wallet # generates a REGTEST wallet
npm start # start the server
node src/test-client.js # runs full payment flow# 1. Get a quote
curl -X POST http://localhost:3000/api/price \
-H "Content-Type: application/json" \
-d '{"symbols": ["BTC", "ETH"]}'
# You'll get:
# {
# "payment": {
# "quote_id": "q_abc123...",
# "amount_sats": 200,
# "spark_address": "spark1q...",
# "expires_at": 1234567890
# }
# }
# 2. Send 200 sats to spark_address from your Spark wallet
# Copy the transaction ID
# 3. Retry with payment proof
curl -X POST http://localhost:3000/api/price \
-H "Content-Type: application/json" \
-H "X-Spark-Payment: <your-txId>" \
-d '{"symbols": ["BTC", "ETH"], "quote_id": "q_abc123..."}'Request: { "message": "hello world" }
Response: { "success": true, "you_sent": { "message": "hello world" }, "paid_sats": 100 }Request: { "symbols": ["BTC", "SOL"], "currency": "usd" }
Response: {
"prices": {
"BTC": { "price": 85000, "change_24h": 2.3 },
"SOL": { "price": 142, "change_24h": -1.1 }
}
}Supported symbols: BTC, ETH, SOL, DOGE, ADA, MATIC, AVAX, LINK
Request: { "prompt": "Write a haiku about Bitcoin", "max_tokens": 100 }
Response: { "result": "Satoshis flow free..." }Requires OPENAI_API_KEY in .env. Runs in demo mode without it.
- Push this repo to GitHub
- Create a new service pointing to your repo
- Set environment variables:
SPARK_MNEMONIC— your 12-word mnemonicSPARK_NETWORK=MAINNETOPENAI_API_KEY(optional)
- Deploy
Once live, post your server URL in:
- utxo.fun community
- Spark Discord / Twitter
- AI agent directories that support S402
Copy any route file and customize:
// src/routes/my-endpoint.js
import { Router } from 'express';
import { requirePayment } from '../middleware/s402.js';
const router = Router();
router.post('/', requirePayment({ sats: 1000 }), async (req, res) => {
// Your logic here — payment is already verified
res.json({ success: true, result: 'your data' });
});
export default router;Then register it in server.js:
import myRouter from './routes/my-endpoint.js';
app.use('/api/my-endpoint', myRouter);- Spark SDK — Bitcoin L2 wallet + payments
- S402 Protocol — HTTP 402 payment standard
- Express.js — HTTP server
- Node.js 18+
- Never commit your
.envfile or mnemonic - Quote IDs expire in 5 minutes — prevents stale payment attacks
- Transaction IDs are tracked to prevent replay attacks
- For production, swap the in-memory payment store for Redis or a DB