Awesome
elixir_authorizenet
Elixir client for the Authorize.Net merchant API. This should help you integrate using the AIM.
A nice number of features are implemented (probably most of the ones used on a daily basis are already there), but since the API offers a big number of features and combinations, I still consider this as WIP, and pull requests, suggestions, or other kind of feedback are very welcome!
Using it with Mix
To use it in your Mix projects, first add it as a dependency:
def deps do
[{:elixir_authorizenet, "~> 0.3.0"}]
end
Then run mix deps.get to install it.
Configuring
In your config.exs, setup the following section:
config :elixir_authorizenet,
environment: :sandbox, # :sandbox or :production
validation_mode: :test, # :test, :live, or :none
login_id: "login_id",
transaction_key: "transaction_key"
Documentation
What follows is just a glance, a quick overview of the common used features. Feel free to take a look at the documentation served by hex.pm or the source itself to find more.
Customer Profiles
These are used when you want to store information in the Authorize.Net servers, like credit card or bank account information, and also billing and shipping addresses. This effectively is the interface to the CIM.
Customer Profiles are used via the Customer module.
alias AuthorizeNet.Customer, as: C
Creating
> C.create "merchantId", "description", "email@host.com"
%AuthorizeNet.Customer{description: "description", email: "email@host.com",
id: "merchantId", payment_profiles: [], profile_id: 35962612,
shipping_addresses: []}
Updating
> C.update 35962612, "merchantId", "description", "email2@host.com"
%AuthorizeNet.Customer{description: "description", email: "email2@host.com",
id: "merchantId", payment_profiles: [], profile_id: 35962612,
shipping_addresses: []}
Get all IDs
> C.get_all
[35962612]
Get Customer Profile
> C.get 35962612
%AuthorizeNet.Customer{description: "description", email: "email2@host.com",
id: "merchantId", payment_profiles: [], profile_id: 35962612,
shipping_addresses: []}
Deleting
> C.delete 35962612
:ok
Addresses
To handle billing and shipping addresses, use the Address module.
alias AuthorizeNet.Address, as: A
address = A.new(
"first_name",
"last_name",
"company",
"street",
"city",
"state",
"zip",
"country",
"phone",
"fax"
)
%AuthorizeNet.Address{address: "street", city: "city", company: "company",
country: "country", customer_id: nil, fax: "fax", first_name: "first_name",
id: nil, last_name: "last_name", phone: "phone", state: "state", zip: "zip"}
Shipping Addresses
You can do some CRUD with shipping addresses in a customer profile.
Creating
> C.create_shipping_address 35962612, address
%AuthorizeNet.Address{address: "street", city: "city", company: "company",
country: "country", customer_id: 35962612, fax: "fax",
first_name: "first_name", id: 34066037, last_name: "last_name", phone: "phone",
state: "state", zip: "zip"}
Getting
> C.get_shipping_address 35962612, 34066037
%AuthorizeNet.Address{address: "street", city: "city", company: "company",
country: "country", customer_id: 35962612, fax: "fax",
first_name: "first_name", id: 34066037, last_name: "last_name", phone: "phone",
state: "state", zip: "zip"}
Updating
Make sure you have an AuthorizeNet.Address
struct with customer_id and id already filled in
(for example by getting it from the server). Then:
> C.update_shipping_address address
%AuthorizeNet.Address{address: "street", city: "city", company: "company",
country: "country", customer_id: 35962612, fax: "fax",
first_name: "first_name", id: 34066235, last_name: "last_name", phone: "phone",
state: "state", zip: "zip2"}
Deleting
> C.delete_shipping_address 35962612, 34066037
:ok
Customer Payment Profiles
Payment profiles are handled in the PaymentProfile module. With a PaymentProfile you can declare credit cards and bank accounts and save them into a customer profile. Bank accounts are handled by the module BankAccount while credit cards are handled by the module Card.
alias AuthorizeNet.PaymentProfile, as: P
alias AuthorizeNet.BankAccount, as: BankAccount
alias AuthorizeNet.Card, as: Card
And can be created with the functions:
- AuthorizeNet.PaymentProfile.create_business: To create a "business" associated payment profile.
- AuthorizeNet.PaymentProfile.create_individual: To create a payment profile for an individual, not associated to a business.
Creating a Credit Card
> card = Card.new "5424000000000015", "2015-08", "900"
%AuthorizeNet.Card{code: "900", expiration_date: "2015-08",
number: "5424000000000015"}
> P.create_individual 35962612, address, card
%AuthorizeNet.PaymentProfile{address: %AuthorizeNet.Address{address: "street",
city: "city", company: "company", country: "country", customer_id: nil,
fax: "fax", first_name: "first_name", id: nil, last_name: "last_name",
phone: "phone", state: "state", zip: "zip"}, customer_id: 35962612,
payment_type: %AuthorizeNet.Card{code: "900", expiration_date: "2015-08",
number: "5424000000000015"}, profile_id: 32510145, type: :individual}
Creating a bank account
Bank accounts can be created via 3 functions:
- AuthorizeNet.BankAccount.savings: A savings account.
- AuthorizeNet.BankAccount.checking: A checking account.
- AuthorizeNet.BankAccount.business_checking: A business checking account.
> account = BankAccount.savings "bank_name", "routing_number", "account_number", "name_on_account", :ccd
%AuthorizeNet.BankAccount{account_number: "account_number",
bank_name: "bank_name", echeck_type: :ccd, name_on_account: "name_on_account",
routing_number: "routing_number", type: :savings}
> P.create_individual 35962612, address, account
%AuthorizeNet.PaymentProfile{address: %AuthorizeNet.Address{address: "street",
city: "city", company: "company", country: "country", customer_id: nil,
fax: "fax", first_name: "first_name", id: nil, last_name: "last_name",
phone: "phone", state: "state", zip: "zip"}, customer_id: 35962612,
payment_type: %AuthorizeNet.BankAccount{account_number: "account_number",
bank_name: "bank_name", echeck_type: :web, name_on_account: "name_on_account",
routing_number: "routing_number", type: :savings}, profile_id: 32510152,
type: :individual}
The last argument is the type of echeck.
Getting a payment profile
> P.get 35962612, 32510152
%AuthorizeNet.PaymentProfile{address: %AuthorizeNet.Address{address: "street",
city: "city", company: "company", country: "country", customer_id: nil,
fax: "fax", first_name: "first_name", id: nil, last_name: "last_name",
phone: "phone", state: "state", zip: "zip"}, customer_id: 35962612,
payment_type: %AuthorizeNet.BankAccount{account_number: "XXXX0999",
bank_name: "bank_name", echeck_type: :web, name_on_account: "name_on_account",
routing_number: "XXXX3093", type: :savings}, profile_id: 32510152,
type: :individual}
There is a third argument available which is a list of options. The available options are:
- :unmask_expiration_date: For payment profiles associated to credit cards, this will return the expiration date unmasked.
Example:
> P.get 35962612, 34818508, [:unmask_expiration_date]
Searching for payment profiles
This will return all the payment profiles of all customers that matches the given criteria. For more information about the values allowed see: http://developer.authorize.net/api/reference/#customer-profiles-get-customer-payment-profile-list.
> P.get_list "cardsExpiringInMonth", "2016-08", "id", false, 100, 1
[%AuthorizeNet.PaymentProfile{address: %AuthorizeNet.Address{address: "street",
city: "city", company: "company", country: "country", customer_id: 38311592,
fax: "fax", first_name: "first_name", id: nil, last_name: "last_name",
phone: "phone", state: "state", zip: "zip"}, customer_id: 38311592,
payment_type: %AuthorizeNet.Card{code: nil, expiration_date: "XXXX",
number: "XXXX0015"}, profile_id: 34818508, type: nil}]
Validating
> P.valid? 35962612, 32510145
{false,
%AuthorizeNet.Error.Operation{message: [{"E00027", "Card Code is required."}]}}
> P.valid? 35962612, 32510145, "900"
true
Deleting
> AuthorizeNet.PaymentProfile.delete 35962612, 32510145
:ok
Making transactions
In a nutshell
Transactions are made via the Transaction module.
To create a transaction, just call the new
function, passing an optional amount (a float) as the argument.
alias AuthorizeNet.Transaction, as: T
T.new(12.34)
To run a transaction, just call the run
function:
T.new(12.34) |>
T.run
TransactionResponse
All transactions will return a TransactionResponse struct, like:
%AuthorizeNet.TransactionResponse{account_number: "XXXX0015",
account_type: "MasterCard", auth_code: "QWIDX2", avs_result: "Y",
cavv_result: nil, code: 1, cvv_result: nil,
errors: [{"I00001", "Successful."}], operation_errors: [],
ref_transaction_id: nil, success: true, test_request: "0",
transaction_hash: "D05A1D1C4558FB329522CCFC62B4A7F3",
transaction_id: "2235759738", user_fields: [{"key1", "value1"}, {"key2", "value2"}]}
Transaction types
Authorize.Net supports different transaction types. You can choose between them as follows:
T.new |>
T.auth_capture() # or
T.auth_only() # or
T.capture_only() # or
T.prior_auth_capture() # or
T.void(transaction_id) # or
T.refund(transaction_id) # or
Adding customer, billing and shipping information
These might or might not be required depending on the type of payment you choose (i.e: customer profiles include the billing and shipping information in their payment profile ids and shipping address ids respectively):
T.bill_to(address) |>
T.ship_to(address) |>
T.customer_individual("id1", "email@host.com") |>
# You can also specify a "business" customer instead:
T.customer_business("id1", "email@host.com")
Transaction Settings
You can enable and disable different transaction settings, like:
T.enable_partial_auth |> # or T.disable_partial_auth
T.enable_duplicate_window |> # or T.disable_duplicate_window
T.enable_test_request |> # or T.disable_test_request
T.enable_recurring_billing |> # or T.disable_recurring_billing
T.enable_email_customer # or T.disable_email_customer
Adding tax information
Optionally, you can add some tax information:
T.not_tax_exempt |> # or T.tax_exempt
T.tax("name", "description", 3.44) |>
T.duty("name", "description", 3.44) |>
T.shipping_cost("name", "description", 3.44)
Adding order information
You can include the order information (and optionally any billing items and purchase order ) like this:
T.order("4455", "order description") |>
T.add_item(1, "item1", "itemdesc1", 1, 1.00) |>
T.add_item(2, "item2", "itemdesc2", 1, 2.00) |>
T.po_number("po_number_1")
Specifying market type
T.market_retail # or
T.market_ecommerce # or
T.market_moto
Specifying device type
T.device_website # or
T.device_unknown # or
T.device_unattended_terminal # or
T.device_electronic_cash_register # or
T.device_personal_computer # or
T.device_air_pay # or
T.device_self_service_terminal # or
T.device_wireless_pos # or
T.device_dial_terminal # or
T.device_virtual_terminal # or
Adding custom fields
T.user_fields(%{
"key1": "value1",
"key2": "value2"
})
Other information you can add to the transaction.
T.auth_code("QFBYYN") |> # Used for already authorised transactions.
T.ref_transaction_id("2235786422") |> # Used to refund or credit
T.employee_id(5678) |>
T.customer_ip("127.0.0.1")
Paying with credit card
T.new(10.25) |>
T.auth_capture() |>
T.bill_to(address) |>
T.pay_with_card(card) |>
T.order("4455", "order description") |>
T.run
Paying with a payment profile id
T.new(10.25) |>
T.auth_capture() |>
T.pay_with_customer_profile(
customer_profile_id,
payment_profile_id,
shipping_address_id,
card_code
) |>
T.order("4455", "order description") |>
T.run
Paying with Apple Pay
T.new(10.25) |>
T.auth_capture() |>
T.pay_with_apple_pay(encrypted_data) |>
T.order("4455", "order description") |>
T.run
Paying with a Bank Account
T.new(10.25) |>
T.bill_to(address) |>
T.auth_capture() |>
T.pay_with_bank_account(account) |>
T.order("4455", "order description") |>
T.run
Voiding a transaction
T.new |>
T.void("2235759535") |>
T.run
Refund a transaction
T.new(3.00) |>
T.bill_to(address) |>
T.order("4455", "order description") |>
T.pay_with_card(card) |>
T.refund("2235759535") |>
T.run
Errors
These errors might be raised by the API calls:
-
AuthorizeNet.Error.Connection: There was an error when trying to hit the API endpoint (like a network issue).
-
AuthorizeNet.Error.Request: The request was sent and received by the server, but it returned a status different than 200.
-
AuthorizeNet.Error.Operation: The request was sent and received successfully, a status 200 was returned by the server, but there was an error when trying to process the operation.
License
The source code is released under Apache 2 License.
Check LICENSE file for more information.
TODO
- Allow payment profiles when creating a customer profile.
- Add support for hosted profile page.
- Add support for creating a customer profile from a successful transaction.
- Add support for recurring billing.
Useful Authorize.Net documentation
- API reference.
- Transaction Types.
- How to generate specific error codes useful for testing purposes.
- Error reason check tool.
- FAQ about sandbox environment.