Attach the rail to your instance — without forking it
Every attachment uses a surface your platform already exposes: a webhook you register, a config value you redirect, a plugin you install, a proxy you put in front. Your platform's source is never modified, and upgrades keep working.
Shared prerequisites (every recipe)
-
A deployed
StakeVaultFactoryon the target chain (contracts/script/DeployStakeRail.s.sol— anvil for local, an L2 testnet for staging). - A running facilitator (
npx up-facilitator) with its API key. -
At least one supporter who has staked + granted a policy via
@universal-paywall/agent(the payer side). -
A wallet registry for your platform's identities — supplied to the sidecar as
PAYER_WALLETS/CREATOR_WALLETSJSON maps (static maps today; music can resolve artists live via MusicBrainz).
The sidecar in one command
Most platforms attach through one env-driven process, up-integration:
PLATFORM=owncast \
FACILITATOR_URL=https://facilitator.example FACILITATOR_API_KEY=… \
PAYER_WALLETS='{"<viewer-id>":"0x…"}' CREATOR_WALLETS='{"<creator-id>":"0x…"}' \
RATE=1000 npx up-integration Environment reference
| Env | Meaning |
|---|---|
PLATFORM | subsonic | navidrome | owncast | jellyfin | rsshub | mastodon | immich-proxy |
FACILITATOR_URL / FACILITATOR_API_KEY | where to report charges |
PAYER_WALLETS / CREATOR_WALLETS | JSON maps: platform id → 0x wallet |
RATE | unit price (per play / per second / per minute / per citation), micro-USDC |
STREAMER_KEY | Owncast only: the creator key for the stream |
PORT | sidecar port (default 8410) |
SIDECAR_API_KEY | optional x-api-key gate on the sidecar |
MUSICBRAINZ_USER_AGENT | music modes: enables recording_mbid → artist_mbid → wallet via WS/2 (CREATOR_WALLETS keyed on artist MBID) |
MUSICBRAINZ_BASE_URL | override WS/2 base (point at a local musicbrainz-server in CI) |
UPSTREAM_URL | immich-proxy only: the Immich base URL to proxy + meter |
Verbatim from the repo's
deployment README,
which also carries each platform's docker-compose.yml.
Per-platform recipes
| Platform | Pattern | Attach surface | Recipe |
|---|---|---|---|
| PeerTube | published plugin | Install the published universal-paywall plugin — per-view support/tips settled on-chain, no PeerTube fork. | repo recipe |
| Owncast | event sidecar | Register an admin webhook for chat presence events — viewers support the streamer per second watched. | repo recipe |
| Navidrome | config redirect | Point ND_LISTENBRAINZ_BASEURL at the sidecar — every play pays the artist, per listen. | repo recipe |
| Subsonic (gonic family) | config redirect | Meter the Subsonic scrobble endpoint — per-play royalties for gonic and other Subsonic-API servers. | repo recipe |
| Jellyfin | event sidecar | Point the official Webhook plugin at the sidecar — watched minutes settle to the library owner. | repo recipe |
| RSSHub | event sidecar | A per-citation toll at the crawler boundary — AI agents pay authors when they ground answers in feed items. | repo recipe |
| Immich | reverse proxy | A transparent reverse proxy in front of Immich meters shared-link photo resolves — a per-resolve license fee. | repo recipe |
| Mastodon | external provider | Serve Mastodon's donation-campaign slot — instance donations settle on-chain, transparently. | repo recipe |
| MusicBrainz | resolver | The identity registry that turns a music scrobble into a payable artist — recording MBID → artist MBID → wallet. | repo recipe |
Verifying your attachment
Each integration page carries its verify command; the general pattern is the
on-chain e2e loops (npm run e2e:<platform> -w
@universal-paywall/integrations against a local anvil chain). The success
check is always the same: after one real platform event from a staked supporter,
the payee's on-chain balance increased by exactly rate × units.