Node.js: how to implement payments with Authorize.Net

Node.js: how to implement payments with Authorize.Net

In this article we will see how to implement payments with Authorize.Net in ExpressJS.

In this article we will see how to implement payments with Authorize.Net in ExpressJS.

We can create an account on the Authorize.Net's sandbox to get the credentials for accessing the API.

We save our credentials in a dedicated file.

'use strict';

module.exports = {
    loginId: '',
    transactionKey: ''
};

Now we install the official NPM module.

npm install authorizenet --save

Unlike other solutions, in the case of Authorize.Net, payments by credit card require that our frontend collect the essential data of a card, namely:

  1. Credit card number (without spaces).
  2. CVV code.
  3. Expiry date (in the format mmyy).

The amount to be paid is in decimal format but the Authorize.Net SDK processes it as a decimal string, so it is not necessary to use the parseFloat() method before making the request.

We can create a utility function for the validation of the data sent.

'use strict';

const validator = require('validator');

module.exports = {
    validateForm(req) {
        const { cc, cvv, expire, amount } = req.body;

        const errors = [];

        if(!validator.isCreditCard(cc)) {
            errors.push({
                param: 'cc',
                msg: 'Invalid credit card number.'
            });
        }

        if(!/^\d{3}$/.test(cvv)) {
            errors.push({
                param: 'cvv',
                msg: 'Invalid CVV code.'
            });
        }

        if(!/^\d{4}$/.test(expire)) {
            errors.push({
                param: 'expire',
                msg: 'Invalid expiration date.'
            }); 
        }

        if(!validator.isDecimal(amount)) {
            errors.push({
                param: 'amount',
                msg: 'Invalid amount.'
            }); 
        }

        return errors;
    }
};

We use the validator module to validate the credit card number. Fictitious numbers should be used in the sandbox, such as 4242424242424242.

Now we can actually create the route for processing the form.

'use strict';

const express = require('express');
const { loginId, transactionKey } = require('./config');
const ApiContracts = require('authorizenet').APIContracts;
const ApiControllers = require('authorizenet').APIControllers;
const SDKConstants = require('authorizenet').Constants;
const app = express();
const port = process.env.PORT || 3000;
const { validateForm } = require('./lib');

app.post('/checkout', (req, res) => {
    const validationErrors = validateForm(req);

    if(validationErrors.length > 0) {
        res.json({ errors: validationErrors });
        return;
    }
    
    // Request
});

app.listen(port);    

The request that triggers the transaction can only take place after data validation.

This relatively elaborate request is divided into two phases. In the first, we setup the classes used by the module to create the transaction.

const { cc, cvv, expire, amount } = req.body;

    const merchantAuthenticationType = new ApiContracts.MerchantAuthenticationType();
    merchantAuthenticationType.setName(loginId);
    merchantAuthenticationType.setTransactionKey(transactionKey);
    
    const creditCard = new ApiContracts.CreditCardType();
    creditCard.setCardNumber(cc);
    creditCard.setExpirationDate(expire);
    creditCard.setCardCode(cvv);
    
    const paymentType = new ApiContracts.PaymentType();
    paymentType.setCreditCard(creditCard);

    const transactionSetting = new ApiContracts.SettingType();
    transactionSetting.setSettingName('recurringBilling');
    transactionSetting.setSettingValue('false');
    
    const transactionSettingList = [];
    transactionSettingList.push(transactionSetting);
    
    const transactionSettings = new ApiContracts.ArrayOfSetting();
    transactionSettings.setSetting(transactionSettingList);
    
    const transactionRequestType = new ApiContracts.TransactionRequestType();
    transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.AUTHCAPTURETRANSACTION);
    transactionRequestType.setPayment(paymentType);
    transactionRequestType.setAmount(amount);
    transactionRequestType.setTransactionSettings(transactionSettings);
    
    const createRequest = new ApiContracts.CreateTransactionRequest();
    createRequest.setMerchantAuthentication(merchantAuthenticationType);
    createRequest.setTransactionRequest(transactionRequestType);

In the second, the remote request is made and the results returned by the Authorize.Net API are managed.

const ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON());

    ctrl.execute(() => {
        const apiResponse = ctrl.getResponse();
        const response = new ApiContracts.CreateTransactionResponse(apiResponse);

        if(response !== null) {
            if(response.getMessages().getResultCode() === ApiContracts.MessageTypeEnum.OK) {
                if(response.getTransactionResponse().getMessages() !== null) {
                    res.json({ success: 'Transaction was successful.' });
                } else {
                    if(response.getTransactionResponse().getErrors() !== null) {
                        let code = response.getTransactionResponse().getErrors().getError()[0].getErrorCode();
                        let text = response.getTransactionResponse().getErrors().getError()[0].getErrorText();
                        res.json({
                            error: `${code}: ${text}`
                        });
                    } else {
                        res.json({ error: 'Transaction failed.' });
                    }
                }    
            } else {
                if(response.getTransactionResponse() !== null && response.getTransactionResponse().getErrors() !== null){
                    let code = response.getTransactionResponse().getErrors().getError()[0].getErrorCode();
                    let text = response.getTransactionResponse().getErrors().getError()[0].getErrorText();
                    res.json({
                        error: `${code}: ${text}`
                    });
                } else {
                    let code = response.getMessages().getMessage()[0].getCode();
                    let text = response.getMessages().getMessage()[0].getText();
                    res.json({
                        error: `${code}: ${text}`
                    });
                }   
            }    

        } else {
            res.json({ error: 'No response.' });
        }
    });

If the transaction was successful, you will receive an email like the one shown below.

Source code

GitHub