Learn how to integrate Stripe API with Ruby: setup, install the Stripe gem, handle payments, subscriptions, webhooks, error handling, and go live securely.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
How to use Stripe API with Ruby
Step 1: Set Up Your Ruby Environment
First, ensure you have Ruby installed on your system. You can check your Ruby version with:
ruby -v
If Ruby is not installed, download and install it from the official Ruby website or use a version manager like RVM or rbenv.
Step 2: Install the Stripe Ruby Gem
Add the Stripe gem to your project by adding it to your Gemfile:
gem 'stripe', '~> 8.0'
Then run:
bundle install
Alternatively, you can install the gem directly:
gem install stripe
Step 3: Sign Up for a Stripe Account and Get API Keys
Step 4: Configure the Stripe Ruby Library
Initialize the Stripe client with your secret API key:
require 'stripe'
Stripe.api_key = 'sk_test\_YourSecretKeyHere'
# Optional configuration
Stripe.api\_version = '2023-08-16' # Specify API version
For Rails applications, create an initializer file at config/initializers/stripe.rb
:
# config/initializers/stripe.rb
Rails.configuration.stripe = {
publishable_key: ENV['STRIPE_PUBLISHABLE\_KEY'],
secret_key: ENV['STRIPE_SECRET\_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
Step 5: Create a Customer
Create a Stripe customer object that you can associate with payments:
customer = Stripe::Customer.create({
email: '[email protected]',
name: 'John Doe',
description: 'Customer created through Ruby API',
metadata: {
order\_id: '6735'
}
})
puts "Created customer with ID: #{customer.id}"
Step 6: Add a Payment Method to a Customer
First, create a payment method token on the client-side using Stripe.js. Then, attach it to your customer:
# Assuming you have a payment method token from the client-side
payment_method_id = 'pm\_123456789'
payment\_method = Stripe::PaymentMethod.attach(
payment_method_id,
{ customer: customer.id }
)
# Set as the default payment method
Stripe::Customer.update(
customer.id,
{ invoice_settings: { default_payment_method: payment_method.id } }
)
Step 7: Create a One-time Charge
Process a one-time payment using the Payment Intents API:
payment\_intent = Stripe::PaymentIntent.create({
amount: 2000, # Amount in cents
currency: 'usd',
customer: customer.id,
payment_method: payment_method.id,
description: 'Payment for order #6735',
confirm: true, # Confirm the payment immediately
metadata: {
order\_id: '6735'
}
})
puts "Payment status: #{payment\_intent.status}"
Step 8: Create a Subscription
Create a subscription for recurring payments:
# First, let's create a product if it doesn't exist
product = Stripe::Product.create({
name: 'Premium Plan',
description: 'Monthly subscription for premium features'
})
# Create a price for the product
price = Stripe::Price.create({
product: product.id,
unit\_amount: 1999, # $19.99 in cents
currency: 'usd',
recurring: {
interval: 'month'
}
})
# Create the subscription
subscription = Stripe::Subscription.create({
customer: customer.id,
items: [
{ price: price.id }
],
payment_behavior: 'default_incomplete', # Create an invoice and attempt to pay
expand: ['latest_invoice.payment_intent'] # Get the payment intent details
})
puts "Subscription status: #{subscription.status}"
puts "Payment intent client secret: #{subscription.latest_invoice.payment_intent.client\_secret}"
Step 9: Handle Webhooks
Set up a webhook endpoint to receive and process Stripe events:
require 'sinatra'
require 'stripe'
require 'json'
# For Rails, you would create a controller instead
post '/stripe/webhook' do
payload = request.body.read
sig_header = request.env['HTTP_STRIPE\_SIGNATURE']
endpoint_secret = 'whsec_your_webhook_signing\_secret'
begin
event = Stripe::Webhook.construct\_event(
payload, sig_header, endpoint_secret
)
rescue JSON::ParserError => e
# Invalid payload
status 400
return
rescue Stripe::SignatureVerificationError => e
# Invalid signature
status 400
return
end
# Handle the event
case event.type
when 'payment\_intent.succeeded'
payment\_intent = event.data.object
puts "PaymentIntent was successful: #{payment\_intent.id}"
# Update your database, fulfill an order, etc.
when 'payment_intent.payment_failed'
payment\_intent = event.data.object
puts "Payment failed: #{payment_intent.id}, #{payment_intent.last_payment_error&.message}"
# Notify the customer that payment failed
when 'invoice.payment\_succeeded'
invoice = event.data.object
puts "Invoice paid: #{invoice.id}"
# Provision access to your service
when 'customer.subscription.created'
subscription = event.data.object
puts "Subscription created: #{subscription.id}"
# Set up the customer's subscription
when 'customer.subscription.deleted'
subscription = event.data.object
puts "Subscription canceled: #{subscription.id}"
# Remove the customer's access
else
puts "Unhandled event type: #{event.type}"
end
status 200
end
Step 10: List and Retrieve Objects
Query and retrieve objects from Stripe:
# List customers
customers = Stripe::Customer.list({
limit: 10,
email: '[email protected]'
})
customers.each do |customer|
puts "Customer: #{customer.id}, #{customer.email}"
end
# Retrieve a specific customer
begin
customer = Stripe::Customer.retrieve('cus\_123456789')
puts "Found customer: #{customer.name}"
rescue Stripe::InvalidRequestError => e
puts "Error retrieving customer: #{e.message}"
end
# List recent payments
payments = Stripe::PaymentIntent.list({
limit: 10
})
payments.each do |payment|
puts "Payment: #{payment.id}, Amount: #{payment.amount}, Status: #{payment.status}"
end
Step 11: Update and Delete Objects
Update and delete Stripe objects:
# Update a customer
Stripe::Customer.update(
'cus\_123456789',
{
email: '[email protected]',
metadata: { updated_at: Time.now.to_i }
}
)
# Cancel a subscription
Stripe::Subscription.update(
'sub\_123456789',
{ cancel_at_period\_end: true }
)
# Delete a customer (only works if there are no charges or other objects linked to this customer)
Stripe::Customer.delete('cus\_123456789')
Step 12: Error Handling and Best Practices
Implement proper error handling for your Stripe integration:
begin
# Attempt to create a charge
charge = Stripe::PaymentIntent.create({
amount: 2000,
currency: 'usd',
customer: 'cus\_nonexistent',
payment_method: 'pm_nonexistent',
confirm: true
})
rescue Stripe::CardError => e
# Since it's a decline, Stripe::CardError will be caught
puts "Card error: #{e.error.message}"
puts "Decline code: #{e.error.decline_code}" if e.error.decline_code
rescue Stripe::RateLimitError => e
# Too many requests made to the API too quickly
puts "Rate limit error: #{e.message}"
rescue Stripe::InvalidRequestError => e
# Invalid parameters were supplied to Stripe's API
puts "Invalid request error: #{e.message}"
rescue Stripe::AuthenticationError => e
# Authentication with Stripe's API failed
puts "Authentication error: #{e.message}"
rescue Stripe::APIConnectionError => e
# Network communication with Stripe failed
puts "API connection error: #{e.message}"
rescue Stripe::StripeError => e
# Generic Stripe error
puts "Stripe error: #{e.message}"
rescue => e
# Something else happened, completely unrelated to Stripe
puts "Other error: #{e.message}"
end
Step 13: Creating a Simple Checkout Flow
Implement a simple checkout flow using Stripe Checkout:
# Server-side code to create a checkout session
session = Stripe::Checkout::Session.create({
payment_method_types: ['card'],
line\_items: [{
price\_data: {
currency: 'usd',
product\_data: {
name: 'T-shirt',
description: 'Comfortable cotton t-shirt',
images: ['https://example.com/t-shirt.png'],
},
unit\_amount: 2000,
},
quantity: 1,
}],
mode: 'payment',
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel\_url: 'https://example.com/cancel',
})
# Redirect to the URL returned in the response
puts "Redirect to: #{session.url}"
Step 14: Working with PaymentIntents for Dynamic Payments
Implement a more flexible payment flow using Payment Intents:
# Create a PaymentIntent without confirming it
payment\_intent = Stripe::PaymentIntent.create({
amount: 1000,
currency: 'usd',
payment_method_types: ['card'],
description: 'Software development services',
metadata: {
order\_id: '6735'
}
})
# The client\_secret is used on the client side to confirm the payment
client_secret = payment_intent.client\_secret
puts "Client Secret: #{client\_secret}"
# Later, you can retrieve and confirm the payment intent
retrieved_intent = Stripe::PaymentIntent.retrieve(payment_intent.id)
confirmed\_intent = Stripe::PaymentIntent.confirm(
payment\_intent.id,
{
payment_method: 'pm_card\_visa', # Provided by the client
return\_url: 'https://example.com/return'
}
)
puts "Payment status: #{confirmed\_intent.status}"
Step 15: Testing
Test your Stripe integration using test cards and webhooks:
# Test card numbers
# 4242 4242 4242 4242 - Successful payment
# 4000 0000 0000 0002 - Card declined (generic)
# 4000 0000 0000 9995 - Insufficient funds
# Create a test payment
payment\_intent = Stripe::PaymentIntent.create({
amount: 2000,
currency: 'usd',
payment_method_data: {
type: 'card',
card: {
number: '4242424242424242',
exp\_month: 12,
exp\_year: 2025,
cvc: '123'
}
},
confirm: true
})
puts "Test payment status: #{payment\_intent.status}"
# To test webhooks locally, use the Stripe CLI:
# stripe listen --forward-to localhost:4567/stripe/webhook
Step 16: Going Live
Prepare your integration for production:
# Switch from test to live keys
if Rails.env.production?
Stripe.api_key = ENV['STRIPE_LIVE_SECRET_KEY']
else
Stripe.api_key = ENV['STRIPE_TEST_SECRET_KEY']
end
# Implement proper logging
begin
charge = Stripe::PaymentIntent.create({
amount: 2000,
currency: 'usd',
payment_method: 'pm_123456789',
confirm: true
})
# Log successful transaction
Rails.logger.info("Payment succeeded: #{charge.id}, Amount: #{charge.amount}")
rescue Stripe::StripeError => e
# Log error details
Rails.logger.error("Stripe error: #{e.message}")
# Also consider sending alerts for critical failures
if e.is\_a?(Stripe::CardError)
# Handle gracefully - expected error
else
# Unexpected error - might need immediate attention
ErrorNotifier.notify(e)
end
raise e
end
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.