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
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    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
    News Module
    Member Blogs
    Public Profile Pages
    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
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    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
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    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
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    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
    News Module
    Member Blogs
    Public Profile Pages
    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
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    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
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    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
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    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
    News Module
    Member Blogs
    Public Profile Pages
    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
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    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
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    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)
    1. Docs
    2. /Features
    3. /PaymentConductor

    Updated Jul 16, 20266 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Docs
    2. /Features
    3. /PaymentConductor

    Updated Jul 16, 20266 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Docs
    2. /Features
    3. /PaymentConductor

    Updated Jul 16, 20266 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    PaymentConductor

    PaymentConductor is Ring Platform's config-driven payment layer. One ledger (payment_transactions) and one webhook dispatcher serve store checkout, membership upgrades, news promotion, and wallet credit top-up.

    Browser UIs never talk to a PSP by brand for redirect — they follow Conductor CheckoutRedirect via lib/payments/checkout-redirect.ts (followCheckoutResult). Deep types: PaymentConductor architecture.

    Use Founder / Developer tabs in the docs sidebar to filter this page. Founders see configuration and business value; developers see modules, purposes, and webhook flows.

    Payment purposes

    PurposeHandlerTypical processorEntry
    store_orderhandlers/store-order.ts (+ Stripe / PayPal capture handlers)WayForPay, Stripe, credit, native token, or PayPalPOST /api/store/payments/{wayforpay|stripe|token|credit|paypal|card} → PaymentConductor.createCheckout
    membership_upgradehandlers/membership-upgrade.ts (+ Stripe / PayPal capture + Subscriptions lifecycle)WayForPay, Stripe, or PayPalCard / native via initiateMembershipPayment; PayPal via POST /api/membership/payment/paypal → SubscriptionConductor
    news_promotionhandlers/news-promotion.tsWayForPay or StripeNews promotion submit
    wallet_topuphandlers/wallet-topup.ts (+ Stripe / PayPal capture handlers)WayForPay, Stripe, or PayPalWalletConductor initiateTopUp → createCheckout
    native_token_onramphandlers/native-token-onramp.ts (+ Stripe: native-token-onramp-stripe.ts)WayForPay / Stripe (PayPal unsupported for onramp)WalletConductor initiateNativeOnramp (confidential+)

    wallet_topup credits the fiat credit ledger (1:1 USD points) via creditBalanceService.addFiatUsd — it does not buy on-chain RING. To spend native RING directly, use the native_token rail on store_order. To convert credit points → native RING, use the Token Desk.

    What founders get

    • One payment layer — store, membership, news, and wallet top-up share the same ledger and webhook path.
    • Config-driven gateway selection — choose the card processor in ring-config.json; override per purpose via env. No code changes for PSP swaps.
    • Internal credit rail — members can pay with in-app credit (zero gateway fee when enabled).
    • Native token rail — members can spend your clone's on-chain token at store checkout (opt-in via PAYMENT_STORE_ALLOW_TOKEN=true, zero gateway fee).
    • Admin Payments tab — platform admins see a user's membership_upgrade and wallet_topup rows from the ledger (GET /api/admin/users/[id]/payments).
    • Membership PaymentModal — native-token, card, and PayPal tabs are live when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true (plus PAYPAL_* + gateways.paypal.enabled). Recurring PayPal membership uses Subscriptions v1 — see SubscriptionConductor. Wallet Add Credit PayPal remains processor=paypal on wallet_topup.
    • Store PayPal — checkout method paypal → POST /api/store/payments/paypal (Orders v2) when the same public flag is on.
    • Browser handoff — UI follows redirect (navigate or form_post). WayForPay HPP must not be opened as a GET query URL.

    Gateway fee rates (ring-config.json)

    GatewayFee %

    Architecture

    Implementation root: lib/payments/conductor/, lib/payments/processors/, lib/payments/payment.config.ts.

    Key modules

    ModulePathRole
    Conductorlib/payments/conductor/payment-conductor.tscreateCheckout (+ normalizeCheckoutResult), webhook entry
    Types / redirectlib/payments/conductor/types.tsCheckoutRedirect, navigate | form_post
    Client handofflib/payments/checkout-redirect.tsfollowCheckoutResult (unbranded)
    Configlib/payments/payment.config.tsgetPaymentProvider, env overrides
    WayForPay

    Related

    Payments overview

    High-level payment integration — store, membership, news, wallet top-up.

    WayForPay integration

    Env SSOT, HMAC, regularApi password, orderReference prefixes.

    Architecture: PaymentConductor

    Types, ledger, dispatcher sequences, API routes.

    SubscriptionConductor

    PayPal Subscriptions v1, ledger, manage page, cancel/renew.

    PaymentConductor

    PaymentConductor is Ring Platform's config-driven payment layer. One ledger (payment_transactions) and one webhook dispatcher serve store checkout, membership upgrades, news promotion, and wallet credit top-up.

    Browser UIs never talk to a PSP by brand for redirect — they follow Conductor CheckoutRedirect via lib/payments/checkout-redirect.ts (followCheckoutResult). Deep types: PaymentConductor architecture.

    Use Founder / Developer tabs in the docs sidebar to filter this page. Founders see configuration and business value; developers see modules, purposes, and webhook flows.

    Payment purposes

    PurposeHandlerTypical processorEntry
    store_orderhandlers/store-order.ts (+ Stripe / PayPal capture handlers)WayForPay, Stripe, credit, native token, or PayPalPOST /api/store/payments/{wayforpay|stripe|token|credit|paypal|card} → PaymentConductor.createCheckout
    membership_upgradehandlers/membership-upgrade.ts (+ Stripe / PayPal capture + Subscriptions lifecycle)WayForPay, Stripe, or PayPalCard / native via initiateMembershipPayment; PayPal via POST /api/membership/payment/paypal → SubscriptionConductor
    news_promotionhandlers/news-promotion.tsWayForPay or StripeNews promotion submit
    wallet_topuphandlers/wallet-topup.ts (+ Stripe / PayPal capture handlers)WayForPay, Stripe, or PayPalWalletConductor initiateTopUp → createCheckout
    native_token_onramphandlers/native-token-onramp.ts (+ Stripe: native-token-onramp-stripe.ts)WayForPay / Stripe (PayPal unsupported for onramp)WalletConductor initiateNativeOnramp (confidential+)

    wallet_topup credits the fiat credit ledger (1:1 USD points) via creditBalanceService.addFiatUsd — it does not buy on-chain RING. To spend native RING directly, use the native_token rail on store_order. To convert credit points → native RING, use the Token Desk.

    What founders get

    • One payment layer — store, membership, news, and wallet top-up share the same ledger and webhook path.
    • Config-driven gateway selection — choose the card processor in ring-config.json; override per purpose via env. No code changes for PSP swaps.
    • Internal credit rail — members can pay with in-app credit (zero gateway fee when enabled).
    • Native token rail — members can spend your clone's on-chain token at store checkout (opt-in via PAYMENT_STORE_ALLOW_TOKEN=true, zero gateway fee).
    • Admin Payments tab — platform admins see a user's membership_upgrade and wallet_topup rows from the ledger (GET /api/admin/users/[id]/payments).
    • Membership PaymentModal — native-token, card, and PayPal tabs are live when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true (plus PAYPAL_* + gateways.paypal.enabled). Recurring PayPal membership uses Subscriptions v1 — see SubscriptionConductor. Wallet Add Credit PayPal remains processor=paypal on wallet_topup.
    • Store PayPal — checkout method paypal → POST /api/store/payments/paypal (Orders v2) when the same public flag is on.
    • Browser handoff — UI follows redirect (navigate or form_post). WayForPay HPP must not be opened as a GET query URL.

    Gateway fee rates (ring-config.json)

    GatewayFee %

    Architecture

    Implementation root: lib/payments/conductor/, lib/payments/processors/, lib/payments/payment.config.ts.

    Key modules

    ModulePathRole
    Conductorlib/payments/conductor/payment-conductor.tscreateCheckout (+ normalizeCheckoutResult), webhook entry
    Types / redirectlib/payments/conductor/types.tsCheckoutRedirect, navigate | form_post
    Client handofflib/payments/checkout-redirect.tsfollowCheckoutResult (unbranded)
    Configlib/payments/payment.config.tsgetPaymentProvider, env overrides
    WayForPay

    Related

    Payments overview

    High-level payment integration — store, membership, news, wallet top-up.

    WayForPay integration

    Env SSOT, HMAC, regularApi password, orderReference prefixes.

    Architecture: PaymentConductor

    Types, ledger, dispatcher sequences, API routes.

    SubscriptionConductor

    PayPal Subscriptions v1, ledger, manage page, cancel/renew.

    PaymentConductor

    PaymentConductor is Ring Platform's config-driven payment layer. One ledger (payment_transactions) and one webhook dispatcher serve store checkout, membership upgrades, news promotion, and wallet credit top-up.

    Browser UIs never talk to a PSP by brand for redirect — they follow Conductor CheckoutRedirect via lib/payments/checkout-redirect.ts (followCheckoutResult). Deep types: PaymentConductor architecture.

    Use Founder / Developer tabs in the docs sidebar to filter this page. Founders see configuration and business value; developers see modules, purposes, and webhook flows.

    Payment purposes

    PurposeHandlerTypical processorEntry
    store_orderhandlers/store-order.ts (+ Stripe / PayPal capture handlers)WayForPay, Stripe, credit, native token, or PayPalPOST /api/store/payments/{wayforpay|stripe|token|credit|paypal|card} → PaymentConductor.createCheckout
    membership_upgradehandlers/membership-upgrade.ts (+ Stripe / PayPal capture + Subscriptions lifecycle)WayForPay, Stripe, or PayPalCard / native via initiateMembershipPayment; PayPal via POST /api/membership/payment/paypal → SubscriptionConductor
    news_promotionhandlers/news-promotion.tsWayForPay or StripeNews promotion submit
    wallet_topuphandlers/wallet-topup.ts (+ Stripe / PayPal capture handlers)WayForPay, Stripe, or PayPalWalletConductor initiateTopUp → createCheckout
    native_token_onramphandlers/native-token-onramp.ts (+ Stripe: native-token-onramp-stripe.ts)WayForPay / Stripe (PayPal unsupported for onramp)WalletConductor initiateNativeOnramp (confidential+)

    wallet_topup credits the fiat credit ledger (1:1 USD points) via creditBalanceService.addFiatUsd — it does not buy on-chain RING. To spend native RING directly, use the native_token rail on store_order. To convert credit points → native RING, use the Token Desk.

    What founders get

    • One payment layer — store, membership, news, and wallet top-up share the same ledger and webhook path.
    • Config-driven gateway selection — choose the card processor in ring-config.json; override per purpose via env. No code changes for PSP swaps.
    • Internal credit rail — members can pay with in-app credit (zero gateway fee when enabled).
    • Native token rail — members can spend your clone's on-chain token at store checkout (opt-in via PAYMENT_STORE_ALLOW_TOKEN=true, zero gateway fee).
    • Admin Payments tab — platform admins see a user's membership_upgrade and wallet_topup rows from the ledger (GET /api/admin/users/[id]/payments).
    • Membership PaymentModal — native-token, card, and PayPal tabs are live when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true (plus PAYPAL_* + gateways.paypal.enabled). Recurring PayPal membership uses Subscriptions v1 — see SubscriptionConductor. Wallet Add Credit PayPal remains processor=paypal on wallet_topup.
    • Store PayPal — checkout method paypal → POST /api/store/payments/paypal (Orders v2) when the same public flag is on.
    • Browser handoff — UI follows redirect (navigate or form_post). WayForPay HPP must not be opened as a GET query URL.

    Gateway fee rates (ring-config.json)

    GatewayFee %

    Architecture

    Implementation root: lib/payments/conductor/, lib/payments/processors/, lib/payments/payment.config.ts.

    Key modules

    ModulePathRole
    Conductorlib/payments/conductor/payment-conductor.tscreateCheckout (+ normalizeCheckoutResult), webhook entry
    Types / redirectlib/payments/conductor/types.tsCheckoutRedirect, navigate | form_post
    Client handofflib/payments/checkout-redirect.tsfollowCheckoutResult (unbranded)
    Configlib/payments/payment.config.tsgetPaymentProvider, env overrides
    WayForPay

    Related

    Payments overview

    High-level payment integration — store, membership, news, wallet top-up.

    WayForPay integration

    Env SSOT, HMAC, regularApi password, orderReference prefixes.

    Architecture: PaymentConductor

    Types, ledger, dispatcher sequences, API routes.

    SubscriptionConductor

    PayPal Subscriptions v1, ledger, manage page, cancel/renew.

    Fixed Fee
    Currency
    Status
    WayForPay2.5%—UAHLive
    Stripe2.9%$0.30USDLive
    Credit Balance0%—USDLive
    RING Token0%—RINGLive
    PayPal2.9%$0.30USDLive (Orders + membership Subscriptions)

    Quick setup

    There is no WAYFORPAY_MERCHANT_ID. Use WAYFORPAY_MERCHANT_ACCOUNT. WAYFORPAY_MERCHANT_PASSWORD is required for recurring / regularApi subscription management.

    Per-purpose processor override

    Non-card rail gates

    Blank PAYMENT_*_PROCESSOR falls back to PAYMENT_DEFAULT_PROCESSOR (default wayforpay). Set it to stripe for USD-first clones.

    lib/payments/processors/wayforpay.processor.ts
    Per-purpose checkout; HPP via wayforpay-hpp.ts
    Stripelib/payments/processors/stripe.processor.tsStripe Checkout sessions (navigate)
    Internal creditlib/payments/processors/internal-credit.processor.tsCredit balance deduction
    Native tokenlib/payments/processors/native-token.processor.tsSynchronous on-chain RING → treasury
    PayPallib/payments/processors/paypal.processor.tsOrders v2 approve URL (navigate); store + wallet_topup + membership one-shot
    Webhook dispatcherlib/payments/conductor/webhook-dispatcher.tsOrders capture by purpose + PayPal Subscriptions lifecycle branch
    Purpose handlerslib/payments/conductor/handlers/*.tsFulfillment after paid (incl. membership-paypal-subscription.ts)

    PaymentProcessorId (conductor/types.ts): wayforpay | stripe | internal-credit | native-token | paypal.

    Rails

    RailDescriptionEnv gate
    merchant_redirectWayForPay / Stripe hosted checkoutDefault
    internal_creditWallet credit balance (fiat points)PAYMENT_STORE_ALLOW_CREDIT
    native_tokenRING token on-chain to treasuryPAYMENT_STORE_ALLOW_TOKEN

    Webhook endpoints

    EndpointProvider
    /api/payments/wayforpay/webhookWayForPay (HMAC)
    /api/payments/stripe/webhookStripe (STRIPE_WEBHOOK_SECRET)
    /api/payments/paypal/webhookPayPal (transmission signature + PAYPAL_WEBHOOK_ID)

    internal_credit and native_token settle synchronously inside createCheckout (no external webhook) — the processor debits credit / transfers on-chain and marks the ledger row paid before returning.

    Store checkout routes (verified)

    RouteRailNotes
    POST /api/store/payments/wayforpaymerchant_redirectcreateCheckout({ purpose: 'store_order' }); initiateStorePayment is an internal helper inside wayforpay.processor.ts, not a ledger bypass
    POST /api/store/payments/stripemerchant_redirectStripe Checkout session
    POST /api/store/payments/tokennative_tokenRequires PAYMENT_STORE_ALLOW_TOKEN=true; isRailEnabled('store_order', 'native_token') gate
    POST /api/store/payments/creditinternal_creditCredit balance deduction
    POST /api/store/payments/paypalmerchant_redirectOrders v2; requires PayPal credentials + gateways.paypal.enabled + public flag
    POST /api/store/payments/cardmerchant_redirectAlias of WayForPay card path

    Native token checkout (verified)

    createNativeTokenCheckout (native-token.processor.ts) resolves fiat → token via the oracle (nativeOut = amount / ringPerUsd, or explicit metadata.tokenAmount), checks balance, then transferNativeTokenForUser → treasury and markPaid. Fails closed with NATIVE_TOKEN_RAIL_DISABLED, TREASURY_NOT_CONFIGURED, or INSUFFICIENT_TOKEN_BALANCE.

    Wallet top-up (verified — credits, not tokens)

    initiateCreditTopupPayment in app/_actions/wallet.ts → purpose: 'wallet_topup' → createWalletTopupWayForPay (or Stripe) → webhook handlers/wallet-topup.ts / wallet-topup-stripe.ts credits fiat USD points via creditBalanceService.addFiatUsd (1:1). This is distinct from the native_token rail: card top-up never mints on-chain RING.

    Membership PayPal (verified — live)

    POST /api/membership/payment/paypal → SubscriptionConductor provider paypal:

    • Recurring (default auto_subscribe) — PayPal Subscriptions v1; ledger pending → BILLING.SUBSCRIPTION.ACTIVATED → active; cancel uses paypal_subscription_id.
    • One-shot — PaymentConductor Orders v2; capture webhook uses recordPaidSubscription (never re-enters provider create).

    PaymentModal PayPal tab: components/membership/payment-modal.tsx when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true. Member manage page: /membership/manage — see SubscriptionConductor.

    Wallet Add Credit PayPal still uses Orders on wallet_topup when credentials are configured.

    Database

    Apply data/migrations/004_payment_transactions.sql before production. Ledger rows use the DatabaseService result contract { success, data, error }.

    Wallet

    Credit top-up via WayForPay / Stripe / PayPal (wallet_topup).

    json
    
    {
      "payment": {
        "cardPaymentProcessor": "wayforpay",
        "supportedMethods": ["wayforpay", "credit_balance", "native_token"],
        "gateways": {
          "wayforpay": { "enabled": true, "feePercent": 2.5, "currency": "UAH" },
          "stripe": { "enabled": false, "feePercent": 2.9, "feeFixedCents": 30, "currency": "USD" }
        }
      }
    }
    bash
    
    PAYMENT_STORE_PROCESSOR=stripe
    PAYMENT_MEMBERSHIP_PROCESSOR=stripe
    PAYMENT_NEWS_PROCESSOR=wayforpay
    PAYMENT_WALLET_TOPUP_PROCESSOR=wayforpay
    bash
    
    PAYMENT_STORE_ALLOW_CREDIT=true    # spend credit points at store checkout
    PAYMENT_STORE_ALLOW_TOKEN=false    # spend native token at store checkout
    NEXT_PUBLIC_PAYMENT_STORE_ALLOW_TOKEN=false
    NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=false
    # PAYPAL_MODE=sandbox
    # PAYPAL_CLIENT_ID=
    # PAYPAL_CLIENT_SECRET=
    # PAYPAL_WEBHOOK_ID=
    CONFIDENTIAL_TOKEN_ONRAMP=false  # confidential+ BuyNativeViaCard (native_token_onramp)
    NEXT_PUBLIC_CONFIDENTIAL_TOKEN_ONRAMP=false
    # Token Desk (credit→RING) is subscriber+ — no confidential env gate
    Fixed Fee
    Currency
    Status
    WayForPay2.5%—UAHLive
    Stripe2.9%$0.30USDLive
    Credit Balance0%—USDLive
    RING Token0%—RINGLive
    PayPal2.9%$0.30USDLive (Orders + membership Subscriptions)

    Quick setup

    There is no WAYFORPAY_MERCHANT_ID. Use WAYFORPAY_MERCHANT_ACCOUNT. WAYFORPAY_MERCHANT_PASSWORD is required for recurring / regularApi subscription management.

    Per-purpose processor override

    Non-card rail gates

    Blank PAYMENT_*_PROCESSOR falls back to PAYMENT_DEFAULT_PROCESSOR (default wayforpay). Set it to stripe for USD-first clones.

    lib/payments/processors/wayforpay.processor.ts
    Per-purpose checkout; HPP via wayforpay-hpp.ts
    Stripelib/payments/processors/stripe.processor.tsStripe Checkout sessions (navigate)
    Internal creditlib/payments/processors/internal-credit.processor.tsCredit balance deduction
    Native tokenlib/payments/processors/native-token.processor.tsSynchronous on-chain RING → treasury
    PayPallib/payments/processors/paypal.processor.tsOrders v2 approve URL (navigate); store + wallet_topup + membership one-shot
    Webhook dispatcherlib/payments/conductor/webhook-dispatcher.tsOrders capture by purpose + PayPal Subscriptions lifecycle branch
    Purpose handlerslib/payments/conductor/handlers/*.tsFulfillment after paid (incl. membership-paypal-subscription.ts)

    PaymentProcessorId (conductor/types.ts): wayforpay | stripe | internal-credit | native-token | paypal.

    Rails

    RailDescriptionEnv gate
    merchant_redirectWayForPay / Stripe hosted checkoutDefault
    internal_creditWallet credit balance (fiat points)PAYMENT_STORE_ALLOW_CREDIT
    native_tokenRING token on-chain to treasuryPAYMENT_STORE_ALLOW_TOKEN

    Webhook endpoints

    EndpointProvider
    /api/payments/wayforpay/webhookWayForPay (HMAC)
    /api/payments/stripe/webhookStripe (STRIPE_WEBHOOK_SECRET)
    /api/payments/paypal/webhookPayPal (transmission signature + PAYPAL_WEBHOOK_ID)

    internal_credit and native_token settle synchronously inside createCheckout (no external webhook) — the processor debits credit / transfers on-chain and marks the ledger row paid before returning.

    Store checkout routes (verified)

    RouteRailNotes
    POST /api/store/payments/wayforpaymerchant_redirectcreateCheckout({ purpose: 'store_order' }); initiateStorePayment is an internal helper inside wayforpay.processor.ts, not a ledger bypass
    POST /api/store/payments/stripemerchant_redirectStripe Checkout session
    POST /api/store/payments/tokennative_tokenRequires PAYMENT_STORE_ALLOW_TOKEN=true; isRailEnabled('store_order', 'native_token') gate
    POST /api/store/payments/creditinternal_creditCredit balance deduction
    POST /api/store/payments/paypalmerchant_redirectOrders v2; requires PayPal credentials + gateways.paypal.enabled + public flag
    POST /api/store/payments/cardmerchant_redirectAlias of WayForPay card path

    Native token checkout (verified)

    createNativeTokenCheckout (native-token.processor.ts) resolves fiat → token via the oracle (nativeOut = amount / ringPerUsd, or explicit metadata.tokenAmount), checks balance, then transferNativeTokenForUser → treasury and markPaid. Fails closed with NATIVE_TOKEN_RAIL_DISABLED, TREASURY_NOT_CONFIGURED, or INSUFFICIENT_TOKEN_BALANCE.

    Wallet top-up (verified — credits, not tokens)

    initiateCreditTopupPayment in app/_actions/wallet.ts → purpose: 'wallet_topup' → createWalletTopupWayForPay (or Stripe) → webhook handlers/wallet-topup.ts / wallet-topup-stripe.ts credits fiat USD points via creditBalanceService.addFiatUsd (1:1). This is distinct from the native_token rail: card top-up never mints on-chain RING.

    Membership PayPal (verified — live)

    POST /api/membership/payment/paypal → SubscriptionConductor provider paypal:

    • Recurring (default auto_subscribe) — PayPal Subscriptions v1; ledger pending → BILLING.SUBSCRIPTION.ACTIVATED → active; cancel uses paypal_subscription_id.
    • One-shot — PaymentConductor Orders v2; capture webhook uses recordPaidSubscription (never re-enters provider create).

    PaymentModal PayPal tab: components/membership/payment-modal.tsx when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true. Member manage page: /membership/manage — see SubscriptionConductor.

    Wallet Add Credit PayPal still uses Orders on wallet_topup when credentials are configured.

    Database

    Apply data/migrations/004_payment_transactions.sql before production. Ledger rows use the DatabaseService result contract { success, data, error }.

    Wallet

    Credit top-up via WayForPay / Stripe / PayPal (wallet_topup).

    json
    
    {
      "payment": {
        "cardPaymentProcessor": "wayforpay",
        "supportedMethods": ["wayforpay", "credit_balance", "native_token"],
        "gateways": {
          "wayforpay": { "enabled": true, "feePercent": 2.5, "currency": "UAH" },
          "stripe": { "enabled": false, "feePercent": 2.9, "feeFixedCents": 30, "currency": "USD" }
        }
      }
    }
    bash
    
    PAYMENT_STORE_PROCESSOR=stripe
    PAYMENT_MEMBERSHIP_PROCESSOR=stripe
    PAYMENT_NEWS_PROCESSOR=wayforpay
    PAYMENT_WALLET_TOPUP_PROCESSOR=wayforpay
    bash
    
    PAYMENT_STORE_ALLOW_CREDIT=true    # spend credit points at store checkout
    PAYMENT_STORE_ALLOW_TOKEN=false    # spend native token at store checkout
    NEXT_PUBLIC_PAYMENT_STORE_ALLOW_TOKEN=false
    NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=false
    # PAYPAL_MODE=sandbox
    # PAYPAL_CLIENT_ID=
    # PAYPAL_CLIENT_SECRET=
    # PAYPAL_WEBHOOK_ID=
    CONFIDENTIAL_TOKEN_ONRAMP=false  # confidential+ BuyNativeViaCard (native_token_onramp)
    NEXT_PUBLIC_CONFIDENTIAL_TOKEN_ONRAMP=false
    # Token Desk (credit→RING) is subscriber+ — no confidential env gate
    Fixed Fee
    Currency
    Status
    WayForPay2.5%—UAHLive
    Stripe2.9%$0.30USDLive
    Credit Balance0%—USDLive
    RING Token0%—RINGLive
    PayPal2.9%$0.30USDLive (Orders + membership Subscriptions)

    Quick setup

    There is no WAYFORPAY_MERCHANT_ID. Use WAYFORPAY_MERCHANT_ACCOUNT. WAYFORPAY_MERCHANT_PASSWORD is required for recurring / regularApi subscription management.

    Per-purpose processor override

    Non-card rail gates

    Blank PAYMENT_*_PROCESSOR falls back to PAYMENT_DEFAULT_PROCESSOR (default wayforpay). Set it to stripe for USD-first clones.

    lib/payments/processors/wayforpay.processor.ts
    Per-purpose checkout; HPP via wayforpay-hpp.ts
    Stripelib/payments/processors/stripe.processor.tsStripe Checkout sessions (navigate)
    Internal creditlib/payments/processors/internal-credit.processor.tsCredit balance deduction
    Native tokenlib/payments/processors/native-token.processor.tsSynchronous on-chain RING → treasury
    PayPallib/payments/processors/paypal.processor.tsOrders v2 approve URL (navigate); store + wallet_topup + membership one-shot
    Webhook dispatcherlib/payments/conductor/webhook-dispatcher.tsOrders capture by purpose + PayPal Subscriptions lifecycle branch
    Purpose handlerslib/payments/conductor/handlers/*.tsFulfillment after paid (incl. membership-paypal-subscription.ts)

    PaymentProcessorId (conductor/types.ts): wayforpay | stripe | internal-credit | native-token | paypal.

    Rails

    RailDescriptionEnv gate
    merchant_redirectWayForPay / Stripe hosted checkoutDefault
    internal_creditWallet credit balance (fiat points)PAYMENT_STORE_ALLOW_CREDIT
    native_tokenRING token on-chain to treasuryPAYMENT_STORE_ALLOW_TOKEN

    Webhook endpoints

    EndpointProvider
    /api/payments/wayforpay/webhookWayForPay (HMAC)
    /api/payments/stripe/webhookStripe (STRIPE_WEBHOOK_SECRET)
    /api/payments/paypal/webhookPayPal (transmission signature + PAYPAL_WEBHOOK_ID)

    internal_credit and native_token settle synchronously inside createCheckout (no external webhook) — the processor debits credit / transfers on-chain and marks the ledger row paid before returning.

    Store checkout routes (verified)

    RouteRailNotes
    POST /api/store/payments/wayforpaymerchant_redirectcreateCheckout({ purpose: 'store_order' }); initiateStorePayment is an internal helper inside wayforpay.processor.ts, not a ledger bypass
    POST /api/store/payments/stripemerchant_redirectStripe Checkout session
    POST /api/store/payments/tokennative_tokenRequires PAYMENT_STORE_ALLOW_TOKEN=true; isRailEnabled('store_order', 'native_token') gate
    POST /api/store/payments/creditinternal_creditCredit balance deduction
    POST /api/store/payments/paypalmerchant_redirectOrders v2; requires PayPal credentials + gateways.paypal.enabled + public flag
    POST /api/store/payments/cardmerchant_redirectAlias of WayForPay card path

    Native token checkout (verified)

    createNativeTokenCheckout (native-token.processor.ts) resolves fiat → token via the oracle (nativeOut = amount / ringPerUsd, or explicit metadata.tokenAmount), checks balance, then transferNativeTokenForUser → treasury and markPaid. Fails closed with NATIVE_TOKEN_RAIL_DISABLED, TREASURY_NOT_CONFIGURED, or INSUFFICIENT_TOKEN_BALANCE.

    Wallet top-up (verified — credits, not tokens)

    initiateCreditTopupPayment in app/_actions/wallet.ts → purpose: 'wallet_topup' → createWalletTopupWayForPay (or Stripe) → webhook handlers/wallet-topup.ts / wallet-topup-stripe.ts credits fiat USD points via creditBalanceService.addFiatUsd (1:1). This is distinct from the native_token rail: card top-up never mints on-chain RING.

    Membership PayPal (verified — live)

    POST /api/membership/payment/paypal → SubscriptionConductor provider paypal:

    • Recurring (default auto_subscribe) — PayPal Subscriptions v1; ledger pending → BILLING.SUBSCRIPTION.ACTIVATED → active; cancel uses paypal_subscription_id.
    • One-shot — PaymentConductor Orders v2; capture webhook uses recordPaidSubscription (never re-enters provider create).

    PaymentModal PayPal tab: components/membership/payment-modal.tsx when NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=true. Member manage page: /membership/manage — see SubscriptionConductor.

    Wallet Add Credit PayPal still uses Orders on wallet_topup when credentials are configured.

    Database

    Apply data/migrations/004_payment_transactions.sql before production. Ledger rows use the DatabaseService result contract { success, data, error }.

    Wallet

    Credit top-up via WayForPay / Stripe / PayPal (wallet_topup).

    json
    
    {
      "payment": {
        "cardPaymentProcessor": "wayforpay",
        "supportedMethods": ["wayforpay", "credit_balance", "native_token"],
        "gateways": {
          "wayforpay": { "enabled": true, "feePercent": 2.5, "currency": "UAH" },
          "stripe": { "enabled": false, "feePercent": 2.9, "feeFixedCents": 30, "currency": "USD" }
        }
      }
    }
    bash
    
    PAYMENT_STORE_PROCESSOR=stripe
    PAYMENT_MEMBERSHIP_PROCESSOR=stripe
    PAYMENT_NEWS_PROCESSOR=wayforpay
    PAYMENT_WALLET_TOPUP_PROCESSOR=wayforpay
    bash
    
    PAYMENT_STORE_ALLOW_CREDIT=true    # spend credit points at store checkout
    PAYMENT_STORE_ALLOW_TOKEN=false    # spend native token at store checkout
    NEXT_PUBLIC_PAYMENT_STORE_ALLOW_TOKEN=false
    NEXT_PUBLIC_PAYMENT_STORE_ALLOW_PAYPAL=false
    # PAYPAL_MODE=sandbox
    # PAYPAL_CLIENT_ID=
    # PAYPAL_CLIENT_SECRET=
    # PAYPAL_WEBHOOK_ID=
    CONFIDENTIAL_TOKEN_ONRAMP=false  # confidential+ BuyNativeViaCard (native_token_onramp)
    NEXT_PUBLIC_CONFIDENTIAL_TOKEN_ONRAMP=false
    # Token Desk (credit→RING) is subscriber+ — no confidential env gate