If you run a business, charity, or any organization that accepts money, a professional online payment feature on your website is a great way for your patrons to conveniently pay you.
Here’s how such a payment feature can be implemented in Python with Authorize.net.
Create a Sandbox Account
If you’re a programmer interested in building a project yourself, then you’ll need to visit Authorize.net and create a sandbox account. Your sandbox account will let you test your payment processing integration without actually charging credit cards, and without needing to set up a Merchant Account with your bank. To process real payments you will need a Merchant Account, but for development we just need sandbox access.
Set up your sandbox account in Authorize.net’s Developer Center.
Once you’ve done that, you will have four pieces of information that you should save.
- Sandbox account credentials (username and password)
- API Login ID (25 alphanumeric characters)
- Transaction Key (16 alphanumeric characters)
- Key
The important elements to note are the API Login ID and the Transaction Key. These two pieces of information are used to authenticate your calls into Authorize.net’s API to process payments. Keep this information secret. Don’t share it with anyone. Don’t commit it to Git.
Use the Python SDK
Create a new directory for the python project.
$ mkdir authnetdemo
$ cd authnetdemo
I’m not going to explain Python virtual environments in this article, but feel free to use one for this project if you like.
Now install the Authorize.net SDK.
$ python3.7 -m pip install authorizenet
Create file called “settings.py” for the module that will be responsible for managing the Authorize.net secrets. For now I’m going to just place the real values directly in the file, but I don’t recommend that for production code, nor for projects that will be committed to source control like Git.
settings.py
def get_transaction_id():
return "YOUR_TRANSACTION_ID"
def get_api_login_id():
return "YOUR_API_LOGIN_ID"
These values could be retrieved from a database or environment variables. Or they could even be retrieved from a configuration file in xml, json, or your format of choice. I’m not going to cover those techniques in this article, but they are all good ways to keep secrets out of the application’s source code.
Create a “models.py” file to hold a couple classes that we’ll use.
models.py
class CreditCard:
number = None
expiration_date = None
code = None
class TransactionResponse:
is_success = False
messages = []
These classes are abstractions for models from the SDK. This helps future SDK upgrades and changes. The CreditCard
class models bare bones card information. The TransactionResponse
class models the response from the Authorize.net API call.
Other potential things we could add include things like billing address, name on card, and order information.
Create a file called “paymentprocessing.py” for the module handling credit card tasks.
paymentprocessing.py
from authorizenet import apicontractsv1
from authorizenet.apicontrollers import createTransactionController
from decimal import Decimal
import settings
import models
def charge_credit_card(card, amount):
merchant_auth = apicontractsv1.merchantAuthenticationType()
merchant_auth.name = settings.get_api_login_id()
merchant_auth.transactionKey = settings.get_transaction_id()
credit_card = apicontractsv1.creditCardType()
credit_card.cardNumber = card.number
credit_card.expirationDate = card.expiration_date
credit_card.cardCode = card.code
payment = apicontractsv1.paymentType()
payment.creditCard = credit_card
transaction_request = apicontractsv1.transactionRequestType()
transaction_request.transactionType ="authCaptureTransaction"
transaction_request.amount = Decimal(amount)
transaction_request.payment = payment
request = apicontractsv1.createTransactionRequest()
request.merchantAuthentication = merchant_auth
request.refId ="MerchantID-0001"
request.transactionRequest = transaction_request
transaction_controller = createTransactionController(request)
transaction_controller.execute()
api_response = transaction_controller.getresponse()
response = response_mapper(api_response)
return response
def response_mapper(api_response):
response = models.TransactionResponse()
if api_response is None:
response.messages.append("No response from api")
return response
if api_response.messages.resultCode=="Ok":
response.is_success = hasattr(api_response.transactionResponse, 'messages')
if response.is_success:
response.messages.append(f"Successfully created transaction with Transaction ID: {api_response.transactionResponse.transId}")
response.messages.append(f"Transaction Response Code: {api_response.transactionResponse.responseCode}")
response.messages.append(f"Message Code: {api_response.transactionResponse.messages.message[0].code}")
response.messages.append(f"Description: {api_response.transactionResponse.messages.message[0].description}")
else:
if hasattr(api_response.transactionResponse, 'errors') is True:
response.messages.append(f"Error Code: {api_response.transactionResponse.errors.error[0].errorCode}")
response.messages.append(f"Error message: {api_response.transactionResponse.errors.error[0].errorText}")
return response
response.is_success = False
response.messages.append(f"response code: {api_response.messages.resultCode}")
return response
There are two functions; charge_credit_card
and response_mapper
.
The response_mapper
is a function to abstract the SDK’s response model away from the rest of the applicaiton. The idea there is if that response model changes, then we only need to update this module and the mapper, and not have to make changes elsewhere in the application.
The charge_credit_card
function is where the actual money changes hands. First the merchant is identified. Then the card information is set.
Create an app.py
file.
app.py
import models
import paymentprocessing
amount = "19.99"
card = models.CreditCard()
card.number = "4007000000027" # visa test number
card.expiration_date = "2050-01" # any date in the future
card.code = "123" # any 3 digit code
response = paymentprocessing.charge_credit_card(card, amount)
print(response.is_success)
print(response.messages)
This is the entry point for our Python script. The amount to charge is specified. The credit card details are specified. Then we attempt to charge the card and print the response.
Run “app.py” without forgeting to add your API Login ID and Transaction ID.
$ python3.7 app.py
True
['Successfully created transaction with Transaction ID: 40051695558', 'Transaction Response Code: 1', 'Message Code: 1', 'Description: This transaction has been approved.']
For more details about Authorize.net’s testability, take a look at their Testing Guide.
Note: If you get a Transaction ID of 0, then you may need to sign in to your sandbox account and switch the sandbox account settings from “Testing” to “Live.” It’s still a testing account and cards wont actually be charged, but this setting replicates the behavior of non-sandbox accounts. Those non-sandbox accounts can be placed in testing mode too.
Security
I can’t discuss processing credit cards without addressing security concerns. PCI Data Security Standard (PCI DSS) is a standardized checklist for making sure merchants and programmers are securely handling credit card information. Here’s an overview of PCI DSS taken from the PCI Security Standards Council’s quick reference guide.
PCI DSS Requirements
Build and Maintain a Secure Network
- Install and maintain a firewall configuration to protect cardholder data
- Do not use vendor-supplied defaults for system passwords and other security parameters
Protect Cardholder Data
- Protect stored cardholder data
- Encrypt transmission of cardholder data across open, public networks
Maintain a Vulnerability Management Program
- Use and regularly update anti-virus software or programs
- Develop and maintain secure systems and applications
Implement Strong Access Control Measures
- Restrict access to cardholder data by business need-to-know
- Assign a unique ID to each person with computer access
- Restrict physical access to cardholder data
Regularly Monitor and Test Networks
- Track and monitor all access to network resources and cardholder data
- Regularly test security systems and processes
Maintain an Information Security Policy
- Maintain a policy that addresses information security for employees and contractors
Read the quick reference guide for more details on what each of these points mean.
Next Steps
What we’ve accomplished in this tutorial is significant. We are able to process credit card payments via Authorize.net’s API. However, the code presented here can certainly be improved with some additions:
- Build a web UI
- Secure with SSL encryption
- Add logging
- Record transations in your own database
- Handle secrets securely
- Open an actual Merchant Account with a bank and configure it with Authorize.net to accept real payments
This isn’t an exhaustive list, but it is a good start. Though with every new feature, be sure to check PCI DSS recommendations to make sure you’re compliant. For example, if you decide to transfer credit card information over a network, you have to make sure it’s secured and encrypted. If you want to store credit card information on your own servers, you have to make sure those servers and the information is secured according to PCI standards.
Further Reading
- Authorize.net Credit Card Tutorial
- Authorize.net Testing Guid
- Authorize.net Python SDK
- Authorize.net sample code in Python
- Authorize.net Developer Community
- PCI DSS Quick Reference Guide
Please share this post with a friend, and subscribe to get notified of new posts.
Comments may be sent to blog@quakkels.com.