Merchant initiated card payments

Card details can be tokenised to allow for the creation of merchant initiated payments. Merchant initiated payments can be useful in processing recurring payments such as subscriptions, or payments in instalments, without requiring the payer to repeatedly enter card details.

To enable merchant initiated payments:

  1. Create a card token.
  2. (For each subsequent payment) create a new payment request
  3. use the 'paywithtoken' action to fulfil the payment request created in step 2.

Remember, when working with payment requests use a MERCHANT access token.

1. Generating a card token

Generating a card token is as easy as creating a payment request and setting the CardCreateToken field to true.

When the payer enters their card details to fulfil the payment request, a card payment response model is returned to the callback URL specified in the original payment request. The following fields allow creation of a merchant initiated transaction:

  • CustomerID
  • TransactionID

Step 3 below shows how to use these fields when submitting a payment using a card token.

2. Creating subsequent payment requests

A new payment request must be created for each merchant initiated payment. These payment requests should be created as shown in creating and managing payment requests, however the PaymentMethodTypes field should be set to cardtoken.

3. Submitting the payment

The card token payment can be submitted using the 'paywithtoken'. In the examples below:

  • CustomerID is the value returned in step 1.
  • PreviousTransactionID is the value returned as TransactionID in step 1.
  • paymentRequestID is the ID of the payment request created in step 2.
using System.Net.Http.Json;
using System.Text;

const string baseUrl = "<<SANDBOX_URL>>paymentrequests";

// Payment requests use MERCHANT tokens (remember to keep these safe and secure).
var jwtToken = Environment.GetEnvironmentVariable("NOFRIXION_MERCHANT_TOKEN");

var client = new HttpClient();

client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwtToken}");

// Specify the payment request ID
string paymentRequestID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";

var paymentData = new Dictionary<string, string>();
paymentData.Add("CustomerID", "D95D.....................A378B");
paymentData.Add("PaymentInitiator", "Customer");
paymentData.Add("MerchantStandardReason", "None");
paymentData.Add("CommerceIndicator", "internet");
paymentData.Add("PreviousTransactionID", "123456789012345");

try
{
    HttpResponseMessage response = await client.PostAsync($"{baseUrl}/{paymentRequestID}/card/paywithtoken", new FormUrlEncodedContent(paymentData));
    if (response.IsSuccessStatusCode)
    {
        // The card payment response model will be returned in JSON object.
        Console.WriteLine(await response.Content.ReadFromJsonAsync<CardResponse>());
    }
    else
    {
        // HTTP error codes will return a MoneyMoov API problem object
        Console.WriteLine(await response.Content.ReadFromJsonAsync<ApiProblem>());
    }
}
catch (Exception e)
{
    Console.WriteLine($"Error: {e.Message}");
}

// type definitions for response data
record CardResponse(string authorizedAmount, string currencyCode, string responseCode, string status,
                string requestID, string transactionID, CardError error, string payerAuthenticationUrl,
                string payerAuthenticationAccessToken, int payerAuthenticationWindowWidth,
                int payerAuthenticationWindowHeight );

record CardError(int errorCode, string id, string message, string reason, string status, string[] details, string rawResponse);
record ApiProblem(string type, string title, int status, string detail);
// These modules allow the code to run on Node.js, they aren't required if running in a browser.
const fetch = require('cross-fetch');
const FormData = require('form-data');

// Remember, the JWT access token must be securely store - this example uses an environment variable
const jwtToken = process.env.NOFRIXION_MERCHANT_TOKEN;

const baseUrl = '<<SANDBOX_URL>>paymentrequests';

var paymentRequestID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';

// Example form data
var form = new FormData();
form.append('CustomerID', 'D95D.....................A378B');
form.append('PaymentInitiator', 'Customer');
form.append('MerchantStandardReason', 'None');
form.append('CommerceIndicator', 'internet');
form.append('PreviousTransactionID', '123456789012345');

var options = {
    method: 'POST',
    headers: {
        Accept: 'application/json',
        Authorization: 'Bearer ' + jwtToken
    },
    body: form
};

fetch(`${baseUrl}/${paymentRequestID}/card/paywithtoken`, options)
    .then(response => response.json())
    // Card payment response model will be returned in JSON response object.
    .then(responseJson => console.log(responseJson))
    .catch(err => console.error(err));
# The 'requests' library for Python can be used to make calls to the MoneyMoov API in
# popular python frameworks such as Django and Flask.
import requests
import os

# Remember, the JWT access token must be securely stored ('os' module above allows storage in environment variable)
# ... and when dealing with payment requests, use a MERCHANT token!
jwtToken = os.environ['NOFRIXION_MERCHANT_TOKEN']

baseUrl = "<<SANDBOX_URL>>paymentrequests"

# the ID of the payment request with PaymentMethodTypes of "cardtoken".
paymentRequestID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

headers = {
    "Accept": "application/json",
    "Authorization": f"Bearer {jwtToken}"
}

paymentDetails = {
    "CustomerID": "D95D.....................A378B",
    "PaymentInitiator": "Customer",
    "MerchantStandardReason": "None",
    "CommerceIndicator": "internet",
    "PreviousTransactionID": "123456789012345"
}

try:
    response = requests.request("POST", f"{baseUrl}/{paymentRequestID}/card/paywithtoken", headers=headers, data=paymentDetails)

    if response.ok:
        #   On success, the API returns the card payment response model 
        print(response.json())
    else:
        # If not OK, response contains MoneyMoov problem (https://docs.nofrixion.com/reference/error-messages)
        print(response.json())

except Exception as ex:
    print(ex)