Accept Payments with Paystack in Ruby on Rails
To accept Paystack payments in Rails, create a PaymentsController that uses Net::HTTP or the httparty gem to call the Paystack API. Initialize a transaction, redirect the customer to Paystack checkout, and verify the payment in a callback action.
Setup
Add your Paystack key to Rails credentials or .env:
# .env
PAYSTACK_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxx
Add the dotenv gem if using .env:
# Gemfile
gem 'dotenv-rails', groups: [:development, :test]
Paystack Service
# app/services/paystack_service.rb
require 'net/http'
require 'json'
class PaystackService
BASE_URL = 'https://api.paystack.co'
def initialize
@secret_key = ENV['PAYSTACK_SECRET_KEY']
end
def initialize_transaction(email:, amount_kobo:, reference:, callback_url:)
uri = URI(BASE_URL + '/transaction/initialize')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer ' + @secret_key
request['Content-Type'] = 'application/json'
request.body = {
email: email,
amount: amount_kobo,
reference: reference,
callback_url: callback_url
}.to_json
response = http.request(request)
JSON.parse(response.body)
end
def verify_transaction(reference)
uri = URI(BASE_URL + '/transaction/verify/' + reference)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['Authorization'] = 'Bearer ' + @secret_key
response = http.request(request)
JSON.parse(response.body)
end
end
Payments Controller
# app/controllers/payments_controller.rb
class PaymentsController < ApplicationController
def create
email = params[:email]
amount = params[:amount].to_f
reference = "order_#{SecureRandom.hex(6)}"
order = Order.create!(
email: email,
amount_kobo: (amount * 100).to_i,
reference: reference
)
service = PaystackService.new
result = service.initialize_transaction(
email: email,
amount_kobo: order.amount_kobo,
reference: reference,
callback_url: payment_callback_url
)
if result['status']
redirect_to result['data']['authorization_url'], allow_other_host: true
else
flash[:error] = result['message'] || 'Failed'
redirect_to checkout_path
end
end
def callback
reference = params[:reference] || params[:trxref]
unless reference
flash[:error] = 'Missing reference'
return redirect_to root_path
end
service = PaystackService.new
result = service.verify_transaction(reference)
if result['status'] && result['data']['status'] == 'success'
order = Order.find_by(reference: reference)
if order && result['data']['amount'] == order.amount_kobo
Order.where(reference: reference, paid: false).update_all(paid: true, paid_at: Time.current)
render :success
else
render :failed
end
else
render :failed
end
end
end
Routes
# config/routes.rb
Rails.application.routes.draw do
post '/pay', to: 'payments#create'
get '/payment/callback', to: 'payments#callback', as: :payment_callback
end
Order Model
rails generate model Order reference:string:uniq email:string amount_kobo:integer currency:string paid:boolean paid_at:datetime
rails db:migrate
Production Checklist
- Use Rails credentials. Store keys with
rails credentials:editinstead of .env in production. - Set up webhooks. See Handle Paystack Webhooks in Rails.
- HTTPS. Required for callback and webhook URLs.
- Validate amounts. Check against your database, not params.
Key Takeaways
- ✓Use Net::HTTP (stdlib) or the httparty gem for Paystack API calls. No Paystack gem is required.
- ✓Store your Paystack secret key in Rails credentials or environment variables.
- ✓Amounts are in kobo (NGN), pesewas (GHS), or cents. Multiply by 100 before sending.
- ✓Skip CSRF verification for webhook actions with skip_forgery_protection.
- ✓Always verify transactions server-side after the redirect callback.
- ✓Rails conventions (MVC, ActiveRecord) map cleanly to the Paystack payment flow.
Frequently Asked Questions
- Do I need a Paystack Ruby gem?
- No. Net::HTTP in the Ruby standard library handles all the API calls. You can also use the httparty or faraday gems for a cleaner API, but they are not required.
- Can I use Rails API mode with Paystack?
- Yes. In API mode, return JSON responses instead of rendering views. The Paystack API calls are identical.
- How do I handle CSRF for webhooks?
- Add skip_forgery_protection to your webhook controller action. Paystack requests do not include Rails CSRF tokens.
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