The paystack_sdk gem provides a simple and intuitive interface for interacting with Paystack's payment gateway API. It allows developers to easily integrate Paystack's payment processing features into their Ruby applications. With support for various endpoints, this SDK simplifies tasks such as initiating transactions, verifying payments, managing customers, and more.
- Installation
- Quick Start
- Usage
- Advanced Usage
- Development
- Contributing
- License
- Code of Conduct
Add this line to your application's Gemfile:
gem 'paystack_sdk'And then execute:
bundle installOr install it yourself as:
gem install paystack_sdkrequire 'paystack_sdk' # Initialize the client with your secret key paystack = PaystackSdk::Client.new(secret_key: "sk_test_xxx") # Initialize a transaction params = { email: "customer@email.com", amount: 2300, # Amount in the smallest currency unit (kobo for NGN) currency: "NGN" } begin response = paystack.transactions.initiate(params) if response.success? puts "Visit this URL to complete payment: #{response.authorization_url}" puts "Transaction reference: #{response.reference}" else puts "Error: #{response.error_message}" end rescue PaystackSdk::MissingParamError => e puts "Missing required data: #{e.message}" rescue PaystackSdk::InvalidFormatError => e puts "Invalid data format: #{e.message}" end # Create a customer customer_params = { email: "customer@email.com", first_name: "John", last_name: "Doe" } begin customer_response = paystack.customers.create(customer_params) if customer_response.success? puts "Customer created: #{customer_response.data.customer_code}" else puts "Error: #{customer_response.error_message}" end rescue PaystackSdk::ValidationError => e puts "Validation error: #{e.message}" endThe SDK handles API responses that use string keys (as returned by Paystack) and provides seamless access through both string and symbol notation. All response data maintains the original string key format from the API while offering convenient dot notation access.
The SDK uses a two-tier error handling approach:
- Validation Errors (thrown as exceptions) - for missing or invalid input data
- API Response Errors (returned as unsuccessful Response objects) - for API-level issues
The SDK validates your parameters before making API calls and throws exceptions immediately for data issues:
begin # This will throw an exception before making any API call response = paystack.transactions.initiate({amount: 1000}) # Missing required email rescue PaystackSdk::MissingParamError => e puts "Fix your data: #{e.message}" endAll successful API calls return a Response object that you can check for success:
response = paystack.transactions.initiate(valid_params) if response.success? puts "Transaction created: #{response.authorization_url}" else puts "Transaction failed: #{response.error_message}" # Get detailed error information error_details = response.error_details puts "Status code: #{error_details[:status_code]}" puts "Error message: #{error_details[:message]}" endNote: The SDK raises exceptions for:
- Validation errors - when required parameters are missing or have invalid formats
- Authentication errors (401) - usually configuration issues
- Rate limiting (429) - requires retry logic
- Server errors (5xx) - Paystack infrastructure issues
- Network errors - connection failures
All other API errors (resource not found, business logic errors, etc.) are returned as unsuccessful Response objects.
# Initialize with your Paystack secret key paystack = PaystackSdk::Client.new(secret_key: "sk_test_xxx") # Or set the PAYSTACK_SECRET_KEY in your environment and do this instead paystack = PaystackSdk::Client.new # => This will dynamically fetch the secret key # You can access the connection directly if needed connection = paystack.connectionThe SDK provides comprehensive support for Paystack's Transaction API.
# Prepare transaction parameters params = { email: "customer@example.com", amount: 10000, # Amount in the smallest currency unit (e.g., kobo, pesewas, cents) currency: "GHS", callback_url: "https://example.com/callback" } # Initialize the transaction response = paystack.transactions.initiate(params) if response.success? puts "Transaction initialized successfully!" puts "Authorization URL: #{response.authorization_url}" puts "Access Code: #{response.access_code}" puts "Reference: #{response.reference}" else puts "Error: #{response.error_message}" end# Verify using transaction reference response = paystack.transactions.verify(reference: "transaction_reference") if response.success? transaction = response.data puts "Transaction verified successfully!" puts "Status: #{transaction.status}" puts "Amount: #{transaction.amount}" puts "Currency: #{transaction.currency}" puts "Customer Email: #{transaction.customer.email}" # Check specific transaction status case transaction.status when "success" puts "Payment successful!" when "pending" puts "Payment is pending." else puts "Current status: #{transaction.status}" end else puts "Verification failed: #{response.error_message}" end# Get all transactions (default pagination: 50 per page) response = paystack.transactions.list # With custom pagination response = paystack.transactions.list(per_page: 20, page: 2) # With additional filters response = paystack.transactions.list( per_page: 10, page: 1, from: "2025-01-01", to: "2025-04-30", status: "success" ) if response.success? puts "Total transactions: #{response.count}" # response.size is another way response.data.each do |transaction| puts "ID: #{transaction.id}" puts "Reference: #{transaction.reference}" puts "Amount: #{transaction.amount}" puts "----------------" end # Get the first transaction first_transaction = response.data.first puts "First transaction reference: #{first_transaction.reference}" # Get the last transaction last_transaction = response.data.last puts "Last transaction amount: #{last_transaction.amount}" else puts "Error: #{response.error_message}" end# Fetch a specific transaction by ID transaction_id = "12345" response = paystack.transactions.fetch(transaction_id) if response.success? transaction = response.data puts "Transaction details:" puts "ID: #{transaction.id}" puts "Reference: #{transaction.reference}" puts "Amount: #{transaction.amount}" puts "Status: #{transaction.status}" # Access customer information puts "Customer Email: #{transaction.customer.email}" puts "Customer Name: #{transaction.customer.name}" else puts "Error: #{response.error_message}" end# Get transaction volume and success metrics response = paystack.transactions.totals if response.success? puts "Total Transactions: #{response.data.total_transactions}" puts "Total Volume: #{response.data.total_volume}" puts "Pending Transfers: #{response.data.pending_transfers}" else puts "Error: #{response.error_message}" endThe SDK provides comprehensive support for Paystack's Customer API, allowing you to manage customer records and their associated data.
# Prepare customer parameters params = { email: "customer@example.com", first_name: "John", last_name: "Doe", phone: "+2348123456789" } # Create the customer response = paystack.customers.create(params) if response.success? puts "Customer created successfully!" puts "Customer Code: #{response.data.customer_code}" puts "Email: #{response.data.email}" puts "Name: #{response.data.first_name} #{response.data.last_name}" else puts "Error: #{response.error_message}" end# Get all customers (default pagination: 50 per page) response = paystack.customers.list # With custom pagination response = paystack.customers.list(per_page: 20, page: 2) # With date filters response = paystack.customers.list( per_page: 10, page: 1, from: "2025-01-01", to: "2025-06-10" ) if response.success? puts "Total customers: #{response.data.size}" response.data.each do |customer| puts "Code: #{customer.customer_code}" puts "Email: #{customer.email}" puts "Name: #{customer.first_name} #{customer.last_name}" puts "----------------" end else puts "Error: #{response.error_message}" end# Fetch by customer code customer_code = "CUS_xr58yrr2ujlft9k" response = paystack.customers.fetch(customer_code) # Or fetch by email response = paystack.customers.fetch("customer@example.com") if response.success? customer = response.data puts "Customer details:" puts "Code: #{customer.customer_code}" puts "Email: #{customer.email}" puts "Name: #{customer.first_name} #{customer.last_name}" puts "Phone: #{customer.phone}" else puts "Error: #{response.error_message}" endcustomer_code = "CUS_xr58yrr2ujlft9k" update_params = { first_name: "Jane", last_name: "Smith", phone: "+2348987654321" } response = paystack.customers.update(customer_code, update_params) if response.success? puts "Customer updated successfully!" puts "Updated Name: #{response.data.first_name} #{response.data.last_name}" else puts "Error: #{response.error_message}" endcustomer_code = "CUS_xr58yrr2ujlft9k" validation_params = { country: "NG", type: "bank_account", account_number: "0123456789", bvn: "20012345677", bank_code: "007", first_name: "John", last_name: "Doe" } response = paystack.customers.validate(customer_code, validation_params) if response.success? puts "Customer validation initiated: #{response.message}" else puts "Error: #{response.error_message}" endparams = { customer: "CUS_xr58yrr2ujlft9k", risk_action: "allow" # Options: "default", "allow", "deny" } response = paystack.customers.set_risk_action(params) if response.success? puts "Risk action set successfully!" puts "Customer: #{response.data.customer_code}" puts "Risk Action: #{response.data.risk_action}" else puts "Error: #{response.error_message}" endparams = { authorization_code: "AUTH_72btv547" } response = paystack.customers.deactivate_authorization(params) if response.success? puts "Authorization deactivated: #{response.message}" else puts "Error: #{response.error_message}" endAll API requests return a PaystackSdk::Response object that provides easy access to the response data.
response = paystack.transactions.initiate(params) # Check if the request was successful response.success? # => true or false # Access response message response.api_message # => "Authorization URL created" # Access data using dot notation response.data.authorization_url response.data.access_code # Access data directly from the response response.authorization_url # Same as response.data.authorization_url # Access nested data response.data.customer.email # For arrays, use array methods response.data.first # First item in an array response.data.last # Last item in an array response.data.size # Size of the array # Iterate through array data response.data.each do |item| puts item.id endSometimes you may need access to the original API response:
response = paystack.transactions.list # Access the original response body original = response.original_response # Access metadata from the original response total_count = original.dig("meta", "total") current_page = original.dig("meta", "page")The SDK provides specific error classes for different types of failures, making it easier to handle errors appropriately:
begin response = paystack.transactions.verify(reference: "invalid_reference") rescue PaystackSdk::AuthenticationError => e puts "Authentication failed: #{e.message}" rescue PaystackSdk::RateLimitError => e puts "Rate limit exceeded. Retry after: #{e.retry_after} seconds" rescue PaystackSdk::ServerError => e puts "Server error: #{e.message}" rescue PaystackSdk::APIError => e puts "API error: #{e.message}" rescue PaystackSdk::Error => e puts "General error: #{e.message}" end # Alternatively, check response success without exceptions response = paystack.transactions.verify(reference: "invalid_reference") unless response.success? puts "Error: #{response.error_message}" # Take action based on the error if response.error_message.include?("not found") puts "The transaction reference was not found." elsif response.error_message.include?("Invalid key") puts "API authentication failed. Check your API key." end endThe SDK includes several specific error classes:
-
PaystackSdk::ValidationError- Base class for all validation errorsPaystackSdk::MissingParamError- Raised when required parameters are missingPaystackSdk::InvalidFormatError- Raised when parameters have invalid format (e.g., invalid email)PaystackSdk::InvalidValueError- Raised when parameters have invalid values (e.g., not in allowed list)
-
PaystackSdk::APIError- Base class for API-related errorsPaystackSdk::AuthenticationError- Authentication failuresPaystackSdk::ResourceNotFoundError- Resource not found (404 errors)PaystackSdk::RateLimitError- Rate limiting encounteredPaystackSdk::ServerError- Server errors (5xx responses)
The SDK validates your input data before making API calls and will throw exceptions immediately if required data is missing or incorrectly formatted:
# Missing required parameter begin paystack.transactions.initiate({amount: 1000}) # Missing email rescue PaystackSdk::MissingParamError => e puts e.message # => "Missing required parameter: email" end # Invalid format begin paystack.transactions.initiate({ email: "invalid-email", # Not a valid email format amount: 1000 }) rescue PaystackSdk::InvalidFormatError => e puts e.message # => "Invalid format for Email. Expected format: valid email address" end # Invalid value begin paystack.customers.set_risk_action({ customer: "CUS_123", risk_action: "invalid_action" # Not in allowed values }) rescue PaystackSdk::InvalidValueError => e puts e.message # => "Invalid value for risk_action: must be one of [default, allow, deny]" endThese validation errors are thrown immediately and prevent the API call from being made, helping you catch data issues early in development.
You can use environment variables to configure the SDK:
# Set the PAYSTACK_SECRET_KEY environment variable ENV["PAYSTACK_SECRET_KEY"] = "sk_test_xxx" # Then initialize resources without specifying the key transactions = PaystackSdk::Resources::Transactions.new customers = PaystackSdk::Resources::Customers.newFor more advanced usage, you can instantiate resource classes directly:
# With a secret key transactions = PaystackSdk::Resources::Transactions.new(secret_key: "sk_test_xxx") customers = PaystackSdk::Resources::Customers.new(secret_key: "sk_test_xxx") # With an existing Faraday connection connection = Faraday.new(url: "https://api.paystack.co") do |conn| # Configure the connection end # The secret key can be omitted if set in an environment transactions = PaystackSdk::Resources::Transactions.new(connection, secret_key:) customers = PaystackSdk::Resources::Customers.new(connection, secret_key:)For more detailed documentation on specific resources, please refer to the following guides:
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
The SDK includes comprehensive test coverage with consistent response format handling. All test specifications use string keys with hashrocket notation (=>) to match the actual format returned by the Paystack API:
# Example test response format .and_return(Faraday::Response.new(status: 200, body: { "status" => true, "message" => "Transaction initialized", "data" => { "authorization_url" => "https://checkout.paystack.com/abc123", "access_code" => "access_code_123", "reference" => "ref_123" } }))Tests also validate specific error types to ensure proper exception handling:
# Testing specific error types expect { customers.set_risk_action(invalid_params) } .to raise_error(PaystackSdk::InvalidValueError, /risk_action/i)To install this gem onto your local machine, run:
bundle exec rake installTo release a new version, update the version number in version.rb, and then run:
bundle exec rake releaseThis will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/nanafox/paystack_sdk. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the PaystackSdk project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the code of conduct.