Creating and managing payment requests

Pre-requisites

Merchant ID: This is the ID of the merchant that was created for you when you registered on the NoFrixion portal. You can get this ID by logging into NoFrixion portal and navigating to profile. You will see the list of merchants with their IDs under "Merchants". If you are using OAuth integration with MoneyMoov to get access token then you can use the Merchants API to get a list of merchants assigned to you.

Access token: For creating and managing payment requests, you have the option to use either a merchant token or an OAuth access token. Generally, a merchant token is preferred for these tasks, as payment requests are not considered highly sensitive operations.

Payment methods

When creating the payment request you can specify a list of payment methods that the payment request can receive money through. Following are the payment methods provided by MoneyMoov API:

  1. Card: Include card as a payment method if you want to accept card payments.
  2. Payment initiation services: Payment Initiation Services (PIS) are financial services that allow third-party providers to initiate payments directly from a customer's bank account on their behalf, subject to the customer's consent. This service is a key component of open banking, enabling seamless and secure direct bank-to-bank transfers without the need for traditional payment methods like credit cards or bank transfers. Include pisp as a payment method to accept direct bank payments.
  3. Lightning: Bitcoin Lightning Payment is a solution built on top of the Bitcoin blockchain, designed to enable faster and more cost-effective transactions. It creates a layer of payment channels that allow users to conduct numerous transactions off-chain, significantly reducing transaction times and fees, before eventually settling the final balance on the Bitcoin blockchain. Include lightning as a payment method to accept bitcoin lightning payments.
  4. Tokenised card: Based on your business needs, if you aim to accept recurring payments, consider utilizing a saved card token in your system. This process involves using a digital token, a secure stand-in for the card's actual details, to facilitate ongoing transactions. To enable automatic payments via this method, ensure you include cardtoken as the payment method, allowing transactions to be seamlessly processed using the previously stored card token.
  5. Wallets: Use this payment method specifically with the NoFrixion pay element. It instructs the pay element to show Apple Pay and Google Pay options. However, if you're not utilizing the NoFrixion pay element, simply including 'card' as a payment method suffices. This approach will also enable Apple Pay and Google Pay buttons, as these services are essentially card payments at their core. Include applePay,googlePay as payment methods to display buttons on the pay element.

Creating payment requests

The following example demonstrates the first step in receiving payments, creating a payment request.

📘

Good to know parameters

Callback URL: Once a payment is processed, or a notification of an inbound payment is received, a callback request will be made to this URL. Typically it will be the page on a your server that displays the results of the payment attempt. This is by default set to the NoFrixion hosted payment page's result page that displays details about all the payments received against the payment request. This will look something like "https://yourserver.com/paymentrequest/callback/{id}" where id is the payment request ID.

Failure callback URL (Optional): Optional callback URL for payment failures that can occur when the payer is redirected away from the payment page. Typically the payer is only sent away from the payment page for pay by bank attempts. If this URL is not set the payer will be redirected back to the original URL the payment attempt was initiated from.

Let's look at how to create a basic payment request.

using System.Net.Http.Json;

const string paymentRequestsAPIUrl = "https://api-sandbox.nofrixion.com/api/v1/paymentrequests";

var jwtToken =
    "<ACCESS_TOKEN>";

var client = new HttpClient();

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

var paymentRequest = new
{
    MerchantID = "<YOUR_MERCHANT_ID>",
    Amount = "19.00",
    Currency = "EUR",
    PaymentMethodTypes = "card,pisp,applePay,googlePay",
    Description = "API Payment request" // Optional
    // Optional if using NoFrixion hosted payment page's result page
    //CallbackUrl = "<YOUR_SERVER_CALLBACK_URL>",
    //FailureCallbackUrl = "YOUR_SERVER_FAILURE_CALLBACK_URL" //Optional
};

