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!
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.
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"
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.
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
> C.create "merchantId", "description", "[email protected]"
%AuthorizeNet.Customer{description: "description", email: "[email protected]",
id: "merchantId", payment_profiles: [], profile_id: 35962612,
shipping_addresses: []}
> C.update 35962612, "merchantId", "description", "[email protected]"
%AuthorizeNet.Customer{description: "description", email: "[email protected]",
id: "merchantId", payment_profiles: [], profile_id: 35962612,
shipping_addresses: []}
> C.get_all
[35962612]
> C.get 35962612
%AuthorizeNet.Customer{description: "description", email: "[email protected]",
id: "merchantId", payment_profiles: [], profile_id: 35962612,
shipping_addresses: []}
> C.delete 35962612
:ok
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"}
You can do some CRUD with shipping addresses in a customer profile.
> 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"}
> 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"}
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"}
> C.delete_shipping_address 35962612, 34066037
:ok
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.
> 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}
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.
> 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]
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}]
> P.valid? 35962612, 32510145
{false,
%AuthorizeNet.Error.Operation{message: [{"E00027", "Card Code is required."}]}}
> P.valid? 35962612, 32510145, "900"
true
> AuthorizeNet.PaymentProfile.delete 35962612, 32510145
:ok
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
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"}]}
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
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 protected]") |>
# You can also specify a "business" customer instead:
T.customer_business("id1", "[email protected]")
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
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)
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")
T.market_retail # or
T.market_ecommerce # or
T.market_moto
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
T.user_fields(%{
"key1": "value1",
"key2": "value2"
})
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")
T.new(10.25) |>
T.auth_capture() |>
T.bill_to(address) |>
T.pay_with_card(card) |>
T.order("4455", "order description") |>
T.run
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
T.new(10.25) |>
T.auth_capture() |>
T.pay_with_apple_pay(encrypted_data) |>
T.order("4455", "order description") |>
T.run
T.new(10.25) |>
T.bill_to(address) |>
T.auth_capture() |>
T.pay_with_bank_account(account) |>
T.order("4455", "order description") |>
T.run
T.new |>
T.void("2235759535") |>
T.run
T.new(3.00) |>
T.bill_to(address) |>
T.order("4455", "order description") |>
T.pay_with_card(card) |>
T.refund("2235759535") |>
T.run
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.
The source code is released under Apache 2 License.
Check LICENSE file for more information.
- 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.
- API reference.
- Transaction Types.
- How to generate specific error codes useful for testing purposes.
- Error reason check tool.
- FAQ about sandbox environment.