# Migrating from Airwallex

> Migrate from the Airwallex API to Qualy: Airwallex Payment Links, Payment Intents, Customers, Global Accounts, FX conversions, payouts and webhooks mapped to Qualy.

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](https://v1-spec.qualyhq.com/#post-/v1/contacts/create) | Names go in a nested `profile`. |
| Payment Link | Payment intent link (one-off) or service + template (reusable) | See [Payment links](/docs/guides/payment-links.md). |
| Hosted Payment Page / Drop-in | Payment portal | Cards, bank transfers and local methods. |
| Payment Intent + Payment Attempt | [Payment intent](/docs/guides/creating-payment-intents.md) + 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](https://v1-spec.qualyhq.com/#post-/v1/fields/create) 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](https://v1-spec.qualyhq.com/#post-/v1/partnerships/create) + [payment splits](/docs/guides/creating-payment-splits.md) | Payouts are created by Qualy when a payment settles. |
| Refund | [Refund](/docs/guides/issuing-transaction-refunds.md) | — |
| `x-on-behalf-of` (connected accounts) | `X-TENANT-ID` | See [Multi-tenancy](/docs/tenants.md). |

---

## 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.

```bash
curl https://api.qualyhq.com/v1/payment-intents \
  -H 'Authorization: ApiKey your-api-key-here' \
  -H 'X-TENANT-ID: your-tenant-id-here'
```

> **Warning — 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

**Airwallex**

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

**Qualy (JavaScript)**

```javascript
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](/docs/guides/payment-links.md#reusable-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:

```javascript
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](/docs/guides/collecting-payments.md).

---

## 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.

```javascript
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`](/docs/guides/creating-payment-splits.md#previewing-payouts). For many payments at once, see [Bulk payment splits](/docs/guides/bulk-payment-splits.md).

---

## 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](/docs/webhooks/events.md) for payloads.
