Non-3DS Payment Gateway Integration with First Atlantic Commerce

Introduction

First Atlantic Commerce (FAC) stands as a premier online payment gateway and provider of fraud management solutions. Established in 1998 and based in Bermuda, FAC offers multi-currency payment processing and risk management services to Internet merchants and acquiring banks throughout the Caribbean and Central America.

Key Features

  1. Secure, real-time, multi-currency credit card processing.
  2. PCI-DSS compliant gateway.
  3. Fully customizable to the merchant's brand.
  4. Reduced shopping cart abandonment for increased sales conversion.
  5. Simple integration.
  6. Lower PCI costs.

How Do Payment Gateways and Merchant Accounts Work together?

Though the terminology might sound complex, the synergy between merchant accounts and payment gateways is crucial for smooth payment transactions. Here is a straightforward explanation of how they work together.

Step 1. A customer makes a payment, and the payment gateway securely forwards the payment information to the payment processor, which then handles the payment operation.

Step 2. The payment processor checks these details with the customer's bank to verify the transaction's authenticity.

Step 3. Once verified, the sanctioned payments are temporarily held in the merchant account before moving to the business's main bank account.

Step 4. The payment processor and merchant account provider rigorously review transactions to ensure precision and prevent fraud.

Step 5. After detailed verification, the funds are transferred from the merchant account to the business's bank account, completing the payment cycle.

You can apply for a merchant account of FAC from the Online Payment Gateway Application Form - First Atlantic Commerce

You can check API documentation PowertranzNon3DSAPI-V-2.0.pdf (firstatlanticcommerce.com)

Integration

First, create a .NET Web API project I've used .NET framework 6.0 you can use the same or your current LTS version.

First Atlantic Commerce API Project Structure

Create the Below Models inside the Model folder.

namespace FirstAtlanticCommerceAPI.Model
{
    public class AuthModel
    {
        public string? AuthorizationCode { get; set; }
        public string TransacctionIdentifier { get; set; }
        public decimal TotalAmount { get; set; }
        public string CurrencyCode { get; set; }
        public bool ThreeDSecure { get; set; }
        public Source Source { get; set; }
        public string OrderIdentifier { get; set; }
        public BillingAddress BillingAddress { get; set; }
        public bool AddressMatch { get; set; }
        public string? ExternalIdentifier { get; set; }
    }
    public class Source
    {
        public string CardPan { get; set; }
        public string CardCvv { get; set; }
        public string CardExpiration { get; set; }
        public string CardholderName { get; set; }
    }
    public class BillingAddress
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Line1 { get; set; }
        public string Line2 { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string PostalCode { get; set; }
        public string CountryCode { get; set; }
        public string EmailAddress { get; set; }
        public string PhoneNumber { get; set; }
    }
    public class ExtendedData
    {
        public int PaymentID { get; set; }
        public int UID { get; set; }
        public DateTime TxnDate_Time { get; set; }
    }
    public class PaymentData
    {
        public int PaymentID { get; set; } = 0;
        public int uid { get; set; }
        public string? PaymentTo { get; set; }
        public string? PaymentFrom { get; set; }
        public string? TransactionIdentifier { get; set; }
        public decimal? TotalAmount { get; set; }
        public DateTime TxnDateTime { get; set; }
        public bool Approved { get; set; }
        public string? ResponseMessage { get; set; }
    }
    public class PaymentModel
    {
        public decimal Amount { get; set; }
        public string CardNumber { get; set; }
        public string? CardHolder { get; set; }
        public string CardCode { get; set; }
        public string Month { get; set; }
        public string Year { get; set; }
    }
    public class PaymentResponse
    {
        public int? TransactionType { get; set; }
        public bool Approved { get; set; }
        public string? AuthorizationCode { get; set; }
        public string? TransactionIdentifier { get; set; }
        public decimal? TotalAmount { get; set; }
        public string? CurrencyCode { get; set; }
        public string? RRN { get; set; }
        public string? CardBrand { get; set; }
        public string? IsoResponseCode { get; set; }
        public string? ResponseMessage { get; set; }
        public string? OrderIdentifier { get; set; }
        public string? ExternalIdentifier { get; set; }
    }
}

Description

  1. AuthModel will be used to initiate authorization it has Source and BillingAddress Models as per FAC API required JSON format.
  2. ExtendedData Model is just a custom model if we want to send our app unique IDs to track payments.
  3. PaymentData Model will be used to save or update payment records in our database.
  4. PaymentModel will be used to pass Source data for FAC authorization.
  5. PaymentResponse Model will be used to Store FAC's Response from both Authorization and Capture Endpoints.

