Getting started
Quick start
This guide walks you through the complete flow of creating and collecting a payment with the Qualy API — from authentication to checkout. By the end, you'll have a working integration that creates a payment intent and collects funds.
Overview
A typical payment flow follows these steps:
- Authenticate — set up your API key and tenant ID.
- Create a contact — the person who will pay.
- Create a payment intent — define the amount, currency, and line items.
- Collect the payment — redirect to Qualy's portal or use the API directly.
- Monitor with webhooks — track when the payment succeeds or fails.
Step 1: Set up authentication
All requests require an API key and a tenant ID. If you haven't created an API key yet, follow the API keys guide. To find your tenant ID, see the tenants guide.
Every example below uses these headers:
const headers = {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
'X-TENANT-ID': 'your-tenant-id-here',
};
See: Authentication
Step 2: Create a contact
A contact is the person who will receive the payment intent and make the payment. You only need to create them once.
const contactResponse = await fetch('https://api.qualyhq.com/v1/contacts/create', {
method: 'POST',
headers,
body: JSON.stringify({
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phone": "+61412345678"
}),
});
const contact = await contactResponse.json();
console.log('Contact ID:', contact._id); // e.g. "656b9ef1a3258074a705433b"
Step 3: Create a payment intent
Now create a payment intent with the contact, amount, currency, and line items:
const paymentResponse = await fetch('https://api.qualyhq.com/v1/payment-intents/create', {
method: 'POST',
headers,
body: JSON.stringify({
"intentType": "ad-hoc",
"contact": "656b9ef1a3258074a705433b",
"dueAt": "2026-05-10T14:26:07.369Z",
"currency": "AUD",
"items": [
{
"name": "Tuition fee",
"description": "",
"category": "Course",
"amount": 100000
}
]
}),
});
const paymentIntent = await paymentResponse.json();
console.log('Payment Intent ID:', paymentIntent._id);
console.log('Payment link:', paymentIntent.links.short);
Amounts are in cents
All amounts in Qualy are in minor currency units (cents). So 100000 means $1,000.00 AUD.
Step 4: Collect the payment
You have two options to collect the payment:
Option A: Payment portal (recommended)
The simplest approach. Redirect your contact to Qualy's hosted payment page using the links URL returned in the payment intent response:
// Redirect the contact to this URL
const paymentUrl = paymentIntent.links.short;
// e.g. "https://qualyhqpay.com/abc123"
Qualy handles method selection, payer verification, and processing. This is required for card payments.
Option B: Direct API
For non-card methods (PIX, Boleto, PayID, bank transfers), call the sign endpoint to get payment details and display them in your own UI:
const signResponse = await fetch('https://api.qualyhq.com/v1/payment-gateways/sign', {
method: 'POST',
headers,
body: JSON.stringify({
gateway: 'zai',
signatureType: 'ZAI_PAYID',
entity: 'payment-intent',
paymentIntentId: paymentIntent._id,
contact: {
contactId: contact._id,
},
payer: {
type: 'myself',
email: 'john.doe@example.com',
profile: {
firstName: 'John',
lastName: 'Doe',
phone: '+61412345678',
},
},
}),
});
const paymentDetails = await signResponse.json();
console.log('PayID address:', paymentDetails.email);
See: Collecting payments
Step 5: Monitor with webhooks
Set up webhooks to get notified when a payment succeeds or fails. After a contact completes the payment, Qualy sends a webhook event to your server.
You can also check the payment status via the API:
const statusResponse = await fetch(
`https://api.qualyhq.com/v1/payment-intents/${paymentIntent._id}`,
{
method: 'GET',
headers,
}
);
const status = await statusResponse.json();
console.log('Payment status:', status.status);
See: Setting up webhooks
Complete example
Here's the entire flow in one script:
const API = 'https://api.qualyhq.com/v1';
const headers = {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
'X-TENANT-ID': 'your-tenant-id-here',
};
// 1. Create a contact
const contact = await fetch(`${API}/contacts/create`, {
method: 'POST', headers,
body: JSON.stringify({
firstName: 'John', lastName: 'Doe',
email: 'john.doe@example.com', phone: '+61412345678',
}),
}).then(r => r.json());
// 2. Create a payment intent
const paymentIntent = await fetch(`${API}/payment-intents/create`, {
method: 'POST', headers,
body: JSON.stringify({
intentType: 'ad-hoc',
contact: contact._id,
dueAt: '2026-05-10T14:26:07.369Z',
currency: 'AUD',
items: [
{ name: 'Tuition fee', description: '', category: 'Course', amount: 100000 },
],
}),
}).then(r => r.json());
// 3. Send the payment link to your contact
console.log('Payment link:', paymentIntent.links.short);
// 4. Check payment status
const status = await fetch(`${API}/payment-intents/${paymentIntent._id}`, {
method: 'GET', headers,
}).then(r => r.json());
console.log('Status:', status.status);
Next steps
- Set up webhooks to track payment events in real time.
- Learn about payment collection methods for PIX, Boleto, PayID, and more.
- Use orders for payment plans with multiple installments.
- Handle errors gracefully in your integration.
- Explore the full API Reference.