Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    Inventory & Stock
    Vendor Management
    Commissions & Settlements
    SubscriptionConductor
    PaymentConductor
    Ring Oracle
    Payments Overview
    Public Pools & DAO Jars
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    Ring Tasks
    WebRTC Calls & STUNner TURN
    Peer Games
    News Module
    Member Blogs
    Public Profile Pages
    Profile Account Widgets
    Ring File Cabinet
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Ring Mailer & RingdomX Mail
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Admin Wiki
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Vertical Presets (SSOT)
    Ringization playbook
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Project configuration
    Public environment variables
    Order Lab secrets
    WalletConnect Project ID (Reown Cloud)
    Supported services
    NODUS wiki (project knowledge)
    Configuration playbook
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel Deployment
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Backend Services
    Firebase Integration
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)

    Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    Inventory & Stock
    Vendor Management
    Commissions & Settlements
    SubscriptionConductor
    PaymentConductor
    Ring Oracle
    Payments Overview
    Public Pools & DAO Jars
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    Ring Tasks
    WebRTC Calls & STUNner TURN
    Peer Games
    News Module
    Member Blogs
    Public Profile Pages
    Profile Account Widgets
    Ring File Cabinet
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Ring Mailer & RingdomX Mail
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Admin Wiki
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Vertical Presets (SSOT)
    Ringization playbook
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Project configuration
    Public environment variables
    Order Lab secrets
    WalletConnect Project ID (Reown Cloud)
    Supported services
    NODUS wiki (project knowledge)
    Configuration playbook
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel Deployment
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Backend Services
    Firebase Integration
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)

    Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    Inventory & Stock
    Vendor Management
    Commissions & Settlements
    SubscriptionConductor
    PaymentConductor
    Ring Oracle
    Payments Overview
    Public Pools & DAO Jars
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    Ring Tasks
    WebRTC Calls & STUNner TURN
    Peer Games
    News Module
    Member Blogs
    Public Profile Pages
    Profile Account Widgets
    Ring File Cabinet
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Ring Mailer & RingdomX Mail
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Admin Wiki
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Vertical Presets (SSOT)
    Ringization playbook
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Project configuration
    Public environment variables
    Order Lab secrets
    WalletConnect Project ID (Reown Cloud)
    Supported services
    NODUS wiki (project knowledge)
    Configuration playbook
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel Deployment
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Backend Services
    Firebase Integration
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)
    Ring Platform Logo

    Loading documentation...

    Preparing Ring Platform content

    Ring Platform Logo

    Loading documentation...

    Preparing Ring Platform content

    Ring Platform Logo

    Loading documentation...

    Preparing Ring Platform content

    SubscriptionConductor

    Filter this page with Founder / Developer in the docs sidebar. Founders learn provider costs, the manage page, PayPal, and Stars; developers get ledger fields, provider modules, and webhook branches.

    SubscriptionConductor is Ring Platform's multi-provider membership billing facade. One SSOT ledger (subscription_ledger) tracks subscriber state for every rail. Provider modules implement SubscriptionProviderModule; PaymentConductor still owns one-shot Orders (store / wallet / one-shot membership).

    Implementation: lib/payments/subscription/. Manage UI: /membership/manage.

    What founders get

    Recurring membership revenue with clear gateway fees. Internal rails (credit points, native token, NFT gate) charge 0% platform PSP fee. Members manage cancel / renew / history on Manage membership (/membership/manage) — not only the upgrade funnel at /membership.

    Member entitlement — File Cabinet

    Own file manager (/file-cabinet) and gallery manage (/profile/gallery) are member+ (hasMemberPrivileges + MemberUpgradeGate). Shared-with-me (/profile/shared) is subscriber+ for trustee shares; subscriber-only users see an upgrade CTA for an own manager — see Ring File Cabinet.

    Feature status

    ProviderDetailsGatewayStatus
    Credit BalanceAuto-deduct credit units (points)Credit points✅ Live
    WayForPayCard HPP + recToken regularApiWayForPay✅ Live
    StripeStripe Subscriptions APIStripe✅ Live
    Native TokenOn-chain Solana / RingMembershipNative RING✅ Live
    NFT GateMetaplex Core + GateEscrow stakeNFT Gate✅ Live (MVP-A)
    PayPalSubscriptions v1 (recurring) + Orders one-shotPayPal✅ Live (flags + credentials)

    Telegram Stars (operator view)

    1. Set a Mini App / Stars bot token: prefer TELEGRAM_MINI_APP_BOT_TOKEN (same helper as Mini App auth — see Authentication).
    2. Checkout must pass metadata.telegramUserId (the payer’s Telegram numeric id). Optional: metadata.invoiceTitle / invoiceDescription.
    3. Conductor creates a pending ledger row and returns a Telegram invoice URL (redirect.mode: navigate). Member pays in Telegram (currency XTR).
    4. Ledger stays pending until Telegram successful_payment on POST /api/telegram/stars-bot/webhook activates it (same pattern as PayPal BILLING.SUBSCRIPTION.ACTIVATED). Do not treat invoice creation alone as paid membership.

    PayPal for membership (operator view)

    1. Set payment.gateways.paypal.enabled: true in ring-config.json.
    2. Fill sandbox/live credentials: PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, PAYPAL_MODE.
    3. Turn on the public UI flag: NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true (also gates store PayPal + membership PaymentModal PayPal tab).
    4. In PayPal Developer, subscribe the webhook to Orders and billing events (BILLING.SUBSCRIPTION.*, PAYMENT.SALE.COMPLETED).
    5. After first Product/Plan create, cache PAYPAL_MEMBERSHIP_PRODUCT_ID / PAYPAL_MEMBERSHIP_PLAN_ID so checkout does not recreate catalog objects every time.

    Members land on /membership/manage after upgrade (members hitting /membership redirect there). Cancel uses the PayPal subscription id (I-…) stored on the ledger.

    Fee rates & net revenue

    ProviderFee %Fixed FeeCurrency
    WayForPay2.5%—UAH (typical)
    Stripe2.9%$0.30USD
    Credit Balance0%—Credit units
    Native Token0%—RING
    NFT Gate0%—RING
    PayPal

    Net: net = gross - (gross × feePercent / 100) - feeFixed via calculateNetRevenue() in subscription-config.ts. Stars fee percent in admin stats defaults to 0 until you configure gateway fees for telegram_stars.

    Configuration sketch

    Prod public flags must also be baked as Docker NEXT_PUBLIC_* build-args and applied via k8s ConfigMap/Secret — see ENV-PROD-WIRING in the clone (ring-platform.org/k8s/ENV-PROD-WIRING.md).

    Admin dashboard

    Superadmins: /admin/subscriptions — list, filters, net revenue, /api/admin/subscriptions/stats.

    Architecture

    PayPal recurring uses Subscriptions v1 inside paypal-subscription.ts (Product → Plan → POST /v1/billing/subscriptions). Ledger starts pending; BILLING.SUBSCRIPTION.ACTIVATED promotes to active without calling provider create again.

    PayPal one-shot (auto_subscribe=false) uses PaymentConductor Orders v2; fulfillment is PAYMENT.CAPTURE.COMPLETED → handleMembershipPayPalCapture → recordPaidSubscription / activate pending.

    Telegram Stars (telegram_stars): createInvoiceLink with currency: XTR, payload = stars_<uuid> (also used as ledger id). Returns ledgerStatus: 'pending' + navigate URL. Activation: Mini App bot webhook POST /api/telegram/stars-bot/webhook handles pre_checkout_query → answerPreCheckoutQuery, then successful_payment → SubscriptionConductor.activateTelegramStarsPayment (status active + MEMBER upgrade + stores telegram_payment_charge_id). Env: TELEGRAM_MINI_APP_BOT_TOKEN + TELEGRAM_STARS_WEBHOOK_SECRET.

    Store checkout PayPal remains Orders-only: POST /api/store/payments/paypal.

    Provider registry

    Provider IDModulePath
    credit_balance

    Related documentation

    Related documentation

    PaymentConductor

    Prerequisite: one-shot Orders vs this recurring ledger facade.

    WayForPay Payment Integration

    Same-workflow: card HPP + recToken pattern mirrored by PayPal I-….

    PaymentConductor architecture

    Deep-dive: webhook dispatcher and API route table.

    Solana NFT Gates

    See-also: GateEscrow stakes shown on the manage page.

    SubscriptionConductor

    Filter this page with Founder / Developer in the docs sidebar. Founders learn provider costs, the manage page, PayPal, and Stars; developers get ledger fields, provider modules, and webhook branches.

    SubscriptionConductor is Ring Platform's multi-provider membership billing facade. One SSOT ledger (subscription_ledger) tracks subscriber state for every rail. Provider modules implement SubscriptionProviderModule; PaymentConductor still owns one-shot Orders (store / wallet / one-shot membership).

    Implementation: lib/payments/subscription/. Manage UI: /membership/manage.

    What founders get

    Recurring membership revenue with clear gateway fees. Internal rails (credit points, native token, NFT gate) charge 0% platform PSP fee. Members manage cancel / renew / history on Manage membership (/membership/manage) — not only the upgrade funnel at /membership.

    Member entitlement — File Cabinet

    Own file manager (/file-cabinet) and gallery manage (/profile/gallery) are member+ (hasMemberPrivileges + MemberUpgradeGate). Shared-with-me (/profile/shared) is subscriber+ for trustee shares; subscriber-only users see an upgrade CTA for an own manager — see Ring File Cabinet.

    Feature status

    ProviderDetailsGatewayStatus
    Credit BalanceAuto-deduct credit units (points)Credit points✅ Live
    WayForPayCard HPP + recToken regularApiWayForPay✅ Live
    StripeStripe Subscriptions APIStripe✅ Live
    Native TokenOn-chain Solana / RingMembershipNative RING✅ Live
    NFT GateMetaplex Core + GateEscrow stakeNFT Gate✅ Live (MVP-A)
    PayPalSubscriptions v1 (recurring) + Orders one-shotPayPal✅ Live (flags + credentials)

    Telegram Stars (operator view)

    1. Set a Mini App / Stars bot token: prefer TELEGRAM_MINI_APP_BOT_TOKEN (same helper as Mini App auth — see Authentication).
    2. Checkout must pass metadata.telegramUserId (the payer’s Telegram numeric id). Optional: metadata.invoiceTitle / invoiceDescription.
    3. Conductor creates a pending ledger row and returns a Telegram invoice URL (redirect.mode: navigate). Member pays in Telegram (currency XTR).
    4. Ledger stays pending until Telegram successful_payment on POST /api/telegram/stars-bot/webhook activates it (same pattern as PayPal BILLING.SUBSCRIPTION.ACTIVATED). Do not treat invoice creation alone as paid membership.

    PayPal for membership (operator view)

    1. Set payment.gateways.paypal.enabled: true in ring-config.json.
    2. Fill sandbox/live credentials: PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, PAYPAL_MODE.
    3. Turn on the public UI flag: NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true (also gates store PayPal + membership PaymentModal PayPal tab).
    4. In PayPal Developer, subscribe the webhook to Orders and billing events (BILLING.SUBSCRIPTION.*, PAYMENT.SALE.COMPLETED).
    5. After first Product/Plan create, cache PAYPAL_MEMBERSHIP_PRODUCT_ID / PAYPAL_MEMBERSHIP_PLAN_ID so checkout does not recreate catalog objects every time.

    Members land on /membership/manage after upgrade (members hitting /membership redirect there). Cancel uses the PayPal subscription id (I-…) stored on the ledger.

    Fee rates & net revenue

    ProviderFee %Fixed FeeCurrency
    WayForPay2.5%—UAH (typical)
    Stripe2.9%$0.30USD
    Credit Balance0%—Credit units
    Native Token0%—RING
    NFT Gate0%—RING
    PayPal

    Net: net = gross - (gross × feePercent / 100) - feeFixed via calculateNetRevenue() in subscription-config.ts. Stars fee percent in admin stats defaults to 0 until you configure gateway fees for telegram_stars.

    Configuration sketch

    Prod public flags must also be baked as Docker NEXT_PUBLIC_* build-args and applied via k8s ConfigMap/Secret — see ENV-PROD-WIRING in the clone (ring-platform.org/k8s/ENV-PROD-WIRING.md).

    Admin dashboard

    Superadmins: /admin/subscriptions — list, filters, net revenue, /api/admin/subscriptions/stats.

    Architecture

    PayPal recurring uses Subscriptions v1 inside paypal-subscription.ts (Product → Plan → POST /v1/billing/subscriptions). Ledger starts pending; BILLING.SUBSCRIPTION.ACTIVATED promotes to active without calling provider create again.

    PayPal one-shot (auto_subscribe=false) uses PaymentConductor Orders v2; fulfillment is PAYMENT.CAPTURE.COMPLETED → handleMembershipPayPalCapture → recordPaidSubscription / activate pending.

    Telegram Stars (telegram_stars): createInvoiceLink with currency: XTR, payload = stars_<uuid> (also used as ledger id). Returns ledgerStatus: 'pending' + navigate URL. Activation: Mini App bot webhook POST /api/telegram/stars-bot/webhook handles pre_checkout_query → answerPreCheckoutQuery, then successful_payment → SubscriptionConductor.activateTelegramStarsPayment (status active + MEMBER upgrade + stores telegram_payment_charge_id). Env: TELEGRAM_MINI_APP_BOT_TOKEN + TELEGRAM_STARS_WEBHOOK_SECRET.

    Store checkout PayPal remains Orders-only: POST /api/store/payments/paypal.

    Provider registry

    Provider IDModulePath
    credit_balance

    Related documentation

    Related documentation

    PaymentConductor

    Prerequisite: one-shot Orders vs this recurring ledger facade.

    WayForPay Payment Integration

    Same-workflow: card HPP + recToken pattern mirrored by PayPal I-….

    PaymentConductor architecture

    Deep-dive: webhook dispatcher and API route table.

    Solana NFT Gates

    See-also: GateEscrow stakes shown on the manage page.

    SubscriptionConductor

    Filter this page with Founder / Developer in the docs sidebar. Founders learn provider costs, the manage page, PayPal, and Stars; developers get ledger fields, provider modules, and webhook branches.

    SubscriptionConductor is Ring Platform's multi-provider membership billing facade. One SSOT ledger (subscription_ledger) tracks subscriber state for every rail. Provider modules implement SubscriptionProviderModule; PaymentConductor still owns one-shot Orders (store / wallet / one-shot membership).

    Implementation: lib/payments/subscription/. Manage UI: /membership/manage.

    What founders get

    Recurring membership revenue with clear gateway fees. Internal rails (credit points, native token, NFT gate) charge 0% platform PSP fee. Members manage cancel / renew / history on Manage membership (/membership/manage) — not only the upgrade funnel at /membership.

    Member entitlement — File Cabinet

    Own file manager (/file-cabinet) and gallery manage (/profile/gallery) are member+ (hasMemberPrivileges + MemberUpgradeGate). Shared-with-me (/profile/shared) is subscriber+ for trustee shares; subscriber-only users see an upgrade CTA for an own manager — see Ring File Cabinet.

    Feature status

    ProviderDetailsGatewayStatus
    Credit BalanceAuto-deduct credit units (points)Credit points✅ Live
    WayForPayCard HPP + recToken regularApiWayForPay✅ Live
    StripeStripe Subscriptions APIStripe✅ Live
    Native TokenOn-chain Solana / RingMembershipNative RING✅ Live
    NFT GateMetaplex Core + GateEscrow stakeNFT Gate✅ Live (MVP-A)
    PayPalSubscriptions v1 (recurring) + Orders one-shotPayPal✅ Live (flags + credentials)

    Telegram Stars (operator view)

    1. Set a Mini App / Stars bot token: prefer TELEGRAM_MINI_APP_BOT_TOKEN (same helper as Mini App auth — see Authentication).
    2. Checkout must pass metadata.telegramUserId (the payer’s Telegram numeric id). Optional: metadata.invoiceTitle / invoiceDescription.
    3. Conductor creates a pending ledger row and returns a Telegram invoice URL (redirect.mode: navigate). Member pays in Telegram (currency XTR).
    4. Ledger stays pending until Telegram successful_payment on POST /api/telegram/stars-bot/webhook activates it (same pattern as PayPal BILLING.SUBSCRIPTION.ACTIVATED). Do not treat invoice creation alone as paid membership.

    PayPal for membership (operator view)

    1. Set payment.gateways.paypal.enabled: true in ring-config.json.
    2. Fill sandbox/live credentials: PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, PAYPAL_MODE.
    3. Turn on the public UI flag: NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true (also gates store PayPal + membership PaymentModal PayPal tab).
    4. In PayPal Developer, subscribe the webhook to Orders and billing events (BILLING.SUBSCRIPTION.*, PAYMENT.SALE.COMPLETED).
    5. After first Product/Plan create, cache PAYPAL_MEMBERSHIP_PRODUCT_ID / PAYPAL_MEMBERSHIP_PLAN_ID so checkout does not recreate catalog objects every time.

    Members land on /membership/manage after upgrade (members hitting /membership redirect there). Cancel uses the PayPal subscription id (I-…) stored on the ledger.

    Fee rates & net revenue

    ProviderFee %Fixed FeeCurrency
    WayForPay2.5%—UAH (typical)
    Stripe2.9%$0.30USD
    Credit Balance0%—Credit units
    Native Token0%—RING
    NFT Gate0%—RING
    PayPal

    Net: net = gross - (gross × feePercent / 100) - feeFixed via calculateNetRevenue() in subscription-config.ts. Stars fee percent in admin stats defaults to 0 until you configure gateway fees for telegram_stars.

    Configuration sketch

    Prod public flags must also be baked as Docker NEXT_PUBLIC_* build-args and applied via k8s ConfigMap/Secret — see ENV-PROD-WIRING in the clone (ring-platform.org/k8s/ENV-PROD-WIRING.md).

    Admin dashboard

    Superadmins: /admin/subscriptions — list, filters, net revenue, /api/admin/subscriptions/stats.

    Architecture

    PayPal recurring uses Subscriptions v1 inside paypal-subscription.ts (Product → Plan → POST /v1/billing/subscriptions). Ledger starts pending; BILLING.SUBSCRIPTION.ACTIVATED promotes to active without calling provider create again.

    PayPal one-shot (auto_subscribe=false) uses PaymentConductor Orders v2; fulfillment is PAYMENT.CAPTURE.COMPLETED → handleMembershipPayPalCapture → recordPaidSubscription / activate pending.

    Telegram Stars (telegram_stars): createInvoiceLink with currency: XTR, payload = stars_<uuid> (also used as ledger id). Returns ledgerStatus: 'pending' + navigate URL. Activation: Mini App bot webhook POST /api/telegram/stars-bot/webhook handles pre_checkout_query → answerPreCheckoutQuery, then successful_payment → SubscriptionConductor.activateTelegramStarsPayment (status active + MEMBER upgrade + stores telegram_payment_charge_id). Env: TELEGRAM_MINI_APP_BOT_TOKEN + TELEGRAM_STARS_WEBHOOK_SECRET.

    Store checkout PayPal remains Orders-only: POST /api/store/payments/paypal.

    Provider registry

    Provider IDModulePath
    credit_balance

    Related documentation

    Related documentation

    PaymentConductor

    Prerequisite: one-shot Orders vs this recurring ledger facade.

    WayForPay Payment Integration

    Same-workflow: card HPP + recToken pattern mirrored by PayPal I-….

    PaymentConductor architecture

    Deep-dive: webhook dispatcher and API route table.

    Solana NFT Gates

    See-also: GateEscrow stakes shown on the manage page.

    Telegram Stars
    XTR invoice link via Bot API createInvoiceLink
    Telegram
    ✅ Create pending — webhook activation TBD
    2.9%
    $0.30
    USD
    Telegram StarsTelegram commission (operator-side)—XTR
    ringCreditSubscriptionProvider
    providers/ring-credit-subscription.ts
    native_tokennativeTokenSubscriptionProviderproviders/native-token-subscription.ts
    stripestripeSubscriptionProviderproviders/stripe-subscription.ts
    wayforpaywayforpaySubscriptionProviderproviders/wayforpay-subscription.ts
    nft_gatenftGateSubscriptionProviderproviders/nft-gate-subscription.ts
    paypalpaypalSubscriptionProviderproviders/paypal-subscription.ts
    telegram_starstelegramStarsSubscriptionProviderproviders/telegram-stars-subscription.ts

    Client helpers: createPayPalBillingSubscription, cancelPayPalBillingSubscription, getPayPalBillingSubscription in lib/payments/processors/paypal-client.ts.

    Stars env helper: getTelegramMiniAppBotToken() from lib/auth/telegram-miniapp-initdata.ts.

    subscription_ledger (verified fields)

    Schema: lib/payments/subscription/subscription-ledger-schema.ts.

    FieldNotes
    statuspending | active | expired | cancelled | suspended | grace_period
    methodcard | credit_balance | crypto | nft | paypal | stars
    providerincludes telegram_stars
    paypal_subscription_idPayPal Subscriptions I-… (not Orders orderReference)
    telegram_stars_payload / telegram_stars_invoice_linkPayload = ledger id; invoice URL from createInvoiceLink
    telegram_payment_charge_idSet on successful_payment (refundStarPayment)
    stripe_subscription_id / wayforpay_rec_token / solana_tx_signature / nft_mint_addressOther rails

    gatewayRefToField('paypal') → { paypal_subscription_id }. Cancel API + app/_actions/membership.ts pass that id into SubscriptionConductor.cancelSubscription.

    Conductor extras (PayPal / webhooks)

    OperationRole
    createSubscriptionHonors ledgerStatus: 'pending' — skips MEMBER upgrade until active
    recordPaidSubscriptionInsert active row without calling provider (Orders capture)
    findByPaypalSubscriptionIdWebhook lookup by I-…
    updateSubscriptionStatusCan set paypal_subscription_id, payments aggregates

    PayPal webhook branches

    dispatchPayPalWebhook (webhook-dispatcher.ts):

    EventHandler
    PAYMENT.CAPTURE.COMPLETEDOrders purpose handlers (store / membership capture / wallet / news)
    BILLING.SUBSCRIPTION.ACTIVATEDmembership-paypal-subscription.ts → activate ledger
    PAYMENT.SALE.COMPLETEDAdvance next_payment_due / payments_count
    BILLING.SUBSCRIPTION.CANCELLED / SUSPENDED / EXPIRED / PAYMENT.FAILEDTerminal / suspended status

    Canonical route: POST /api/payments/paypal/webhook.

    Membership & manage routes

    MethodPathRole
    POST/api/membership/payment/paypalCreate recurring (default) or renew status-sync
    POST/api/membership/subscription/cancelCancel; extracts paypal_subscription_id
    GET/api/membership/subscription/statuscan_cancel for active | pending
    Page/[locale]/(protected)/membership/manageSubscriptionManagement + role + NFT stakes + payment_transactions
    Route helperROUTES.MEMBERSHIP_MANAGE(locale)/membership/manage

    UI: components/membership/payment-modal.tsx PayPal tab when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true; components/membership/subscription-management.tsx on the manage page.

    Environment variables

    Secrets stay runtime (K8s Secret). Public flags also need Dockerfile / prod.js build-args for client bundles.

    Cron pipelines

    Unchanged five membership crons in lib/processes/registry.ts (expiry, credit-balance monthly, subscription-payment, solana-batch, nft-gate-expiry). PayPal renewals are primarily webhook-driven (PAYMENT.SALE.COMPLETED); manual renew is a Subscriptions GET status sync. Stars renew currently returns a synthetic success + 30-day nextPaymentDue — production renew should follow Telegram payment events once the webhook is live.

    Anti-patterns

    • Do not call SubscriptionConductor.createSubscription from PayPal webhooks (re-opens checkout). Use recordPaidSubscription / updateSubscriptionStatus.
    • Do not store Orders orderReference as paypal_subscription_id.
    • Do not treat returnUrl alone as paid — wait for webhook events.
    • Do not treat Stars createInvoiceLink success as membership — wait for successful_payment on /api/telegram/stars-bot/webhook → activate pending ledger.
    • Do not omit metadata.telegramUserId on Stars create (provider returns an error).

    Payments Overview

    See-also: purpose map across the clone.

    Payment Gateway Integration

    Next-step: operator PSP checklist.

    Authentication

    Depends-on: Mini App bot token helper used by telegram_stars invoices.

    Ring File Cabinet

    Same-workflow: own File Cabinet (/file-cabinet) and gallery are member+; shared-with-me (/profile/shared) is subscriber+ for trustees.

    json
    
    {
      "payment": {
        "cardPaymentProcessor": "wayforpay",
        "gateways": {
          "paypal": { "enabled": true, "feePercent": 2.9, "feeFixedCents": 30, "currency": "USD" }
        }
      }
    }
    text
    
    Membership upgrade / PaymentModal / manage cancel
            ↓
    SubscriptionConductor (create | cancel | renew | recordPaidSubscription)
            ↓
    Providers: stripe | wayforpay | credit_balance | native_token | nft_gate | paypal | telegram_stars
            ↓
    subscription_ledger  (paypal_subscription_id = PayPal I-…; Stars stores invoice link pending)
            ↓
    Cron: expiry · credit-balance · payment · solana-batch · nft-gate
    Telegram Stars
    XTR invoice link via Bot API createInvoiceLink
    Telegram
    ✅ Create pending — webhook activation TBD
    2.9%
    $0.30
    USD
    Telegram StarsTelegram commission (operator-side)—XTR
    ringCreditSubscriptionProvider
    providers/ring-credit-subscription.ts
    native_tokennativeTokenSubscriptionProviderproviders/native-token-subscription.ts
    stripestripeSubscriptionProviderproviders/stripe-subscription.ts
    wayforpaywayforpaySubscriptionProviderproviders/wayforpay-subscription.ts
    nft_gatenftGateSubscriptionProviderproviders/nft-gate-subscription.ts
    paypalpaypalSubscriptionProviderproviders/paypal-subscription.ts
    telegram_starstelegramStarsSubscriptionProviderproviders/telegram-stars-subscription.ts

    Client helpers: createPayPalBillingSubscription, cancelPayPalBillingSubscription, getPayPalBillingSubscription in lib/payments/processors/paypal-client.ts.

    Stars env helper: getTelegramMiniAppBotToken() from lib/auth/telegram-miniapp-initdata.ts.

    subscription_ledger (verified fields)

    Schema: lib/payments/subscription/subscription-ledger-schema.ts.

    FieldNotes
    statuspending | active | expired | cancelled | suspended | grace_period
    methodcard | credit_balance | crypto | nft | paypal | stars
    providerincludes telegram_stars
    paypal_subscription_idPayPal Subscriptions I-… (not Orders orderReference)
    telegram_stars_payload / telegram_stars_invoice_linkPayload = ledger id; invoice URL from createInvoiceLink
    telegram_payment_charge_idSet on successful_payment (refundStarPayment)
    stripe_subscription_id / wayforpay_rec_token / solana_tx_signature / nft_mint_addressOther rails

    gatewayRefToField('paypal') → { paypal_subscription_id }. Cancel API + app/_actions/membership.ts pass that id into SubscriptionConductor.cancelSubscription.

    Conductor extras (PayPal / webhooks)

    OperationRole
    createSubscriptionHonors ledgerStatus: 'pending' — skips MEMBER upgrade until active
    recordPaidSubscriptionInsert active row without calling provider (Orders capture)
    findByPaypalSubscriptionIdWebhook lookup by I-…
    updateSubscriptionStatusCan set paypal_subscription_id, payments aggregates

    PayPal webhook branches

    dispatchPayPalWebhook (webhook-dispatcher.ts):

    EventHandler
    PAYMENT.CAPTURE.COMPLETEDOrders purpose handlers (store / membership capture / wallet / news)
    BILLING.SUBSCRIPTION.ACTIVATEDmembership-paypal-subscription.ts → activate ledger
    PAYMENT.SALE.COMPLETEDAdvance next_payment_due / payments_count
    BILLING.SUBSCRIPTION.CANCELLED / SUSPENDED / EXPIRED / PAYMENT.FAILEDTerminal / suspended status

    Canonical route: POST /api/payments/paypal/webhook.

    Membership & manage routes

    MethodPathRole
    POST/api/membership/payment/paypalCreate recurring (default) or renew status-sync
    POST/api/membership/subscription/cancelCancel; extracts paypal_subscription_id
    GET/api/membership/subscription/statuscan_cancel for active | pending
    Page/[locale]/(protected)/membership/manageSubscriptionManagement + role + NFT stakes + payment_transactions
    Route helperROUTES.MEMBERSHIP_MANAGE(locale)/membership/manage

    UI: components/membership/payment-modal.tsx PayPal tab when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true; components/membership/subscription-management.tsx on the manage page.

    Environment variables

    Secrets stay runtime (K8s Secret). Public flags also need Dockerfile / prod.js build-args for client bundles.

    Cron pipelines

    Unchanged five membership crons in lib/processes/registry.ts (expiry, credit-balance monthly, subscription-payment, solana-batch, nft-gate-expiry). PayPal renewals are primarily webhook-driven (PAYMENT.SALE.COMPLETED); manual renew is a Subscriptions GET status sync. Stars renew currently returns a synthetic success + 30-day nextPaymentDue — production renew should follow Telegram payment events once the webhook is live.

    Anti-patterns

    • Do not call SubscriptionConductor.createSubscription from PayPal webhooks (re-opens checkout). Use recordPaidSubscription / updateSubscriptionStatus.
    • Do not store Orders orderReference as paypal_subscription_id.
    • Do not treat returnUrl alone as paid — wait for webhook events.
    • Do not treat Stars createInvoiceLink success as membership — wait for successful_payment on /api/telegram/stars-bot/webhook → activate pending ledger.
    • Do not omit metadata.telegramUserId on Stars create (provider returns an error).

    Payments Overview

    See-also: purpose map across the clone.

    Payment Gateway Integration

    Next-step: operator PSP checklist.

    Authentication

    Depends-on: Mini App bot token helper used by telegram_stars invoices.

    Ring File Cabinet

    Same-workflow: own File Cabinet (/file-cabinet) and gallery are member+; shared-with-me (/profile/shared) is subscriber+ for trustees.

    json
    
    {
      "payment": {
        "cardPaymentProcessor": "wayforpay",
        "gateways": {
          "paypal": { "enabled": true, "feePercent": 2.9, "feeFixedCents": 30, "currency": "USD" }
        }
      }
    }
    text
    
    Membership upgrade / PaymentModal / manage cancel
            ↓
    SubscriptionConductor (create | cancel | renew | recordPaidSubscription)
            ↓
    Providers: stripe | wayforpay | credit_balance | native_token | nft_gate | paypal | telegram_stars
            ↓
    subscription_ledger  (paypal_subscription_id = PayPal I-…; Stars stores invoice link pending)
            ↓
    Cron: expiry · credit-balance · payment · solana-batch · nft-gate
    Telegram Stars
    XTR invoice link via Bot API createInvoiceLink
    Telegram
    ✅ Create pending — webhook activation TBD
    2.9%
    $0.30
    USD
    Telegram StarsTelegram commission (operator-side)—XTR
    ringCreditSubscriptionProvider
    providers/ring-credit-subscription.ts
    native_tokennativeTokenSubscriptionProviderproviders/native-token-subscription.ts
    stripestripeSubscriptionProviderproviders/stripe-subscription.ts
    wayforpaywayforpaySubscriptionProviderproviders/wayforpay-subscription.ts
    nft_gatenftGateSubscriptionProviderproviders/nft-gate-subscription.ts
    paypalpaypalSubscriptionProviderproviders/paypal-subscription.ts
    telegram_starstelegramStarsSubscriptionProviderproviders/telegram-stars-subscription.ts

    Client helpers: createPayPalBillingSubscription, cancelPayPalBillingSubscription, getPayPalBillingSubscription in lib/payments/processors/paypal-client.ts.

    Stars env helper: getTelegramMiniAppBotToken() from lib/auth/telegram-miniapp-initdata.ts.

    subscription_ledger (verified fields)

    Schema: lib/payments/subscription/subscription-ledger-schema.ts.

    FieldNotes
    statuspending | active | expired | cancelled | suspended | grace_period
    methodcard | credit_balance | crypto | nft | paypal | stars
    providerincludes telegram_stars
    paypal_subscription_idPayPal Subscriptions I-… (not Orders orderReference)
    telegram_stars_payload / telegram_stars_invoice_linkPayload = ledger id; invoice URL from createInvoiceLink
    telegram_payment_charge_idSet on successful_payment (refundStarPayment)
    stripe_subscription_id / wayforpay_rec_token / solana_tx_signature / nft_mint_addressOther rails

    gatewayRefToField('paypal') → { paypal_subscription_id }. Cancel API + app/_actions/membership.ts pass that id into SubscriptionConductor.cancelSubscription.

    Conductor extras (PayPal / webhooks)

    OperationRole
    createSubscriptionHonors ledgerStatus: 'pending' — skips MEMBER upgrade until active
    recordPaidSubscriptionInsert active row without calling provider (Orders capture)
    findByPaypalSubscriptionIdWebhook lookup by I-…
    updateSubscriptionStatusCan set paypal_subscription_id, payments aggregates

    PayPal webhook branches

    dispatchPayPalWebhook (webhook-dispatcher.ts):

    EventHandler
    PAYMENT.CAPTURE.COMPLETEDOrders purpose handlers (store / membership capture / wallet / news)
    BILLING.SUBSCRIPTION.ACTIVATEDmembership-paypal-subscription.ts → activate ledger
    PAYMENT.SALE.COMPLETEDAdvance next_payment_due / payments_count
    BILLING.SUBSCRIPTION.CANCELLED / SUSPENDED / EXPIRED / PAYMENT.FAILEDTerminal / suspended status

    Canonical route: POST /api/payments/paypal/webhook.

    Membership & manage routes

    MethodPathRole
    POST/api/membership/payment/paypalCreate recurring (default) or renew status-sync
    POST/api/membership/subscription/cancelCancel; extracts paypal_subscription_id
    GET/api/membership/subscription/statuscan_cancel for active | pending
    Page/[locale]/(protected)/membership/manageSubscriptionManagement + role + NFT stakes + payment_transactions
    Route helperROUTES.MEMBERSHIP_MANAGE(locale)/membership/manage

    UI: components/membership/payment-modal.tsx PayPal tab when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true; components/membership/subscription-management.tsx on the manage page.

    Environment variables

    Secrets stay runtime (K8s Secret). Public flags also need Dockerfile / prod.js build-args for client bundles.

    Cron pipelines

    Unchanged five membership crons in lib/processes/registry.ts (expiry, credit-balance monthly, subscription-payment, solana-batch, nft-gate-expiry). PayPal renewals are primarily webhook-driven (PAYMENT.SALE.COMPLETED); manual renew is a Subscriptions GET status sync. Stars renew currently returns a synthetic success + 30-day nextPaymentDue — production renew should follow Telegram payment events once the webhook is live.

    Anti-patterns

    • Do not call SubscriptionConductor.createSubscription from PayPal webhooks (re-opens checkout). Use recordPaidSubscription / updateSubscriptionStatus.
    • Do not store Orders orderReference as paypal_subscription_id.
    • Do not treat returnUrl alone as paid — wait for webhook events.
    • Do not treat Stars createInvoiceLink success as membership — wait for successful_payment on /api/telegram/stars-bot/webhook → activate pending ledger.
    • Do not omit metadata.telegramUserId on Stars create (provider returns an error).

    Payments Overview

    See-also: purpose map across the clone.

    Payment Gateway Integration

    Next-step: operator PSP checklist.

    Authentication

    Depends-on: Mini App bot token helper used by telegram_stars invoices.

    Ring File Cabinet

    Same-workflow: own File Cabinet (/file-cabinet) and gallery are member+; shared-with-me (/profile/shared) is subscriber+ for trustees.

    json
    
    {
      "payment": {
        "cardPaymentProcessor": "wayforpay",
        "gateways": {
          "paypal": { "enabled": true, "feePercent": 2.9, "feeFixedCents": 30, "currency": "USD" }
        }
      }
    }
    text
    
    Membership upgrade / PaymentModal / manage cancel
            ↓
    SubscriptionConductor (create | cancel | renew | recordPaidSubscription)
            ↓
    Providers: stripe | wayforpay | credit_balance | native_token | nft_gate | paypal | telegram_stars
            ↓
    subscription_ledger  (paypal_subscription_id = PayPal I-…; Stars stores invoice link pending)
            ↓
    Cron: expiry · credit-balance · payment · solana-batch · nft-gate
    1. Docs
    2. /Features
    3. /SubscriptionConductor

    Updated Jul 22, 20267 min listen

    1. Docs
    2. /Features
    3. /SubscriptionConductor

    Updated Jul 22, 20267 min listen

    1. Docs
    2. /Features
    3. /SubscriptionConductor

    Updated Jul 22, 20267 min listen