Create PaymentController inside the Controller folder.

using FirstAtlanticCommerceAPI.Model;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Net;
namespace FirstAtlanticCommerceAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PaymentController : Controller
    {
        readonly string facBaseUrl = "https://staging.ptranz.com/api/";  //Stage
                                   //"https://gateway.ptranz.com/api/";  //Prod
        readonly string PowerTranzId = "00000000";                   //your powertranz id
        readonly string PowerTranzPassword = "encrypted password";   //your powertranz password

        HttpClient httpClient = new HttpClient();
        HttpResponseMessage httpResponse = new(HttpStatusCode.InternalServerError);

        //Here we will create our Authorization and Capture Endpoints
    }
}

Description

PaymentController is our API controller inside we will be integrating FAC Endpoints calls. I've created some properties to store FAC base URL, PowerTranzId, and PowerTranzPassword you can store these credentials in your appsettings.json file and access from there. Below these properties, I've created created HttpClient class object to make FAC API calls and a HttpResponseMessage to receive responses.

Create /auth Endpoint.

[HttpPost]
[Route("/auth")]
public async void MakePayments(PaymentModel paymentModel)
{
    try
    {
        PaymentData initiatPayment = new PaymentData()
        {
            TransactionIdentifier = Guid.NewGuid().ToString(),
            PaymentFrom = paymentModel.CardHolder ?? string.Empty,
            PaymentTo = "Merchant Name",
            TotalAmount = paymentModel.Amount,
            TxnDateTime = DateTime.Now,
            Approved = false,
            ResponseMessage = "Transaction Pending",
            uid = 1,    //application logged-in user id to map payment with
        };
        //Here you can save the pending transaction in DB function or procedure and get unique payment id.
        //ExtendedData extendedData = await SavePaymentTrasaction(initiatPayment);

        //e.g.
        ExtendedData extendedData = new ExtendedData()
        {
            UID = 1,
            PaymentID = 1,
            TxnDate_Time = DateTime.Now,
        };
        var serializerSettings = new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore
        };
        var customData = JsonConvert.SerializeObject(extendedData, serializerSettings);

        AuthModel authModel = new AuthModel()
        {
            TransacctionIdentifier = initiatPayment.TransactionIdentifier,
            TotalAmount = paymentModel.Amount,
            CurrencyCode = "840",   //for USD
            ThreeDSecure = false,
            Source = new Source()
            {
                CardPan = paymentModel.CardNumber,
                CardholderName = initiatPayment.PaymentFrom,
                CardCvv = paymentModel.CardCode,
                CardExpiration = paymentModel.Year.Length == 4 ? paymentModel.Year.Substring(2, 2) + paymentModel.Month
                                                               : paymentModel.Year + paymentModel.Month.PadLeft(2, '0')
            },
            BillingAddress = new BillingAddress()
            {
                FirstName = "John",//logged in user fname
                LastName = "Doe",//logged in user lname
                Line1 = string.Empty,
                Line2 = string.Empty,
                City = string.Empty,
                State = string.Empty,
                PostalCode = string.Empty,
                CountryCode = string.Empty,
                EmailAddress = "[email protected]",
                PhoneNumber = "0000000000"
            },
            AddressMatch = false,
            OrderIdentifier = Guid.NewGuid().ToString(),
            ExternalIdentifier = customData
        };
        if (httpClient.BaseAddress == null)
        {
            httpClient.BaseAddress = new Uri(facBaseUrl);
            // Configure HttpClient with authentication credentials
            httpClient.DefaultRequestHeaders.Add("PowerTranz-PowerTranzId", PowerTranzId);
            httpClient.DefaultRequestHeaders.Add("PowerTranz-PowerTranzPassword", PowerTranzPassword);
        }
        PaymentResponse paymentResponse = new();
        //Payment Auth Start
        httpResponse = await httpClient.PostAsJsonAsync("auth", authModel);
        _ = httpResponse.EnsureSuccessStatusCode();
        var authContent = await httpResponse.Content.ReadAsStringAsync();
        paymentResponse = JsonConvert.DeserializeObject<PaymentResponse>(authContent) ?? paymentResponse;
        if (paymentResponse.IsoResponseCode == "00")    //successfully authorized
        {
            // Save Response in DB
            var PaymentData = new PaymentData()
            {
                TransactionIdentifier = paymentResponse.TransactionIdentifier,//this is unique generated by fac needed for later capture
                PaymentFrom = paymentModel.CardHolder ?? string.Empty,
                PaymentTo = "Merchant Name",
                TotalAmount = paymentModel.Amount,
                TxnDateTime = DateTime.Now,
                Approved = paymentResponse.Approved,
                ResponseMessage = paymentResponse.ResponseMessage,
                uid = extendedData.UID,
                PaymentID = extendedData.PaymentID
            };
            //Update Payment status in DB
            //bool authStatus = await UpdatePaymentTrasaction(PaymentData);
        }
        else if (paymentResponse.IsoResponseCode == "05")   //Card Denied
        {
            //Optional : Send email to user  that card was denied
            //_ = SendDeniedEmailAsync(authmodel, paymentResponse.ResponseMessage);
        }
        //Add other response status if needed all status codes available in fac pdf doc
        //Payment Auth End
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

Description

Here in the "/auth" POST Endpoint we will get PaymentModel data from the Request Body and create PaymentData Model to initiate the "Pending" Transaction in our data if anything fails we can track the transaction in our Database I've not mentioned DB Process here but added comment, you can add your Stored procedure or DB function code.

After this, I've created an object of the custom model in which I'll be sending the user ID and payment ID that was initiated as pending in DB. Then Create an AuthModel object that contains all required values and add Request header key values for authentication.

At the last call the endpoint with auth model object as request body. This will return the response read and deserialize it to check the response. FAC has its list of response codes i've used only two you can add more if you need. These response codes are mentioned in the PDF link that I mentioned above. You can send a failed transaction email to the user or admin if the response code is not returned as a success. If the response is succeeded you can save it to your DB as auth completed. This transaction will be initiated in FAC for later capture you can call the capture Endpoint of FAC just after it or you can have provision for admin capture.

Note: Capture could be done for authorized transactions in the limited time that FAC allows.

Create /capture Endpoint.

[HttpPost]
[Route("/capture")]
public async void CapturePayments(string TransactionIdentifier, decimal TotalAmount)
{
    try
    {
        // Capture in FAC
        if (httpClient.BaseAddress == null)
        {
            httpClient.BaseAddress = new Uri(facBaseUrl);
            // Configure HttpClient with authentication credentials
            httpClient.DefaultRequestHeaders.Add("PowerTranz-PowerTranzId", PowerTranzId);
            httpClient.DefaultRequestHeaders.Add("PowerTranz-PowerTranzPassword", PowerTranzPassword);
        }
        PaymentResponse captureResponse = new();
        //Payment Capture Start
        var captureData = new
        {
            TransactionIdentifier = TransactionIdentifier,   // transaction ID
            TotalAmount = TotalAmount    // total amount
        };
        // Serialize captureData to JSON
        var jsonData = JsonConvert.SerializeObject(captureData);
        // Create the HttpContent with the JSON data
        var jsonContent = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
        httpResponse = await httpClient.PostAsync("capture", jsonContent);
        _ = httpResponse.EnsureSuccessStatusCode();
        var captureContent = await httpResponse.Content.ReadAsStringAsync();
        captureResponse = JsonConvert.DeserializeObject<PaymentResponse>(captureContent) ?? captureResponse;
        if (httpResponse.StatusCode == HttpStatusCode.OK && captureResponse.IsoResponseCode == "00")
        {
            // Capture in DB
            //Here you can save the success transactrion in DB function or procedure.
            //bool captureStatus = await UpdatePaymentTrasaction(PaymentData);
        }
        //Based on captureResponse send reciept on success
        //send reciept on email integration
        //_ = SendRecieptAsync(authModel); 

        //Payment Capture End
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

Description

Here in the "/capture" POST Endpoint, we need to pass the transaction ID that was generated before by authorization for some amount. You need to set HttpClient objects request header key values for authentication, this will allow you to call FAC's Capture Endpoint. Create a local object with Keys TransactionIdentifier and TotalAmount and convert it to JSON to pass it in the capture's Request Body. After calling FAC's "capture" Endpoint you will receive their response JSON read and Deserialize it to check whether it succeeded or failed.

If the Capture Response is "00" it means the request is completed. FAC does not send any Receipt of the transaction you can create your template in SendGrid and send it to the user via email.

That's is you have completed the FAC's payment process you can check your merchant dashboard related to the transaction.

Conclusion

First Atlantic Commerce (FAC), a leading online payment gateway based in Bermuda, offers secure, real-time, multi-currency credit card processing and fraud management solutions. This guide details how to integrate FAC's payment gateway using .NET, covering essential models, authorization, and capture endpoints for seamless payment transactions. Here is the Project repository link - FirstAtlanticCommerceAPI that contains this article's source code you can clone and use it.