Credit Card Processing with Python

Jul 9, 2020

Programming Tutorial

By: Brandon Quakkelaar

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.

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

Protect Cardholder Data

Maintain a Vulnerability Management Program

Implement Strong Access Control Measures

Regularly Monitor and Test Networks

Maintain an Information Security Policy

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:

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