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

AirwallexQualyNotes
CustomerContactNames go in a nested profile.
Payment LinkPayment intent link (one-off) or service + template (reusable)See Payment links.
Hosted Payment Page / Drop-inPayment portalCards, bank transfers and local methods.
Payment Intent + Payment AttemptPayment intent + transactionsEach attempt or receipt is a transaction on the payment.
merchant_order_idnumberYour own reference for the payment (letters, digits, ., _, -).
metadatacustomVisible once a custom field with the same name exists.
Conversions / FX quotessettlementCurrencyThe student pays in their currency; you invoice in yours.
Global Accounts (receiving bank details)Bank transfer methods on the paymentSigning a bank method returns the account the student pays into, reconciled to that payment.
Beneficiaries + Transfers (payouts)Partnerships + payment splitsPayouts are created by Qualy when a payment settles.
RefundRefund—
x-on-behalf-of (connected accounts)X-TENANT-IDSee 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.


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

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 eventQualy event
payment_intent.createdpaymentIntents.create
payment_intent.succeededpaymentIntents.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.

Previous
From Stripe