Dev.to · 4 min read

Paywall Any API Endpoint With Two Prices: Sats or Compute

Paywall Any API Endpoint With Two Prices: Sats or Compute

You built an API. It works. Then the scrapers show up. Not paying customers. Bots hammering your endpoint a thousand times a minute, running up your compute bill, and giving you nothing back. The usual fix is API keys, a signup flow, a Stripe integration, a dashboard, and a support inbox for people who lost their key. That is a lot of plumbing to answer one question: did this caller give up something real to reach me? Here is a smaller idea. Put a price on the endpoint itself. Every call costs something. The caller either pays a few sats over Lightning, or burns a bit of their own CPU on a proof-of-work puzzle. No account. No key. No dashboard. The payment IS the authorization. This post walks the whole thing end to end against a live server at gate.powforge.dev. Every number and response below came off a real request. Copy the curl lines and run them yourself. The two-price idea The gate hands the caller a choice for every request: Pay compute. Solve a SHA-256 partial collision in the browser or on the command line. Costs the caller electricity and a second of wall-clock time. Costs you nothing. Pay sats. Settle a Lightning invoice for 10 sats. About a tenth of a cent. Costs the caller money, costs you nothing to verify. Both paths end the same way: the caller gets the gated response. The point is that both paths cost the caller something. A scraper running at scale cannot do either one for free, so the free-riding stops without you ever standing up a login. Path 1: pay with compute Ask the server for a challenge. curl -s https://gate.powforge.dev/api/challenge You get back a fresh nonce and a difficulty: {"nonce":"35df6dfac728013209f389eb8921f5aa6236b8a7b12f794c31b01edac563756f","difficulty":20} Difficulty 20 means the caller has to find a string solution such that SHA-256(nonce + solution) starts with 20 leading zero bits. There is no clever shortcut. You grind candidates until one hits. Here is the whole solver in Node. No dependencies. const crypto = require('crypto'); function valid(nonce, sol, diff) { const h = crypto.createHash('sha256').update(nonce + sol).digest(); const wholeBytes = Math.floor(diff / 8); const remBits = diff % 8; for (let i = 0; i < wholeBytes; i++) if (h[i] !== 0) return false; if (remBits > 0) { const mask = 0xFF { const { nonce, difficulty } = await (await fetch('https://gate.powforge.dev/api/challenge')).json(); let attempt = 0, sol; const t0 = Date.now(); do { attempt++; sol = attempt.toString(36); } while (!valid(nonce, sol, difficulty)); console.log(`solved in ${attempt} attempts, ${Date.now() - t0}ms, solution=${sol}`); const res = await fetch('https://gate.powforge.dev/api/solve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ nonce, solution: sol }), }); console.log(await res.json()); })(); Running that against the live server just now: solved in 113275 attempts, 1277ms, solution=2fej One core, one and a third seconds, a hundred thousand hashes. Then the solve POST comes back with the goods: { "token": "5ec59d49aa431e1c...", "method": "pow", "content": ["Bitcoin is not money. Bitcoin is a weapon system.", "..."] } That is the gated response. The caller proved work, the server checked the hash in a single operation, and access was granted. Notice what did NOT happen: no signup, no email, no key to store, no rate-limit table to maintain. The cost lives in the caller's CPU, and it scales against them automatically. One call is cheap. A million calls is a million times the electricity. The server side of the check is tiny. It is the same hash test, run once: function verifyPoW(nonce, solution, difficulty) { const hash = crypto.createHash('sha256').update(nonce + solution).digest(); const wholeBytes = Math.floor(difficulty / 8); const remBits = difficulty % 8; for (let i = 0; i < wholeBytes; i++) if (hash[i] !== 0) return false; if (remBits > 0) { const mask = 0xFF

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More Programming & Dev News