-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Patterns & Standards
ActiveMerchant is predicated on the idea of providing a common Ruby API to payment gateway API's. Towards this goal, this (currently very rough draft form) Patterns & Standards guide seeks to lay out what that common API is, how to test it, and what is within the scope of it.
Currently this document is broken down by public API - where each API can potentially encompass multiple public methods - and then further by sections on expected behavior and testing guidelines.
This is the bare minimum API for a gateway to support, and consists of a single call:
def purchase(amount, payment_method, options={}) #=> Response
This method is expected to authorize payment and transparently trigger eventual settlement. Preferably it is implemented as a single call to the gateway, but it can also be implemented as chained authorize
and capture
calls.
Arguments:
authorize
should authorize funds on a payment instrument that will not be settled without a following call to capture
within some finite period of time. When implementing this API, authorize
and capture
are both required. void
is an optional (but highly recommended) supplement to this API that should immediately cancel an authorized charge, clearing it off of the underlying payment instrument without waiting for expiration.
def authorize(amount, payment_method, options={}) #=> Response
def capture(amount, identifier, options={}) #=> Response
def void(identifier, options={}) #=> Response
Arguments:
Partial captures, if supported by the gateway, are achieved by passing an amount
. Not passing an amount to capture
should always cause the full amount of the initial authorization to be captured.
If the gateway does not support partial captures, calling capture
with an amount other than nil
should raise an error indicating partial capture is not supported.
Cancels settlement or returns funds as appropriate for a referenced prior purchase
or capture
.
def refund(amount, identifier, options={}) #=> Response
Arguments:
When supported by the payment method, verifies that the instrument is valid.
Ideally this will be implemented for credit cards as a zero dollar authorization. Unfortunately, many gateways do not support zero dollar authorizations, in which case this should be implemented as an authorize
immediately followed by a void
.
def verify(payment_method, options={}) #=> Response
Arguments:
Tokenizes a supported payment method in the gateway's vault. ActiveMerchant treats all tokenization as a simple token -> payment method
mapping. If the gateway conflates tokenization with customer management, ActiveMerchant should hide all customer management and any customer identifier(s) within the token returned. It's certainly legitimate to have a library that interacts with all the features in a gateway's vault, but ActiveMerchant is not the right place for it.
def store(payment_method, options={}) #=> Response
def unstore(token, options={}) #=> Response
def update(token, payment_method, options={}) #=> Response
Arguments:
It's critical that store
returns a token that can be used against purchase
and authorize
. Currently the standard is to return the token in the Response#authorization
field.
While it's OK to pass along basic customer information for update in the options to this call, it is only designed to support the case of wanting to change/update the payment method mapped to a token. It's critical that the token is the token returned from store
, and that the call fails if not passed a payment method.
Puts funds directly onto a supported payment method. Typically hard to get approval for usage.
def credit(amount, payment_method, options={}) #=> Response
Arguments:
The amount to charge as an integer (never a float). In the case of currencies that support fractional amounts, should be the integer amount of the smallest fractional (so, in the case of USD, the integer number of cents).
The instrument to charge. The minimum instrument required to be supported is a bare credit card; ActiveMerchant does not support gateways that solely allow transacting against tokens acquired elsewhere.
Currently supported instruments:
-
CreditCard
: As per above, a raw credit card, including a PAN at a minimum. -
BankAccount
: Checking account information, for echeck transactions. -
String
/token
: Representation of a payment method tokenized viastore
-
String
/identifier
: Representation of a previous transaction that can be transacted against ("reference transaction")
Card specific data should only come from the CreditCard
object when executing transactions.
CreditCard.number
CreditCard.first_name
CreditCard.last_name
CreditCard.verfication_value
CreditCard.month
CreditCard.year
Gateway-specific options hash, that nevertheless has some standard keys:
:billing_address
:shipping_address
:ip
:email
:phone
:order_id
:currency
Beyond the standard keys, optional additional information can be included from the options hash in the gateway request.