logicsrc/docs/openswarm/pay2stream.md
Anthony Ettinger be99e683bd
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
Add pay2seed, paid2seed, pay2stream and paid2stream to the OpenSwarm family (#143)
* Add pay2seed to the OpenSwarm family: consent at upload and a paid seed market

OpenSwarm pays a seeder per verified piece served, and nothing pays anyone
to stay. An archive, a backup, a dataset waiting for its buyer or a
podcast's back catalogue earns nothing the month nobody downloads it, so
it dies the way every swarm always has. And nothing in BitTorrent says who
put a swarm there or whether they were allowed to, which is why a seeder
is presumed to be doing something wrong.

pay2seed is the member document for both halves. An attestation, signed
at upload with a fixed basis (own, licensed, open-license, public-domain,
personal) and a notice endpoint, is what a hub requires before it will
list anything; public claims get a claim window and a standing, and a
notice voids them. An offer escrows a budget at an ippay hub for a swarm,
public or private, to be held by M seeders for N days at a price per
GiB-month, bought over x402 exactly as a pass is. Seeders take leases,
prove each period by storage challenge or by a probe over the ordinary
wire, and are paid through the payee they already have. Public feeds ride
on ipdb; ipfile.pin on c0mpute is the same offer on the auction.

Also: the family table, stack diagram and registry rows; the ip seed
command group; PRD 0006; the protocol row on /openswarm.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* Split pay2seed into client and server halves, and add pay2stream and paid2stream

The rule is now in the names. pay2* is the client protocol: the side that
pays, over HTTPS, and plays. paid2* is the server protocol: the BitTorrent
side that earns. One hub implements both halves of a pair; a requester or
viewer implements only pay2*; a seeder, relay or gateway only paid2*.

pay2seed keeps consent, offers, the requester's market and notices.
paid2seed takes leases, storage challenges and probes over the wire,
GiB-month accrual and receipts, the seeder client, and the ipfile.pin
mapping.

pay2stream and paid2stream do the same for a live channel over iplive.
A broadcaster attests the channel (with the two rules that separate a
licensed rebroadcast from a stolen feed), buys relays by the hour, and
publishes listings; viewers buy tickets. Relays take leases and are
proven present by a verifier that pulls segments as a peer; a gateway is
a relay that also serves standard HLS, clear or sealed, with the M3U and
XMLTV pair every IPTV app asks for, so VLC, TiviMate, Kodi and a
television play a paid swarm with nothing installed. Ace Stream showed
BitTorrent can carry live TV to millions; this is that with consent,
payment and an open spec.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* pay2seed: encrypted by default, access as the product, a README in every swarm

The client encrypts by default and the hub never does: what the hub
manages is who may decrypt. A team is a named set of member keys with a
scope over the owner's swarms; the hub, as keeper, issues grants to
members when the owner is offline, with invitations that expire, roles,
an audit trail, and re-encryption on removal so the next version is
closed to whoever left. A few seats are free; above that the hub charges
per seat and per organisation, settled through the same pay plugins as
everything else. Seeding is priced at disk; access is where a hub earns,
and both sides earn: seeders rent disk, requesters sell access.

Public is not a fallback. Encryption off is an explicit act, and a
public swarm is attested, listed, kept and rendered exactly as a private
one is; the only difference is who can read it.

Every swarm on the market carries a README.md at its root, no
exceptions, and the attestation carries its Markdown and the hash of
the copy inside the swarm, so the hub renders it as the swarm's page
without a key. Relative links resolve into the swarm and are gated the
way the files are.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* pay2seed: 1 percent, ads on the free tier, and agents as sellers

Three things the specs did not say. The reference hub takes 1 percent of
any payment that crosses it, charged to whoever is paying and never
deducted from a seeder or a relay, so a quoted price is what the
publisher gets and a promised floor is what the seeder is paid.

Public swarms are free to fetch and free to list, and an advertisement on
the swarm README page is what pays for that. The ad is on the hub page
and nowhere else: never inside a swarm, never injected into a file, a
segment or a playlist, and never in the catalogue or the market API. A
requester who wants no ad buys a seat instead. A free-to-watch channel
works the same way.

And a requester is a key, not a person. An agent can attest what it made,
price access, sell tickets, take payment through its own payee and spend
what it earns keeping its own work online. The consent rules do not
soften because a machine signed them, and the reference hub asks an
agent public attestation to name a responsible operator key so somebody
is reachable when a notice arrives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

* Fix CI: number the PRD requirements and advance the next-id assertion

Two checks the new PRD tripped, both by existing rather than by being
wrong.

The collection validator wants requirements as numbered R# entries and
0006 used a plain ordered list, so it reported OP-L-NO-REQUIREMENTS.
Rewritten as R1 to R7 with priorities, one capability per entry, and the
implementation tracking moved to a paragraph under them where it is not
pretending to be a requirement.

The MCP standards test asserts what the next free PRD id is, and its own
comment says that advances with every PRD added. Adding 0006 makes it
0007.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SKAohrRkqLKVQL2cGCAkR5

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 19:12:45 -07:00

12 KiB

pay2stream: The Client Protocol for Paid Live Streams

Status: 0.1 draft. Member of the OpenSwarm family. Depends on the core, iplive, ippay and pay2seed. Its server half is paid2stream.

1. Scope

pay2stream is the side that pays for a live stream. Two parties speak it over HTTPS to a hub and to a gateway:

  • A broadcaster, who attests a channel (consent), buys guaranteed relay capacity for a window, publishes listings, and sets ticket prices.
  • A viewer, who buys a ticket and watches, either as an iplive peer or, out of the box, on any player that speaks HLS: VLC, TiviMate, Kodi, hls.js, an Apple TV, a Smart TV app. The viewer never installs anything new. What they get is a URL with a pass on it, and an M3U plus an EPG that look, to a television, like the provider they replace.

The BitTorrent side, how a relay takes a lease, proves it is online and serving, runs a gateway that turns swarmed segments into HLS, and is paid, is paid2stream. One hub implements both. A player implements nothing; that is the point.

Prior art

Ace Stream (TorrentStream, 2013) proved BitTorrent carries live television to millions of viewers at once. It never paid a relay, never recorded consent, and never opened its engine. pay2stream and paid2stream are the open answer to the same problem with those three things added.

Non-goals

Encoding and ingest (iplive §6, c0mpute DIP 0019). Chat, ads, a guide format beyond the M3U attributes every IPTV player already reads. DRM past the key a viewer is granted; a gateway serving clear HLS is serving plaintext to whoever holds the pass, and this document says so.

2. Terminology

  • Origin, relay, viewer, channel, head, segment, part, epoch. As iplive §2.
  • Broadcaster. The identity that attests the channel and buys relay offers. Usually the publisher of the iplive.channel.
  • Gateway. A relay that presents the channel over HTTP as HLS and M3U (paid2stream §5).
  • Ticket. An ippay.pass scoped to one or more channel keys, with a window: a game, a day, a month.
  • Listing. A signed ipdb entry saying what is on when, at what price.

A channel is listed on a hub only against a pay2seed.attestation (pay2seed §3) whose subject names the channel:

"subject": { "channel": "ed25519:0d87e09c7fea3ad6ba6c2f3e027ea47f5b245452899910948470906704c5295d" }

visibility is public for a channel any viewer may buy, private for one whose tickets a broadcaster hands out themselves. basis is any value from pay2seed §3.2 except personal. The attestation MUST be signed by the channel key and the publisher key, as the channel record itself is (iplive §3.1).

Two things are stated because they are where live streaming has always gone wrong:

  • A broadcaster relaying a feed they receive under a subscription that forbids redistribution has no basis in the table and MUST NOT attest licensed. A hub that learns of it treats the attestation as false.
  • A broadcaster with a licence that does permit redistribution (a league's own OTT rights, a broadcaster's own channel, a creator's own camera) attests licensed or own and names the licence in description. That is the entire difference between an IPTV reseller and a pirate, and it is now a signed record on a public standing.

The claim window (pay2seed §3.3) applies to a public channel before its first listing, not to each broadcast.

4. Relay offers

A broadcaster buys relays the way a requester buys seeders: an offer with a budget escrowed at the hub, so a stream has relays before its first viewer arrives and keeps them when vouchers alone would not.

{
  "openswarm": "0.1",
  "type": "pay2stream.offer",
  "hub": "ed25519:c9f1…",
  "broadcaster": "ed25519:5d29…",
  "attestation": "sha256:8e1c…",
  "channel": "ed25519:0d87…",
  "window": { "startsAt": "2026-09-12T18:30:00.000Z", "endsAt": "2026-09-12T22:00:00.000Z" },
  "relays": { "min": 4, "max": 12 },
  "regions": ["eu", "us-east"],
  "capacity": { "downstreamPerRelay": 8, "renditions": ["1080p", "720p"] },
  "priceUsdPerRelayHour": "0.050000",
  "gatewayBonusBps": 5000,
  "budgetUsd": "4.200000",
  "proof": { "everyMinutes": 10, "verifiers": ["hub", "broadcaster"] },
  "pass": { "…": "an ippay.pass scoped to the channel, so relays can pull" },
  "payment": { "network": "eip155:8453", "nonce": "0x2f0a…" },
  "createdAt": "2026-09-10T09:00:00.000Z",
  "sigs": [{ "alg": "ed25519", "key": "ed25519:c9f1…", "sig": "…" }]
}
Field Rule
attestation An honoured attestation for channel (§3).
window When relays are wanted. A standing channel MAY post rolling 24 h windows.
relays.min, max Leases before the offer is active; the cap.
regions OPTIONAL. Region labels a relay self-declares; the hub prefers matching relays and never refuses others.
capacity.downstreamPerRelay The iplive maxDownstream a leased relay MUST accept.
priceUsdPerRelayHour The floor a relay earns per proven hour online, on top of vouchers.
gatewayBonusBps OPTIONAL. Extra floor, in basis points of the hourly price, for a relay that also runs a gateway.
budgetUsd Escrowed: at least max * priceUsdPerRelayHour * hours * (1 + gatewayBonusBps/10000).
proof.everyMinutes Period length, 5 to 60.
pass So a leased relay can pull from upstream as a paying peer; the upstream perGib cost is the broadcaster's, not the relay's.

Purchase, lifecycle, voiding and refund are as pay2seed §4.2, over x402 at POST /streams.

5. Tickets and listings

A ticket is an ippay.pass with scope.channels (added to the pass record by this document; the hub verifies it as it verifies scope.files) and a window: the hub sells expiresAt as short as one hour for a channel whose record sets ticket.minHours, and as long as its passDays. Pricing is the channel's keyUsd per grant plus perGib served; a broadcaster who wants a flat ticket sets perGib to zero and keyUsd to the ticket price, and the pass's capUsd to zero. Nobody pays for bytes twice.

A listing is an ipdb entry of type pay2stream.listing: channel, title, start, end, description, and the ticket price at the time, signed by the channel key. Listings are what a market page and an EPG are built from, and what a viewer buys against.

A channel whose keyUsd and perGib are both zero is free to watch: no ticket, no grant, and a gateway serves it to anyone. Its page on the hub carries an advertisement the same way a public swarm's does (pay2seed §5.7), which is what pays for listing it. The stream itself is never interrupted: nothing is injected into a segment, into the playlist, or into the M3U. A broadcaster selling tickets pays the hub its percentage instead, 1 percent at the reference hub, and their page carries no advertising.

6. Watching

6.1 As a peer

iplive §7: resolve the channel, buy or reuse a ticket with grant: true, connect to two peers, pull segments, send vouchers. This is the browser player on bittorrented.com and the ip live watch command.

6.2 On any HLS player

An HLS player cannot sign a voucher, so the viewer's ticket is bought with a gateway's key as payer (ippay §3.3) and the viewer's own identity recorded by the hub as boundBy. The gateway then signs vouchers on the viewer's behalf, bounded by the ticket's capUsd, which is the whole of the viewer's exposure. A viewer who disputes a gateway's spend has the hub's GET /passes/<id> record and the gateway's standing.

The ticket reaches the player as a bearer token in the URL, because that is the only credential an IPTV player can carry:

https://gw-eu1.example.net/openswarm/hls/<channel key>/master.m3u8?pass=<base64url pass>

Gateways also accept the pass as a cookie and as Authorization: Bearer for browser players (paid2stream §5.2).

The pair every IPTV app asks for on setup:

https://gw-eu1.example.net/openswarm/channels.m3u?pass=<pass>
https://gw-eu1.example.net/openswarm/epg.xml?pass=<pass>

The M3U lists every channel the ticket is in scope for, with tvg-id, tvg-name, tvg-logo and group-title; the EPG is XMLTV built from the listings. Point TiviMate or Kodi at those two and it is done. Latency is one segment behind the peer edge, one part with low latency.

Which gateway? GET /streams/<id> lists the gateways currently relaying the channel with their regions and median verified latency; a hub's own gateway is always among them. A viewer client picks the nearest, and a ticket bought against one gateway is presentable at any gateway the hub lists for the channel, since the pass is the hub's record, not the gateway's.

7. Hub API, client side

Relative to a pay2stream.base the hub adds to its ippay.hub record as pay2seed adds its own. The relay and gateway side is paid2stream §6.

Method and path Auth Purpose
POST /streams x402 + X-OpenSwarm-Payer Buy a relay offer (§4).
GET /streams?live&region&basis&minPrice none Channels currently live with their gateways and listings; offers with free relay slots.
GET /streams/<id> none The offer, leases, gateways, the latest listing.
DELETE /streams/<id> broadcaster signed Void and refund the unearned budget.
POST /listings channel signed Publish a pay2stream.listing (also replicated on the channel's ipdb feed).
GET /tickets?payer&channel&hours x402 + X-OpenSwarm-Payer Buy a ticket (§5). payer MAY be a gateway key with the viewer's own key as X-OpenSwarm-Bound-By.
GET /gateways?region&channel none Gateways, and which channels each currently relays.
POST /notices signed As pay2seed §8; voiding ends every lease and delists every gateway for the channel.

8. Client behaviour

A broadcaster client (ip live plus ip stream offer and ip stream ticket in cli.md; bittorrented.com's Live TV rent-out form) attests before listing, buys offers only against its own attestation, includes a pass in the offer, publishes a listing for every window, and receives notices at its endpoint.

A viewer client (a web page, ip live watch, or a plain IPTV app with a URL pasted in) buys or reuses a ticket, prefers a gateway by region, and MUST NOT send a ticket to a gateway the hub does not list for that channel.

9. Security notes

  • Clear HLS is clear. A ticket holder can capture the stream. So could a peer with a grant. The spec does not pretend otherwise.
  • Pass in the URL. It is a bearer token in a log line on every proxy in the path. Hubs SHOULD sell short tickets to gateway-bound viewers and viewers SHOULD prefer the cookie form where a player supports it.
  • Gateway as payer. The viewer's exposure is capUsd; the gateway's incentive to over-sign is bounded by its standing and by the hub comparing signed bytes with the segment count in the window.
  • A stolen feed with a signed attestation is the failure this spec moves from "impossible to know" to "a named key, a public standing, and a notice that ends it".

10. Implementations

Piece Where Status
Reference hub, client side: attestations, offers, tickets, listings, market profullstack/media-streamer (bittorrented.com), Live TV planned; the IPTV resale rail sells per-game passes today, centrally
Viewer in the browser bittorrented.com, tipoffwatch, genrewatch players (hls.js, mpegts.js) no change for HLS; iplive peer mode planned
Players VLC, TiviMate, Kodi, Apple, Android TV no work
Broadcaster CLI ip stream … (cli.md) proposed

11. Conformance

A hub on this side: everything pay2seed §11 requires of it, over channels; sells tickets bound to gateways; lists gateways per channel.

A broadcaster client and a viewer client: §8.

12. Version history

  • 0.1 (2026-09-06): first draft, as the client half; consent for channels, relay offers, tickets and listings, watching as a peer or on any HLS player.