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.
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);
}