Build Paystack Subscriptions in Ruby on Rails
To build Paystack subscriptions in Rails, create a plan via the API, initialize a transaction with the plan code, handle subscription webhooks in ActiveJob, track status in an ActiveRecord model, and use before_action filters to gate premium content.
Subscription Model
rails generate model Subscription user:references subscription_code:string:uniq plan_code:string email_token:string status:string next_payment_date:datetime
rails db:migrate
Subscribe Action
def subscribe
service = PaystackService.new
result = service.initialize_with_plan(
email: current_user.email,
plan_code: params[:plan_code],
callback_url: subscription_callback_url
)
if result['status']
redirect_to result['data']['authorization_url'], allow_other_host: true
else
flash[:error] = result['message']
redirect_to pricing_path
end
end
Webhook Handlers
def handle_subscription_create(data)
user = User.find_by(email: data['customer']['email'])
return unless user
Subscription.find_or_initialize_by(user: user).update!(
subscription_code: data['subscription_code'],
plan_code: data['plan']['plan_code'],
email_token: data['email_token'] || '',
status: 'active',
next_payment_date: data['next_payment_date']
)
end
def handle_invoice_failed(data)
sub_code = data.dig('subscription', 'subscription_code')
Subscription.where(subscription_code: sub_code).update_all(status: 'past_due') if sub_code
end
Access Control
# app/controllers/concerns/subscription_required.rb
module SubscriptionRequired
extend ActiveSupport::Concern
included do
before_action :require_active_subscription
end
private
def require_active_subscription
unless current_user&.subscription&.status == 'active'
redirect_to pricing_path, alert: 'An active subscription is required.'
end
end
end
# In premium controllers:
class PremiumController < ApplicationController
include SubscriptionRequired
end
Cancellation
def cancel
sub = current_user.subscription
return redirect_to dashboard_path, alert: 'No subscription' unless sub
service = PaystackService.new
result = service.disable_subscription(sub.subscription_code, sub.email_token)
if result['status']
sub.update!(status: 'cancelled')
redirect_to dashboard_path, notice: 'Subscription cancelled'
else
redirect_to dashboard_path, alert: 'Cancellation failed'
end
end
Key Takeaways
- ✓Paystack handles recurring billing. Create plans once and subscribe customers.
- ✓Use ActiveRecord for subscription tracking with status, subscription_code, and email_token.
- ✓Webhook events drive state changes. Handle subscription.create and invoice.payment_failed.
- ✓Use before_action to gate premium controllers behind subscription checks.
- ✓Store email_token for cancellation via the API.
- ✓ActiveJob handles async webhook processing with Sidekiq or another backend.
Frequently Asked Questions
- Can I use Stripe-like subscription gems with Paystack?
- No. Gems like Pay and Cashier are designed for Stripe. Build Paystack subscriptions directly using the API and ActiveRecord as shown in this guide.
- How do I handle plan upgrades?
- Cancel the current subscription and create a new one on the new plan. Handle prorating in your Rails application.
- What if a renewal payment fails?
- Paystack retries automatically. You receive invoice.payment_failed webhooks. Update the status and notify the customer.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon