← Blog

April 8, 2026 · security · 7 min read

Pay-to-message bonds: spam control without moderators

Every open messaging system has the same problem. If anyone can DM anyone, someone will spam. The standard answers are also the same: captchas, identity verification, moderation queues, reputation scores, limits tied to a phone number. Each of them adds friction for the honest sender and still gets gamed by a motivated attacker. The honest user answers a puzzle at 2 a.m. to send a short message to a stranger, the spammer runs a solver farm and pushes through anyway. The cost lands on the wrong party.

Spam is a pricing bug

Spam is only economical because the marginal cost of sending is zero. Every other medium with a non-zero per-message cost, paper letters, paid SMS, pre-paid mobile plans in countries where minutes are rationed, has near-zero spam. The economics do not survive contact with a real fee. When a single message costs even one sat, the spammer's spreadsheet falls apart. Not because one sat is a lot. Because they were planning to send billions of them.

Every other anti-spam measure tries to price the message in human time, identity risk, or infrastructure cost. Pay-to-message prices the message in money. That is the variable the spammer actually cares about.

What we built

A user-configurable minimum bond. You set it in Settings. Example: "to DM me for the first time, attach a zap receipt for at least 100 sats". Unknown senders who do not attach a sufficient bond land in a Requests folder, not the main inbox. Senders the user has approved before, and any sender the user has already replied to, bypass the bond entirely. The default ships OFF. It exists for people who need it.

There is no global ledger of who paid what. There is no reputation carried between users. Alice's bond threshold is Alice's policy, enforced by Alice's client. Bob never hears about it unless he tries to DM Alice for the first time.

How it works on the wire

An outbound DM carries an optional Nostr tag. The recipient's client looks up the referenced zap, verifies it was paid to the recipient's Lightning address (LUD-16), and extracts the amount. If the amount meets or exceeds the recipient's configured minimum, the message lands in the main inbox. If not, it lands in Requests, where the user can glance, accept, ignore, or delete. The zap parser and the admission check are decoupled: one service knows how to read receipts, another decides what to do with them.

tags: [
  ["p", "recipient_pubkey"],
  ["bond", "lnbc1u1p...bolt11..."],
]

Bonds are verified against the recipient's own Lightning address. A sender cannot fake a payment to someone else, and cannot reuse one payment across many recipients. If the receipt does not verify, the tag is ignored and the message is treated as unbonded.

What it is not

Not a payment to the recipient per message after they have accepted you. The bond applies only to first contact from an unknown sender. Once the user replies, the sender is waived forever, no further bonds required.

Not a tax on legitimate conversation. Friends, family, anyone you have ever replied to, your approved senders list, all bypass the bond. Most people will never attach a bond to anything, because most people are not cold-messaging strangers.

Not a wall against the poor. The user can waive the bond entirely, set it to zero, or set it to ten sats, which is a fraction of a cent. The amount is the recipient's call. People who want unfiltered inboxes get them. People who want filtered inboxes get those. Nobody else is in the middle of that decision.

Worked example

A recruiter wants to cold-pitch a developer. They attach five hundred sats, roughly twenty cents at current prices. Economic nothing for a real outreach. Economic poison for someone trying to send the same pitch to a hundred thousand people. If the recipient replies, the sender is waived forever and future messages cost nothing. If not, the sender has purchased a few seconds of attention and the system has rejected them cleanly. No moderator reviewed the case. No reputation score changed. No database of identities grew.

How it compares

Honest caveats

A bond does not stop a sender with a lot of sats. It raises the floor, it does not install a ceiling. It does not stop someone who already paid once, got waived, and then spams their approved inbox, although that person has now burned an identity you can simply remove from your approved list. It does not help on channels that are public by design, like the geohash rooms, because those are broadcast, not one-to-one.

The right combinator is: bonds for unsolicited DM first-contact, zero bond for replies, no bonds at all for public rooms. Apply the tool where the economics fit.

Closing

Spam is a pricing bug, not a moral failing. We priced the bug. The rest of the system does not need a moderator, a reputation graph, or a registered identity. That is the whole point.

Published by the Hoppr team. Mirrored as a NIP-23 long-form event (kind 30023) on the Hoppr publication key. Questions: hello@hoppr.chat.