Implementing credit card payment systems has been one of my least favorite coding projects, but things have gotten much nicer since I first started. I'm just starting again with my new company, and I will be continuously updating this post with my progress. I'm hoping to capture every single decision I've made to help other people get going and also as a reference for myself the next time I need to do this.
10/20/11: Choosing a Merchant Account and Gateway
After looking at a few different payment gateways, I've decided to try
Braintree, mostly because of their awesome-looking,
well-documented Ruby gem, but also because I've seen them at various Ruby/Rails events (speaking and sponsoring), and because I've heard good things about them from
Figure53 and friends at
LivingSocial. I also really like their "
transparent redirect" feature, where credit card numbers never enter our system at all.
We also need a merchant account to go with the gateway. Since we're doing all of our banking with
BB&T so we've decided to get a merchant account with them as well. Their rates seem competitive (much cheaper than Braintree's merchant account, probably because they have to partner with a bank and are charging a markup over the bank's fees). We also want to deepen our business relationship with the bank vs. shopping around for the absolute cheapest rates (something that can be done with
FeeFighters).
We're doing the paperwork with BB&T right now. Next step will be to start integrating the braintree gem into our codebase, creating the payment screens in our system, etc.
10/25/11: Considering a Switching to Stripe
After posting the above,
Gabriel Weinberg and other friends on Twitter suggested I check out a Braintree competitor,
Stripe. Stripe seems to offer even more of a "one-stop shop" for payment systems than Braintree, and it has similar Ruby bindings and "transparent signup" features. So for me it comes down to pricing. A commenter from FeeFighters also suggested their
Samurai gateway.
Both Stripe and Samurai look great when your volume is relatively small: their lack of monthly fees means your processing costs are lower. I'm building a subscription-based app, so I removed Samurai from consideration; not having to write a bunch of proration code, not having to worry about accidentally billing someone twice, etc., is a huge benefit of Braintree and Stripe. I'm sure Samurai will add it soon.
Once you get up to higher volumes, Stripe and Samurai become more expensive than Braintree plus a merchant account. I did some spreadsheet modeling and determined that using Braintree plus our BB&T merchant account becomes cost effective once we have 50 customers, which is about as many as we would need to really have traction.
I'm tempted to use the cheaper short-term solution now, but since I don't want to have to switch this around later once we get to 50 customers, I've decided to stick with Braintree and our own merchant account.
I also considered using
Authorize.net, which seems slightly cheaper than Braintree, but the overall look and feel of their website is not developer friendly. Whereas all of the other sites I've mentioned look like they've put a big priority on making the developer happy.
11/4/11: Finished Initial Integration
I had a fairly easy time integrating the code with Braintree's sandbox. I was greatly helped by this
testing technique that uses the wonderful
VCR gem, so I could run my integration tests against real Braintree responses without having to hit their API every time. I also found inspiration from Braintree's
example Ruby applications.
I'm using the
Transparent-Redirect customer creation method to create a customer and store their credit card in the vault (so the credit card number never touches my systems at all; the only thing we store is a payment token referring to the credit card stored by Braintree). In a separate step I use the
subscription creation API to create the monthly recurring charge.
My biggest struggle was in figuring out how to wrap the transparent-redirect response from Braintree in an ActiveModel-compliant object, so that when the user entered invalid data I could render the form like any other Rails form, with inline errors and so forth. I came up with a hack which I'm a little too embarrassed to post here but if you want it
email me. In hindsight I should have just used this
custom form builder.