Skip to content

[Payments] : Support Subscription Billing and Tier-Based Relay Access #673

Description

@Ferryx349

Problem

Nostream currently supports one-time pay-to-relay admission, not recurring subscription billing.

Today, a user pays a Lightning invoice once, gets is_admitted = true permanently, and keeps write access forever. There is no plan lifecycle, no renewal flow, no grace period, and no tiered benefits tied to payment.

What exists but is incomplete:

  • One-time admission invoices only (feeSchedule: admission)
  • Permanent admission flag in users.is_admitted
  • Global retention and rate limits not tied to paid status
  • Kind 402 notifications only on payment, not for renewal or expiry
  • No admin view for subscribers, revenue, or dunning ([Admin Console] Phase 6: Payments and Admissions View #636)

This is enough for a simple paid relay gate, but not for relay operators who want recurring billing with plans, renewals, and tiered access.

This is relay-operator billing (users pay the relay for access). It is not the same as creator subscriptions (NIP-88).

Solution

Add a subscription billing layer on top of the existing Lightning payment flow:

  • Define subscription plans in settings
  • Store subscription state in PostgreSQL (user_subscriptions, extended invoices)
  • Reuse PaymentsService for renewal invoices
  • Add a SubscriptionWorker for renewals, expiry, and grace handling
  • Enforce write access, retention, and rate limits based on active plan
  • Notify subscribers via extended kind 402 events
  • Expose plan and status info through NIP-11 and HTTP API
  • Extend the admin console for subscriber and payment operations ([Admin Console] Phase 6: Payments and Admissions View #636, [Admin Console] Phase 7: Webhooks and Notifications #637)

Existing admitted users will be migrated to a grandfathered plan so current access is preserved.

Scope

Database and settings

  • Add subscription_plans and user_subscriptions tables
  • Extend invoices with plan_id, period_start, period_end, subscription_id
  • Add payments.subscriptionPlans[] to settings (amount, interval, grace, benefits)
  • Migration for existing is_admitted users

Subscription core

  • SubscriptionService for subscribe, renew, cancel, and status transitions
  • SubscriptionWorker for renewal invoice generation and expiry handling
  • Subscription lifecycle: active -> renewal_pending -> past_due -> expired (+ cancel at period end)

Enforcement

  • Replace boolean is_admitted check with active subscription in event-message-handler
  • Tier-based retention, rate limits, and connection limits per plan
  • Tier-aware purge in maintenance worker

API and user-facing

  • POST /subscriptions, GET /subscriptions/status
  • Extend kind 402 with subscription tags (status, plan_id, period_end, bolt11)
  • Extend NIP-11 relay info with plans and access requirements
  • Extend resources/invoices.html for subscription checkout and status

Admin console

NIPs involved

Reuse (already in Nostream):

  • NIP-01 — base protocol, NOTICE/CLOSED messages
  • NIP-11 — relay info, plans, payment requirements
  • NIP-40 — expiration on membership events
  • NIP-47 — NWC invoice creation
  • Kind 402 — invoice and subscription status events

Align with drafts:

  • NIP-11 access_control (#2311)
  • NIP-63 membership lists (#2156) — optional interop

Out of scope for v1:

  • NIP-88 (creator zap subscriptions)
  • NIP-57 (zap renewals)
  • NIP-61 / Cashu
  • Publication metering via charge_user()

Key files to extend

  • payments-service.ts — extend period on invoice confirm, not permanent admit
  • event-message-handler.ts — subscription write gate
  • maintenance-worker.ts — renewal/expiry cron
  • user-repository.ts — subscription CRUD
  • root-request-handler.ts — NIP-11 plan advertisement
  • resources/invoices.html — subscription UI

Success criteria

  • Operator can define multiple plans with different benefits
  • Subscriber gets a renewal invoice before period ends
  • Expired subscriptions lose write access
  • Kind 402 notifies renewal due, past due, and expired states
  • NIP-11 advertises available plans
  • Admin can view and manage subscribers
  • Existing admitted users migrate without losing access

CC: @cameri

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions