Implementation guides
Creating a payment intent
Qualy's API provides robust functionality for creating payments, allowing developers to implement a wide range of payment scenarios. This guide will take you through the process step by step, starting with a basic example and gradually introducing more complex payment scenarios.
Before you start
You need to have a Contact _id
to create a Payment Intent, use the Contact API to create or retrieve a Contact.
Creating a payment
To create a payment on Qualy, you will have to use the Payment Intent API.
When you create the Payment Intent, you can specify options like the amount, currency, and more:
try {
const response = await fetch('https://api.qualyhq.com/v1/payment-intents/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
'X-TENANT-ID': 'your-tenant-id-here',
},
body: JSON.stringify({
"intentType": "ad-hoc",
"contact": "656b9ef1a3258074a705433b",
"dueAt": "2025-05-10T14:26:07.369Z",
"tax": "456b9ff1b3258074l705433b"
"currency": "AUD",
"items": [
{
"name": "Tuition fee",
"description": "",
"category": "Course",
"amount": 100000
},
{
"name": "Material fee",
"description": "",
"category": "Course",
"amount": 10000
},
{
"name": "Enrollment fee",
"description": "",
"category": "Course",
"amount": 25000
}
],
}),
});
if (response.ok) {
const data = await response.json();
console.log(data);
} else {
throw new Error(`Request failed with status: ${response.status}`);
}
} catch (error) {
console.error(error);
}
Intent types
Payment intents can have different types. The intentType
property helps customers in their reporting and analytics activities, and it's currently not used in any other feature. Make sure to select the correct intentType
when creating a payment.
A quick note
While Qualy supports many types of intentType
values, as a user of the API, you may probably want to use either ad-hoc
or installment
as other values are used for other purposes. If you believe you have a valid use-case, feel free to choose a different value.
Intent type | Description |
---|---|
ad-hoc | For payments that are not part of payment plan, such as specific one-off fees. |
installment | For payments part of a payment plan. |
step | Reserved use. |
portal | Used by Qualy when a contact uses Qualy's to purchase a service from the Contact portal. |
ecommerce | Used by Qualy when purchase is made via Qualy, and the contact didn't previously existed in the tenant's account. |
Tax calculation
Qualy's v1
API calculates the payment's tax based on the total amount. If you need to apply different tax rates based on the payment item, you must create different payments.
Check our Tax API to retrieve, and create taxes. Use the created tax _id
in the payment creation to get the tax calculated automatically by Qualy. Learn more about Tax calculation in our dedicated guide.
Settlement currency and FX (Currency exchange)
Sometimes you may want to create a payment in a specific currency (e.g. AUD) but you want the end-user to pay in another (e.g. EUR), this is useful in many cases, especially when you want Qualy to pay the suppliers in the original currency, and to convert it automatically at the time of payout.
Set the property settlementCurrency
as your desired currency. When the end-user tries to pay, it will only display the payment options of the specificed settlementCurrency
.
Qualy will automatically fetch the most up-to-date FX rate, but if you want to specify a static FX rate, you can add the property quote
when creating a Payment Intent, here's an of a Payment Intent creation with the quote
specified:
try {
const response = await fetch('<https://api.qualyhq.com/v1/payment-intents/create>', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
'X-TENANT-ID': 'your-tenant-id-here',
},
body: JSON.stringify({
"intentType": "ad-hoc",
"contact": "656b9ef1a3258074a705433b",
"dueAt": "2025-05-10T14:26:07.369Z",
"tax": "456b9ff1b3258074l705433b"
"currency": "AUD",
"items": [
{
"name": "Tuition fee",
"description": "",
"category": "Course",
"amount": 100000
},
{
"name": "Material fee",
"description": "",
"category": "Course",
"amount": 10000
},
{
"name": "Enrollment fee",
"description": "",
"category": "Course",
"amount": 25000
}
],
"quote": {
"sourceCurrency": "AUD",
"targetCurrency": "EUR",
"sourceAmount": 135000,
"targetAmount": 67500,
"rate": 0.5,
"markup": {
"type": "percentage-on-amount",
"amount": 0.3
}
}
}),
});
if (response.ok) {
const data = await response.json();
console.log(data);
} else {
throw new Error(`Request failed with status: ${response.status}`);
}
} catch (error) {
console.error(error);
}
Creating a payment plan (Orders)
If you are creating a payment that's part of a payment plan, or that is an installment, you should associate this payment with an "Order". Orders are how Qualy handles when services are sold, and they will be paid in multiple payments.
It's possible to create a payment with the property intentType
using the value installment
without an Order. We do not recommend, as users will get confused when extracting reports.
How to create a payment plan
The steps above should be follow just as usual, but you will need to add a new property.
- Create an Order: follow the guide Creating an Order
- Create an Order Item: follow the guide Creating an Order Item
- With the resulting
_id
of both Order and Order Item, add the following properties when creating a PaymentIntent:order
andorderItems
(array).
Here's an example of a Payment Intent creation payload that includes the Orders and Order Items properties.
try {
const response = await fetch('https://api.qualyhq.com/v1/payment-intents/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
'X-TENANT-ID': 'your-tenant-id-here',
},
body: JSON.stringify({
"intentType": "ad-hoc",
"contact": "656b9ef1a3258074a705433b",
"dueAt": "2025-05-10T14:26:07.369Z",
"tax": "456b9ff1b3258074l705433b",
"order": "4123b9cc1b3228074l705433b",
"orderItems": ["677d24f98bd3d800483852f2"],
"currency": "AUD",
"items": [
{
"name": "Tuition fee",
"description": "",
"category": "Course",
"amount": 100000
},
{
"name": "Material fee",
"description": "",
"category": "Course",
"amount": 10000
},
{
"name": "Enrollment fee",
"description": "",
"category": "Course",
"amount": 25000
}
],
}),
});
if (response.ok) {
const data = await response.json();
console.log(data);
} else {
throw new Error(`Request failed with status: ${response.status}`);
}
} catch (error) {
console.error(error);
}
For more information on how to create an Order and Order Items, following the following guide: Creating Orders.
After the payment creation
After the payment is created, it is a best practice for your server to monitor webhooks to detect when the payment successfully completes or fails.
A PaymentIntent might have more than one Transaction object associated with it if there were multiple payment attempts, or if there were multiple partial payments. For each Transaction you can retrieve the status and details of the payment method used.
Sending payment reminders
Qualy will automatically send payment reminders via email and SMS based on the frequency selected using the Settings API. But if you want to send a payment reminder right away, you can use the Notifications API.
You will need the PaymentIntent
_id and the the Contact
_id to send the notification:
try {
const response = await fetch('https://api.qualyhq.com/v1/notifications/queue/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
'X-TENANT-ID': 'your-tenant-id-here',
},
body: JSON.stringify({
"category": "payment-reminder",
"comment": "",
"data": {},
"from": "user",
"paymentIntent": "6634f56c7dbbc16e07b5025e",
"recipientId": "6606ab8ffb9085579f1b5844",
"recipientType": "contact",
"templateId": "reminder"
}),
});
if (response.ok) {
const data = await response.json();
console.log(data);
} else {
throw new Error(`Request failed with status: ${response.status}`);
}
} catch (error) {
console.error(error);
}