Migration guides
Migrating from Airwallex
Airwallex and Qualy both lean on multi-currency collection, so most of your integration maps one to one. The big difference is what happens after the money arrives: in Qualy you declare who gets paid (schools, agents, suppliers) on the payment itself, and Qualy pays them out.
Concept map
| Airwallex | Qualy | Notes |
|---|---|---|
| Customer | Contact | Names go in a nested profile. |
| Payment Link | Payment intent link (one-off) or service + template (reusable) | See Payment links. |
| Hosted Payment Page / Drop-in | Payment portal | Cards, bank transfers and local methods. |
| Payment Intent + Payment Attempt | Payment intent + transactions | Each attempt or receipt is a transaction on the payment. |
merchant_order_id | number | Your own reference for the payment (letters, digits, ., _, -). |
metadata | custom | Visible once a custom field with the same name exists. |
| Conversions / FX quotes | settlementCurrency | The student pays in their currency; you invoice in yours. |
| Global Accounts (receiving bank details) | Bank transfer methods on the payment | Signing a bank method returns the account the student pays into, reconciled to that payment. |
| Beneficiaries + Transfers (payouts) | Partnerships + payment splits | Payouts are created by Qualy when a payment settles. |
| Refund | Refund | — |
x-on-behalf-of (connected accounts) | X-TENANT-ID | See Multi-tenancy. |
Authentication
Airwallex exchanges a client id and API key for a short-lived token. Qualy needs no token exchange: send the API key on every request.
curl https://api.qualyhq.com/v1/payment-intents \
-H 'Authorization: ApiKey your-api-key-here' \
-H 'X-TENANT-ID: your-tenant-id-here'
Amounts change unit
Airwallex takes decimal amounts (1350.00). Qualy takes minor units (135000). Multiply by 100 when you port your amount fields.
Payment Links
const res = await fetch('https://api.airwallex.com/api/v1/pa/payment_links/create', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
amount: 1350.0,
currency: 'AUD',
title: 'Tuition fee',
reusable: false,
}),
});
const res = 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',
number: 'INV-2026-0042', // your own reference
contact: 'john.doe@example.com',
currency: 'AUD',
dueAt: '2026-12-01T00:00:00.000Z',
items: [{ name: 'Tuition fee', amount: 135000 }],
}),
});
const { data: payment } = await res.json();
console.log(payment.links.short);
This is a one-off link for one student. For a reusable: true Airwallex link, use a public service with a price template instead. See Payment links.
Collecting in the student's currency
With Airwallex you collect in one currency and convert. In Qualy you invoice in your currency and let the student pay in theirs:
body: JSON.stringify({
intentType: 'ad-hoc',
contact: 'joao@example.com',
currency: 'AUD', // what you invoice
settlementCurrency: 'BRL', // what the student pays in (optional)
items: [{ name: 'Tuition fee', amount: 135000 }],
}),
Leave settlementCurrency out and the student chooses on the portal. The currency decides which local methods appear (PIX and boleto for BRL, PayID for AUD, and so on). See Collecting payments.
Payouts → splits
Instead of creating a Transfer to a Beneficiary after the money arrives, attach splits to the payment. Each partnership has its bank details on file; Qualy pays them once the student's payment settles.
await fetch('https://api.qualyhq.com/v1/payment-splits/create', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'ApiKey your-api-key-here',
'X-TENANT-ID': 'your-tenant-id-here',
},
body: JSON.stringify({
type: 'percentage-on-amount',
currency: 'AUD',
amount: 40500,
percentage: 0.3,
partnership: 'usyd',
contact: 'john.doe@example.com',
paymentIntent: '661e9bbfe0eb901d6b2f2670',
item: '661e9bc0e0eb901d6b2f2682',
}),
});
To see the payouts first, use POST /v1/payment-splits/preview. For many payments at once, see Bulk payment splits.
Webhooks
| Airwallex event | Qualy event |
|---|---|
payment_intent.created | paymentIntents.create |
payment_intent.succeeded | paymentIntents.update with status: "paid-full" |
payment_attempt.* | transactions.create / transactions.update |
refund.* | transactions.create (transactionType: "refund") |
payout.transfer.* | splitIntents.update |
See Webhook events for payloads.