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 typeDescription
ad-hocFor payments that are not part of payment plan, such as specific one-off fees.
installmentFor payments part of a payment plan.
stepReserved use.
portalUsed by Qualy when a contact uses Qualy's to purchase a service from the Contact portal.
ecommerceUsed 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.

Settlement currency and FX (Currency exchange)

Sometimes you may want to create a payment in a specific currency (e.g. AUD) but you want the end-user to pay in another (e.g. EUR), this is useful in many cases, especially when you want Qualy to pay the suppliers in the original currency, and to convert it automatically at the time of payout.

Set the property settlementCurrency as your desired currency. When the end-user tries to pay, it will only display the payment options of the specificed settlementCurrency.

Qualy will automatically fetch the most up-to-date FX rate, but if you want to specify a static FX rate, you can add the property quote when creating a Payment Intent, here's an of a Payment Intent creation with the quote specified:

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
        }
      ],
      "quote": {
        "sourceCurrency": "AUD",
        "targetCurrency": "EUR",
        "sourceAmount": 135000,
        "targetAmount": 67500,
        "rate": 0.5,
        "markup": {
          "type": "percentage-on-amount",
          "amount": 0.3
        }
      }
    }),
  });

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

Creating a payment plan (Orders)

If you are creating a payment that's part of a payment plan, or that is an installment, you should associate this payment with an "Order". Orders are how Qualy handles when services are sold, and they will be paid in multiple payments.

It's possible to create a payment with the property intentType using the value installment without an Order. We do not recommend, as users will get confused when extracting reports.

How to create a payment plan

The steps above should be follow just as usual, but you will need to add a new property.

  1. Create an Order: follow the guide Creating an Order
  2. Create an Order Item: follow the guide Creating an Order Item
  3. With the resulting _id of both Order and Order Item, add the following properties when creating a PaymentIntent: order and orderItems (array).

Here's an example of a Payment Intent creation payload that includes the Orders and Order Items properties.

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",
      "order": "4123b9cc1b3228074l705433b",
      "orderItems": ["677d24f98bd3d800483852f2"],
      "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);
}

For more information on how to create an Order and Order Items, following the following guide: Creating Orders.

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);
}
Previous
Errors