Introduction
Note: For native English speakers and high ability non-native speakers
I have attempted to write this post using simplified English grammar to hopefully aid reading comprehension for English learners, and to also aid machine translation. So, I may use shorter sentences and less complicated grammar constructs.
Overview
In this post I will write about Payment Gateways and the card purchase process. After, I will then write about the ActiveMerchant RubyGem.
Payment Gateways and Credit Card Processing
How are Credit Card purchases processed?
Entities in Purchase process
The Process
The diagram above shows the key actors in the process. In my previous and current work experience, I've been writing the software at two places. First was for Issuing banks. (Integration from Bank to Visa). More recently, it is software at the Merchant.
During a purchases purchase:
- Card Details (or a token representing a card) are passed from Customer
- ... Into Merchant Software (the EC Site)
- ... Sends request to Payment Gateway
- ... Gateway selects which Payment Processor to communicate with
- ... Sends request to Payment Processor
- ... Sends request to correct Card Association
- ... Sends request to Issuing Bank (except American Express and Discover, who are ALSO the Issuing Bank)
Payment Flow and State Transition
Below is generic description of the purchase flow.
Different Gateways may provide different, or additional functionality. In fact, each Gateway will have very specific differences which the merchant needs to handle.
Examples:
- Some Gateways only support
AUTH
andSALE
using the Card Token obtained duringSTORE
. - Some Gateways may NOT support
VOID
after aCAPTURE
, and/orSALE
. - Some Gateways may NOT support
VOID
after aCAPTURE
, and/orSALE
, if a certain time has expired. - Gateways will have different expirations for
AUTH
. Ifx
time passes, andAUTH
will be automaticallyVOID
ed by Gateway, and aCAPTURE
will fail. - Some Gateways may not support
SALE
. - Some Gateways may NOT support partial
REFUND
.
This means, if a Merchant needs to support multiple Gateways, a large amount of custom code will need to be written.
A merchant could write their own adapter layer. This will provide a unified API to the main merchant Store software.
The alternative is to use Open Source software.
ActiveMerchant
ActiveMerchant is a RubyGem written and maintained by Shopify. It's goal is to provide a simple unified API to a lot of different Payment Gateways.
The source code is open source. So, you can contribute code for new gateways. You could also fork, and maintain your own version with custom Gateway integration.
In my previous employment, I maintained an ActiveMerchant fork. This contained our code for integration with three Payment Gateways not supported by the master ActiveMerchant branch.
Gateways
ActiveMerchant provides a guide on how to use and write your own integration.
Typically, you will use an existing subclass of ActiveMerchant::Billing::Gateway
, or write a new one.
Standard Methods
Typically, each ActiveMerchant::Billing::Gateway
will provide implementation for the following:
Method | State Equivalent | Notes |
---|---|---|
purchase | SALE | Perform a combined AUTH/CAPTURE, with specified amount, using supplied Card Token (or supplied card details |
authorize | AUTH | Perform an AUTH, for a specified amount, using supplied Card Token (or supplied card details |
capture | CAPTURE | Capture a previous AUTH |
void | VOID | Cancel a previous SALE, AUTH, or CAPTURE (if gateway supports it) |
refund | REFUND | Perform a second transaction, to repay Cardholder. Partial may be possible. |
verify | Some Gateways support verification of card details | |
store | STORE | Use supplied card details, and obtain a card token. |
unstore |
Example Code
STRIPE requires the use of JSON in their calls. post
is a Ruby hash with request parameters. These are then sent to STRIPE.
Also note, the payment
parameter with STRIPE can ONLY be a card token (a String). It cannot be a ActiveMerchant::Billing::CreditCard
instance, which the base class supports.
# To create a charge on a card or a token, call
#
# purchase(money, card_hash_or_token, { ... })
#
# To create a charge on a customer, call
#
# purchase(money, nil, { :customer => id, ... })
def purchase(money, payment, options = {})
if ach?(payment)
direct_bank_error = "Direct bank account transactions are not supported. Bank accounts must be stored and verified before use."
return Response.new(false, direct_bank_error)
end
MultiResponse.run do |r|
if payment.is_a?(ApplePayPaymentToken)
r.process { tokenize_apple_pay_token(payment) }
payment = StripePaymentToken.new(r.params["token"]) if r.success?
end
r.process do
post = create_post_for_auth_or_purchase(money, payment, options)
commit(:post, 'charges', post, options)
end
end.responses.last
end
The full code is available here.
def authorize(money, credit_card_or_vault_id, options = {})
create_transaction(:sale, money, credit_card_or_vault_id, options)
end
def capture(money, authorization, options = {})
commit do
result = @braintree_gateway.transaction.submit_for_settlement(authorization, amount(money).to_s)
response_from_result(result)
end
end
def purchase(money, credit_card_or_vault_id, options = {})
authorize(money, credit_card_or_vault_id, options.merge(:submit_for_settlement => true))
end
BrainTree Blue has a different implementation. But, you can see it exposes the same API to the calling Merchant code.
Sample Architecture
The diagram is a very rough layout of a possible architecture.
In the case of a monolithic Rails application, ActiveMerchant is included directly via Gemfile. Then, we could write some form Gateway Service class layer. Here, we could write code to store and manage Gateway configuration. There should be code to instantiate the correct ActiveMerchant Gateway instance. Perhaps we would wrap this in a decorator.
If necessary, the decorator could store Gateway specific information that may be necessary for certain operations.
The EC site code would then call the appropriate decorator class when payment operations are required.
Alternatively, the Gateway code could be extracted out into a micro-service. This micro-service would include ActiveMerchant in it's Gemfile. The EC site code would then call the Payment micro-service.