Working on a payment system we had to sort some difficulties when making recurring payments using active merchant. Why? Because we needed to use BeanStream gateway and active merchant does not support recurring billing for this gateway yet. So I just added the functionality to it.
You can check out my fork of Active Merchant that supports recurring billing for this merchant on http://github.com/wyeworks/active_merchant.
Here I leave you an example on how to use it:
require 'rubygems'
require 'active_merchant'
ActiveMerchant::Billing::Base.mode = :test
# ActiveMerchant accepts all amounts as Integer values in cents
# $10.00
amount = 1000
# The card verification value is also known as CVV2, CVC2, or CID
credit_card = ActiveMerchant::Billing::CreditCard.new(
:first_name => 'Bob',
:last_name => 'Bobsen',
:number => '4242424242424242',
:month => '8',
:year => '2012',
:verification_value => '123'
)
# Validating the card automatically detects the card type
if credit_card.valid?
# Create a gateway object for the BeansTream service
gateway = ActiveMerchant::Billing::BeanstreamGateway.new(
:login => 'TestMerchant',
:password => 'password',
:pass_code => 'pass_code'
)
# Make recurring payment for the amount
response = gateway.recurring(amount, credit_card, {
:recurring_billing => {
:end_of_month => '1',
:tax1 => 0,
:interval => {
:unit => :months,
:length => '1'
},
:duration => {
:start_date => Date.today,
:occurrences => 5
}
})
if response.success?
puts "Successfully charged $#{sprintf("%.2f", amount / 100)} to the credit card #{credit_card.display_number}. The Account number is #{response.params['rbAccountId']}"
else
raise StandardError, response.message
end
end
And that’s it, you have now created a recurring billing payment.
Now, what if you want to cancel the same? Heres is how to do that:
gateway.cancel_recurring({ :account_id => account_id })
Pretty easy…the account_id is the number the gateway responses with when making a recurrent payment, and the passcode is the way of authenticating in order to make this kind of transactions, and you can find it at the beanstream administrative console.
So try it out and have fun!



Is there an easy way to query for the status of the “subscription”, or be notified if it fails or is cancelled outside of your app in the future?
Kenzie, this is why the SaaS Rails Kit uses CIM or other stored-card gateways, rather than depending on the gateway itself doing the billing. It’s easier that way to know immediately when a charge fails.
Kenzie, this gateway in particular (BeanStream) supports being queried later on time. Note though that this is not yet implemented in Active Merchant. Nevertheless, if a recurring billing payment fails say three months later, the BeanStream people (and I guess other gateways would do the same) email you notifying about it.
ActiveMerchant isn’t bad. However, it’s been my experience that mapping ActiveMerchant onto individual payment gateways can be somewhat onerous.
I used AM with Authorize.Net (for heaven’s sake, DON’T EVER use Authorize.Net with or without AM). In hindsight, I realized that it would’ve been easier to write my own simple abstraction layer around an Authorize.Net-specific implementation. AM didn’t map cleanly onto Authorize.Net’s API.
Incidentally, if you want to read more about why not to use Authorize.Net, read http://evan.tiggerpalace.com/articles/2009/04/24/how-i-hate-authorize-net-let-me-count-the-ways/ and http://evan.tiggerpalace.com/articles/2009/05/22/really-never-ever-use-authorize-net/.
Sebastián: If you give the BeanStream recurring() method the same interface as the other gateways in ActiveMerchant then we can pull your changes into the official repo.
Evan: ActiveMerchant wasn’t designed to map directly to one payment gateway. It is a common abstraction to all the supported gateways, which allows you to change which gateway you’re using without minimal changes to your code.
Does this work with PayPal Website Payments Pro? There doesn’t seem to be a way to test recurring payments in the sandbox without signing up for the paid service.
Mark: This only applies for Beanstream Gateway.