try
{
    // Post the data as JSON
    HttpResponseMessage response = await client.PostAsJsonAsync(paymentRequestsAPIUrl, paymentRequest);
    if (response.IsSuccessStatusCode)
    {
        // "Created" on success
        Console.WriteLine(response.StatusCode);
        // JSON object with payment request details will be in the response body
        Console.WriteLine(await response.Content.ReadFromJsonAsync<PaymentRequest>());
    }
    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 returned data
record PaymentRequest(
    string id,
    string merchantID,
    decimal amount,
    string currency,
    string customerID,
    string orderID,
    string paymentMethodTypes,
    string description,
    string pispAccountID,
    string shippingFirstName,
    string hostedPayCheckoutUrl,
    string shippingLastName,
    string shippingAddressLine1,
    string shippingAddressLine2,
    string shippingAddressCity,
    string shippingAddressCounty,
    string shippingAddressPostCode,
    string shippingAddressCountryCode,
    string shippingPhone,
    string shippingEmail,
    string baseOriginUrl,
    string callbackUrl,
    bool cardAuthorizeOnly,
    bool cardCreateToken,
    bool ignoreAddressVerification,
    bool cardIgnoreCVN);

record ApiProblem(string type, string title, int status, string detail);
const axios = require('axios');

const paymentRequestsAPIUrl = "https://api-sandbox.nofrixion.com/api/v1/paymentrequests";

const jwtToken = "<ACCESS_TOKEN>"; // Replace with your actual access token

// Set up the HTTP client headers
const config = {
    headers: {
        "Accept": "application/json",
        "Authorization": `Bearer ${jwtToken}`
    }
};

// Prepare the payment request data
const paymentRequest = {
    MerchantID: "<YOUR_MERCHANT_ID>", // Replace with your merchant ID
    Amount: "19.00",
    Currency: "EUR",
    PaymentMethodTypes: "card,pisp,applePay,googlePay",
    Description: "API Payment request" // Optional
};

// Make the POST request
axios.post(paymentRequestsAPIUrl, paymentRequest, config)
    .then(response => {
        if (response.status === 200 || response.status === 201) {
            // "Created" on success
            console.log("Status:", response.status);
            // JSON object with payment request details will be in the response body
            console.log("Payment Request:", response.data);
        }
    })
    .catch(error => {
        if (error.response) {
            // HTTP error codes will return a MoneyMoov API problem object
            console.log("Error:", error.response.data);
        } else {
            console.log("Error:", error.message);
        }
    });

// Assuming an error response format (ApiProblem)
// Adjust according to the actual API response structure

import requests

# URL for the payment requests API
payment_requests_api_url = "https://api-sandbox.nofrixion.com/api/v1/paymentrequests"

# Replace with your actual access token
jwt_token = "<ACCESS_TOKEN>"

# Set up the HTTP headers
headers = {
    "Accept": "application/json",
    "Authorization": f"Bearer {jwt_token}"
}

# Prepare the payment request data
payment_request = {
    "MerchantID": "<YOUR_MERCHANT_ID>",  # Replace with your merchant ID
    "Amount": "19.00",
    "Currency": "EUR",
    "PaymentMethodTypes": "card,pisp,applePay,googlePay",
    "Description": "API Payment request"  # Optional
}

# Make the POST request
try:
    response = requests.post(payment_requests_api_url, json=payment_request, headers=headers)
    
    if response.status_code in [200, 201]:
        # "Created" on success
        print("Status:", response.status_code)
        # JSON object with payment request details will be in the response body
        print("Payment Request:", response.json())
    else:
        # HTTP error codes will return a MoneyMoov API problem object
        print("Error:", response.json())
except Exception as e:
    print(f"Error: {e}")

# Assuming an error response format (ApiProblem)
# Adjust according to the actual API response structure

Many optional fields such as the billing and shipping addresses were omitted from the examples above, for full details see the API reference on the PaymentRequests POST action.

NoFrixion hosted payment page

Once the payment request is created, you can simply navigate to the link in hostedPayCheckoutUrl received in the response. This is the link to the NoFrixion hosted payment page where you can complete the payment through any of the payment methods specified in the payment request.

Viewing and updating payment requests

A payment request can be retrieved by specifying the payment request ID when using the paymentrequests/{id} GET action.

using System.Net.Http.Json;

const string paymentRequestsAPIUrl = "https://api-sandbox.nofrixion.com/api/v1/paymentrequests";

// Payment requests use MERCHANT tokens (remember to keep these safe and secure).
var jwtToken = "<ACCESS_TOKEN>";

var client = new HttpClient();

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

string paymentRequestID = "<PAYMENT_REQUEST_ID_TO_GET>";

try
{
    HttpResponseMessage response = await client.GetAsync($"{paymentRequestsAPIUrl}/{paymentRequestID}");
    if (response.IsSuccessStatusCode)
    {
        // returns a JSON object containing payment request details
        var paymentRequest = await response.Content.ReadFromJsonAsync<PaymentRequest>();
        Console.WriteLine(paymentRequest);
    }
    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 definition for response data
record PaymentRequest(string id, string merchantID, string hostedPayCheckoutUrl, decimal amount, string currency, string customerID,
                string orderID, string paymentMethodTypes, string description, string pispAccountID, string shippingFirstName,
                string shippingLastName, string shippingAddressLine1, string shippingAddressLine2, string shippingAddressCity,
                string shippingAddressCounty, string shippingAddressPostCode, string shippingAddressCountryCode,
                string shippingPhone, string shippingEmail, string baseOriginUrl, string callbackUrl, bool cardAuthorizeOnly,
                bool cardCreateToken, bool ignoreAddressVerification, bool cardIgnoreCVN, string pispRecipientReference);

record ApiProblem(string type, string title, int status, string detail);
const axios = require('axios');

const paymentRequestsAPIUrl = "https://api-sandbox.nofrixion.com/api/v1/paymentrequests";

// Payment requests use MERCHANT tokens (remember to keep these safe and secure).
const jwtToken = "<ACCESS_TOKEN>"; // Replace with your actual access token

// Setting up the headers for the HTTP client
const config = {
    headers: {
        "Accept": "application/json",
        "Authorization": `Bearer ${jwtToken}`
    }
};

const paymentRequestID = "<PAYMENT_REQUEST_ID_TO_GET>"; // Replace with your payment request ID

// Making the GET request
axios.get(`${paymentRequestsAPIUrl}/${paymentRequestID}`, config)
    .then(response => {
        if (response.status === 200) {
            // returns a JSON object containing payment request details
            console.log("Payment Request:", response.data);
        }
    })
    .catch(error => {
        if (error.response) {
            // HTTP error codes will return a MoneyMoov API problem object
            console.log("Error:", error.response.data);
        } else {
            console.log("Error:", error.message);
        }
    });

// Assuming an error response format (ApiProblem)
// Adjust according to the actual API response structure

import requests

# URL for the payment requests API
payment_requests_api_url = "https://api-sandbox.nofrixion.com/api/v1/paymentrequests"

# Payment requests use MERCHANT tokens (remember to keep these safe and secure).
jwt_token = "<ACCESS_TOKEN>"  # Replace with your actual access token

# Set up the HTTP headers
headers = {
    "Accept": "application/json",
    "Authorization": f"Bearer {jwt_token}"
}

# The payment request ID you want to get
payment_request_id = "<PAYMENT_REQUEST_ID_TO_GET>"  # Replace with your payment request ID

# Making the GET request
try:
    response = requests.get(f"{payment_requests_api_url}/{payment_request_id}", headers=headers)
    
    if response.status_code == 200:
        # Returns a JSON object containing payment request details
        print("Payment Request:", response.json())
    else:
        # HTTP error codes will return a MoneyMoov API problem object
        print("Error:", response.json())
except Exception as e:
    print(f"Error: {e}")

# Assuming an error response format (ApiProblem)
# Adjust according to the actual API response structure

Payment requests can be updated using the paymentrequests/{id} PUT action as follows:

using System.Net.Http.Json;

string paymentRequestIDToUpdate = "<PAYMENT_REQUEST_ID_TO_UPDATE>";

const string paymentRequestsAPIUrl = $"https://api-sandbox.nofrixion.com/api/v1/paymentrequests/{paymentRequestIDToUpdate}";

var jwtToken =
    "<ACCESS_TOKEN>";

var client = new HttpClient();

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

var paymentRequest = new
{
    MerchantID = "<YOUR_MERCHANT_ID>",
    Amount = "19.00",
    Currency = "EUR",
    PaymentMethodTypes = "card,pisp,applePay,googlePay",
    Description = "API Payment request" // Optional
    // Optional if using NoFrixion hosted payment page's result page
    //CallbackUrl = "<YOUR_SERVER_CALLBACK_URL>",
    //FailureCallbackUrl = "YOUR_SERVER_FAILURE_CALLBACK_URL" //Optional
};

try
{
    // Post the data as JSON
    HttpResponseMessage response = await client.PutAsJsonAsync(paymentRequestsAPIUrl, paymentRequest);
    if (response.IsSuccessStatusCode)
    {
        // "Created" on success
        Console.WriteLine(response.StatusCode);
        // JSON object with payment request details will be in the response body
        Console.WriteLine(await response.Content.ReadFromJsonAsync<PaymentRequest>());
    }
    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 returned data
record PaymentRequest(
    string id,
    string merchantID,
    decimal amount,
    string currency,
    string customerID,
    string orderID,
    string paymentMethodTypes,
    string description,
    string pispAccountID,
    string shippingFirstName,
    string hostedPayCheckoutUrl,
    string shippingLastName,
    string shippingAddressLine1,
    string shippingAddressLine2,
    string shippingAddressCity,
    string shippingAddressCounty,
    string shippingAddressPostCode,
    string shippingAddressCountryCode,
    string shippingPhone,
    string shippingEmail,
    string baseOriginUrl,
    string callbackUrl,
    bool cardAuthorizeOnly,
    bool cardCreateToken,
    bool ignoreAddressVerification,
    bool cardIgnoreCVN,
    string pispRecipientReference);

record ApiProblem(string type, string title, int status, string detail);
const axios = require('axios');

const paymentRequestIDToUpdate = "<PAYMENT_REQUEST_ID_TO_UPDATE>"; // Replace with your payment request ID to update

// Construct the URL for updating the payment request
const paymentRequestsAPIUrl = `https://api-sandbox.nofrixion.com/api/v1/paymentrequests/${paymentRequestIDToUpdate}`;

const jwtToken = "<ACCESS_TOKEN>"; // Replace with your access token

// Setting up the headers for the HTTP client
const config = {
    headers: {
        "Accept": "application/json",
        "Authorization": `Bearer ${jwtToken}`
    }
};

// Prepare the payment request data
const paymentRequest = {
    MerchantID: "<YOUR_MERCHANT_ID>", // Replace with your merchant ID
    Amount: "19.00",
    Currency: "EUR",
    PaymentMethodTypes: "card,pisp,applePay,googlePay",
    Description: "API Payment request", // Optional
    // Optional if using NoFrixion hosted payment page's result page
    // CallbackUrl: "<YOUR_SERVER_CALLBACK_URL>",
    // FailureCallbackUrl: "YOUR_SERVER_FAILURE_CALLBACK_URL" //Optional
};

// Make the PUT request to update the payment request
axios.put(paymentRequestsAPIUrl, paymentRequest, config)
    .then(response => {
        if (response.status === 200) {
            // "Created" on success
            console.log("Status:", response.status);
            // JSON object with payment request details will be in the response body
            console.log("Updated Payment Request:", response.data);
        }
    })
    .catch(error => {
        if (error.response) {
            // HTTP error codes will return a MoneyMoov API problem object
            console.log("Error:", error.response.data);
        } else {
            console.log("Error:", error.message);
        }
    });

// Assuming an error response format (ApiProblem)
// Adjust according to the actual API response structure

import requests

# The ID of the payment request to update
payment_request_id_to_update = "<PAYMENT_REQUEST_ID_TO_UPDATE>"  # Replace with the actual ID

# URL for the payment requests API
payment_requests_api_url = f"https://api-sandbox.nofrixion.com/api/v1/paymentrequests/{payment_request_id_to_update}"

# Payment requests use MERCHANT tokens (remember to keep these safe and secure).
jwt_token = "<ACCESS_TOKEN>"  # Replace with your actual access token

# Set up the HTTP headers
headers = {
    "Accept": "application/json",
    "Authorization": f"Bearer {jwt_token}"
}

# Prepare the payment request data
payment_request = {
    "MerchantID": "<YOUR_MERCHANT_ID>",  # Replace with your merchant ID
    "Amount": "19.00",
    "Currency": "EUR",
    "PaymentMethodTypes": "card,pisp,applePay,googlePay",
    "Description": "API Payment request"  # Optional
    # Optional if using NoFrixion hosted payment page's result page
    # "CallbackUrl": "<YOUR_SERVER_CALLBACK_URL>",
    # "FailureCallbackUrl": "YOUR_SERVER_FAILURE_CALLBACK_URL"  # Optional
}

# Making the PUT request
try:
    response = requests.put(payment_requests_api_url, json=payment_request, headers=headers)

    if response.status_code == 200:
        # "Created" on success
        print("Status:", response.status_code)
        # JSON object with payment request details will be in the response body
        print("Updated Payment Request:", response.json())
    else:
        # HTTP error codes will return a MoneyMoov API problem object
        print("Error:", response.json())
except Exception as e:
    print(f"Error: {e}")

# Assuming an error response format (ApiProblem)
# Adjust according to the actual API response structure

Web Hook

An optional HTTP web hook can be sent to your own server when a payment request is marked as fully paid. To receive the web hook the SuccessWebHookUrl field needs to be set to a valid URL.

The URL will be invoked as a GET request, i.e. there will be no request body. Two query parameters will be added to the URL. The first one will be "id" and will hold the payment request ID. The second one will be "orderid" and will hold the payment request OrderID, note the OrderID could be empty if it was not set when the payment request was created.

🚧

The recommended approach when receiving a success web hook is to use the "id" parameter to call the moneymoov get payment request endpoint to retrieve the full details of the payment request and check the status. Web hooks can be easily spoofed and should not be relied upon.