Pay Per Read

Micropayments for the Web
April 2026 · melvin.me · Part 4 of Solid Articles

1. One Number

In Part 3, we set amount to "0" — a membership gate that checks you've deposited but doesn't charge. Now change it to "10":

"acl:condition": {
  "@type": "PaymentCondition",
  "amount": "10",
  "currency": "tbtc4"
}

That's it. Every read now costs 10 sats. The server deducts from the reader's balance automatically. When the balance hits zero, the reader gets 402 again until they top up.

2. Update the ACL

Using the same setup from Part 3 (JSS running with --pay, Alice's pod, premium article), update the ACL:

curl -X PUT http://localhost:4443/alice/public/premium.json.acl \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/ld+json" \
  -d '[
    {
      "@context": {"acl": "http://www.w3.org/ns/auth/acl#"},
      "@id": "#owner",
      "@type": "acl:Authorization",
      "acl:agent": {"@id": "http://localhost:4443/alice/profile/card#me"},
      "acl:accessTo": {"@id": "http://localhost:4443/alice/public/premium.json"},
      "acl:mode": [{"@id": "acl:Read"}, {"@id": "acl:Write"}, {"@id": "acl:Control"}]
    },
    {
      "@context": {"acl": "http://www.w3.org/ns/auth/acl#"},
      "@id": "#paid",
      "@type": "acl:Authorization",
      "acl:agentClass": {"@id": "acl:AuthenticatedAgent"},
      "acl:accessTo": {"@id": "http://localhost:4443/alice/public/premium.json"},
      "acl:mode": [{"@id": "acl:Read"}],
      "acl:condition": {
        "@type": "PaymentCondition",
        "amount": "10",
        "currency": "tbtc4"
      }
    }
  ]'

3. Watch the Meter

Say you deposited 50 sats in Part 3. Now read the article five times:

Read 1: 200 OK  —  Balance: 50 → 40 sats
Read 2: 200 OK  —  Balance: 40 → 30 sats
Read 3: 200 OK  —  Balance: 30 → 20 sats
Read 4: 200 OK  —  Balance: 20 → 10 sats
Read 5: 200 OK  —  Balance: 10 → 0 sats

Read 6:

402 Payment Required
{
  "type": "PaymentRequired",
  "amount": "10",
  "currency": "tbtc4"
}

Out of sats. Deposit more to continue reading.

4. The Headers

On each successful paid request, the server includes headers so the client can track spending:

HTTP/1.1 200 OK
X-Cost: 10
X-Balance: 30
Content-Type: application/ld+json

A smart client can display a balance meter, warn when funds are low, or prompt for a top-up — all from standard HTTP headers. No proprietary API. No JavaScript SDK. Just headers.

5. Pricing

Different resources can have different prices. Each one is just an ACL:

ResourceAmountUse Case
/free/No conditionPublic content
/members/"0"Membership gate (Part 3)
/articles/"10"Blog posts
/api/data"1"Cheap API calls
/premium/report.pdf"1000"High-value content

Use acl:default to price an entire folder at once, or set per-resource ACLs for individual pricing. The same inheritance model from Part 1.

6. The Business Model

What changed

For the first time, a web server can charge for content using a standard HTTP status code, a standard access control spec, and cryptographic identity. No payment processor. No subscription platform. No cookies tracking what you read. The reader pays sats. The server serves content. The transaction is between two parties, not three.

TraditionalHTTP 402
MiddlemanStripe, PayPal, app storeNone
Fee2.9% + 30¢ per transaction0
Minimum payment~50¢ (economics of card fees)1 sat (~$0.001)
Account requiredEmail, password, credit cardNostr key
TrackingCookies, analytics, profilingNone — key is pseudonymous
ChargebacksYesNo — sats are final
Works offlineNoBalance is local to the pod

A 10-sat article at today's prices costs about one hundredth of a cent. Try charging that with a credit card.