// the find
pay-rails/pay
Payments for Ruby on Rails apps
Pay is a Rails engine that bolts payments onto any Rails app by adding a `pay_customer` concern to your models. It abstracts over Stripe, Paddle (both Classic and Billing), Braintree, and Lemon Squeezy behind a common interface for charges, subscriptions, and payment methods. It's for Rails indie hackers and small SaaS teams who want billing working in an afternoon without writing webhook handlers from scratch.
The webhook handling is genuinely well thought-out — each processor has its own handler classes per event type, so you're not debugging a 400-line switch statement. The Fake Processor is a real feature, not an afterthought: you can run trials, free plans, and tests without touching Stripe's test mode. The gem tests against Rails 7.0 through main via Appraisals, so you're unlikely to be caught out by a Rails upgrade. The STI-based model structure (Pay::Stripe::Subscription, Pay::Braintree::Subscription, etc.) means processor-specific logic stays isolated instead of bleeding into shared models.
The 'we standardize payment processors' promise breaks down fast with anything non-trivial — metered billing, usage-based pricing, and multi-currency edge cases all behave differently per processor and the abstraction leaks. Switching processors in production is a data migration problem the gem doesn't help you with at all. Lemon Squeezy support is visibly thinner than Stripe — fewer webhook handlers, less documentation, and the 'community' Asaas processor is an external repo not under the org's control. The polymorphic `pay_customers` table with STI means your database queries get a `WHERE processor = ?` clause everywhere, which is fine at small scale but becomes a problem if you later need to query across processors.