Pay - Payments engine for Ruby on Rails

repository·main·Indexed 25 days ago

https://github.com/pay-rails/pay

A payments engine for Ruby on Rails (6.0+) that provides a unified interface for managing customers, charges, and subscriptions. It supports multiple payment processors including Stripe, Paddle, Braintree, and Lemon Squeezy, and includes support for marketplaces via Stripe Connect.

Tokens
33.4K
Snippets
101
Records
178
Agent score
31%

What's inside Pay

  1. Overview of Pay - Payments engine for Ruby on Rails

    main

    Pay is a payments engine designed for Ruby on Rails 6.0 and higher. It provides a standardized way to handle payments, subscriptions, and customers across multiple payment processors.

    Key features include:

    • Support for multiple payment processors (Stripe, Paddle, Braintree, Lemon Squeezy, and a Fake Processor for testing).
    • Standardized API for managing Customers, Payment Methods, Charges, and Subscriptions.
    • Support for marketplaces via Stripe Connect.

    If you are upgrading from a previous version of Pay, refer to the UPGRADE.md guide for migration instructions.

  2. Understand Paddle Classic limitations

    main

    When using the Paddle Classic processor, be aware of the following behavioral differences compared to other processors:

    • Customer Creation: You cannot create a Customer via the API.
    • Checkout Flow: Checkout is restricted to an iFrame or a hosted page.
    • Subscription Management: Once a subscription is cancelled, it cannot be resumed.
    • Payment Methods: Payment methods can only be updated while a subscription is currently active.
    • Customer Reuse: Paddle customers are not reused when a user re-subscribes.
  3. Core Usage Concepts in Pay

    main

    Pay organizes its functionality into several core domains. To use Pay effectively, you should understand how to interact with these models:

    • Customers: Managing the identity and billing information of your users.
    • Payment Methods: Handling the various ways customers pay (e.g., credit cards).
    • Charges: Processing one-time payments.
    • Subscriptions: Managing recurring billing cycles.
    • Routes & Webhooks: Handling incoming signals from payment providers to update local state.
    • Customizing Pay Models: Extending the default Pay models to fit your specific application needs.
  4. Use Hosted vs Overlay Checkout with Lemon.js

    main

    Lemon Squeezy supports two checkout modes via Lemon.js:

    1. Hosted Checkout: The default behavior. It opens the checkout in a new browser window/tab on the Lemon Squeezy website.
    2. Overlay Checkout: Opens the checkout as an overlay on your current page. To enable this mode, add the embed=1 parameter to your checkout URL.
  5. Configure Background Jobs for Pay

    main

    Pay relies on ActiveJob for two critical tasks:

    1. Webhook processing: Pay::Webhooks::ProcessJob
    2. Customer syncing: Pay::CustomerSyncJob

    If you use an asynchronous queue adapter (like Sidekiq or Solid Queue), ensure a worker process is running. Without a running worker, incoming webhooks may not be processed, and charges or subscriptions may not appear in your records.

  6. How Lemon Squeezy subscriptions are created

    main
    Lemon Squeezy subscriptions are not created directly via the API. Instead, they are created via Webhooks. When a subscription is successfully created in Lemon Squeezy, it sends a webhook to your application, and Pay will automatically create the subscription record for you.
  7. Access and manage Pay::Customer records

    main

    Once a processor is set, your model gains a payment_processor method which returns the active Pay::Customer record. This record tracks the active processor and the external processor_id from the API. It is also the central point of association for all Charges, Subscriptions, and Payment Methods.

    Because users can switch processors over time (e.g., moving from Braintree to Stripe), Pay uses a has_many :pay_customers association to maintain history. While multiple records may exist, only one is designated as the default and accessible via the payment_processor method.

    # Access the active processor
    @user.payment_processor
    #=> #<Pay::Customer processor: "stripe", processor_id: "cus_1000">
    
    # Access the history of all processors used by this user
    @user.pay_customers
    #=> [#<Pay::Customer>, #<Pay::Customer>]
  8. How Pay processes Stripe webhooks

    main

    Pay uses Stripe webhooks to synchronize local payment data with Stripe. Webhook processing is handled asynchronously via Pay::Webhooks::ProcessJob.

    Requirement: You must have an asynchronous queue adapter configured and a worker running to ensure events are applied to your local database. Refer to the Background jobs documentation for setup.

  9. Compare Stripe Connect charge types

    main

    Stripe Connect supports three main charge patterns depending on how funds should flow between your platform and the connected accounts:

    Charge TypeUse When
    Direct chargesCustomers directly transact with your user, often unaware of your platform's existence
    Destination chargesCustomers transact with your platform for products or services provided by your user
    Separate charges and transfersMultiple users are involved in the transaction; a specific user isn't known at the time of charge; or transfer can't be made at the time of charge
  10. How subscriptions are created with Paddle Billing

    main
    In Paddle Billing, subscriptions are not created directly via the API. Instead, they are created via Webhooks. When a subscription is successfully created in Paddle, Paddle sends a webhook to your application, and Pay will automatically create the subscription record in your Rails database.
  11. Handle Failed Stripe Payments

    main

    When a Stripe subscription fails a payment, it is set to past_due status. Depending on your Stripe account settings, it may eventually become canceled or unpaid.

    Pay treats unpaid subscriptions as inactive. It is recommended to mark subscriptions as unpaid to prevent users from accessing services without paying outstanding invoices, especially in metered billing scenarios. Users can then be prompted to pay their outstanding invoice to resume their subscription.

  12. Configure Overlay vs Inline Checkout modes

    main

    Paddle.js supports two primary display modes for the checkout interface:

    1. Overlay Checkout: The default mode. It opens the checkout in a modal window on top of your existing website content.
    2. Inline Checkout: Integrates the checkout directly into your page layout. To enable this, add data-display-mode='inline' to your element with the paddle_button class.