Installment Payments

An installment payment plan allows customers to split a full payment into smaller amounts paid off at regular intervals over a fixed period. Omise provides a set of APIs that allow you to offer your customers this convenient payment method. Currently, you can offer payment plans of up to 36 monthly installments with a minimum total charge amount of 3000 THB (available term lengths and monthly minimum payments vary per card).

The following applies to merchants with accounts registered in Thailand.

Supported Cards

Credit Card Source type installment_term Lengths (months) Monthly Minimum (THB)
Krungsri installment_bay 3, 4, 6, 9, 10 500
Bangkok Bank installment_bbl 4, 6, 8, 9, 10 500
Krungsri First Choice installment_first_choice 3, 4, 6, 9, 10, 12, 18, 24, 36 300
Kasikorn Bank installment_kbank 3, 4, 6, 10 300
Krungthai Card (KTC) installment_ktc 3, 4, 5, 6, 7, 8, 9, 10 300

Payment Flow

Customers who choose to pay using an installment payment plan go through a redirect payment flow. This means that they are redirected from your website to a external, bank-operated webpage to authorize and confirm the payment amount. Upon completion, the customer is redirected back to your website.

The following screenshots demonstrate this payment flow. At checkout, the customer selects the installment payment method.

installment 1

After choosing the bank with which they would like to pay, the customer is redirected to the external, bank-operated webpage. The payment amount and any reference numbers should already be filled out on the authorization page.

installment 2

The customer only has to review the information and confirm the payment. Upon confirmation, the customer will be redirected to your website via the specified return_uri.

Implementation

Typically, creating an installment payment charge involves:

  1. Creating a new payment source using the Source API
  2. Creating a new charge using the Charge API and passing the id of the source created in the first step.

This assumes that the installment payment source creation (step 1) happens client-side (e.g. on a user's browser or mobile phone) using a public key while charge creation (step 2) happens server-side using a secret key. We recommend using Omise.js or one of our mobile SDKs to implement the client side of this flow.

Alternatively, if both the creation and charge of a source must happen server-side (not recommended), then the Charge API can be used to both create and charge the source.

Setting Who Pays Installment Interest

Before creating a source, you will need to set which party absorbs the interest for installment payments. This can either be you (Merchant) or the customer (Customer). This value can be set on the Dashboard.

Setting Zero Interest Installments

Creating a Source Client-side

Installment payment methods are implemented as types of sources. Valid values for the type and installment_term parameters are listed in the table above. Keep in mind that the effective valid values for installment_term depend on the amount and monthly minimum. The following code demonstrates how to create a new source.

Note: for the following example, you must have already set your $OMISE_PUBLIC_KEY environment variable to contain your public key.

curl https://api.omise.co/sources \
  -X POST \
  -u $OMISE_PUBLIC_KEY: \
  -d "description=Installment Payment Source" \
  -d "amount=500000" \
  -d "currency=THB" \
  -d "type=installment_kbank" \
  -d "installment_term=4" \
  -H "Omise-Version: 2019-05-29"
{
  "object": "source",
  "id": "src_test_5g2hvadpm5ucvap2a6n",
  "livemode": false,
  "location": "/sources/src_test_5g2hvadpm5ucvap2a6n",
  "type": "installment_kbank",
  "flow": "redirect",
  "amount": 500000,
  "currency": "THB",
  "installment_term": 4,
  "zero_interest_installments": true
}

The returned source object reflects the parameters passed at source creation in addition to the zero_interest_installments attribute. This will be set to true if you set Merchant to absorb installment interest in the Dashboard earlier.

Creating an Installment Payment Charge

Use the value of the id attribute of the returned object above to pass as the value of the source parameter for a new charge. Because this charge involves the customer leaving the site to authorize the charge, we must also pass the parameter return_uri. This is the URI on your site to which the customer is redirected upon charge completion.

Note: for this example, you must have already set your $OMISE_SECRET_KEY environment variable to contain your secret key, and $SOURCE_ID must contain the value of the id attribute above.

curl https://api.omise.co/charges \
-X POST \
-u $OMISE_SECRET_KEY: \
-d "source=$SOURCE_ID" \
-d "description=Installment Payment Charge" \
-d "amount=500000" \
-d "currency=THB" \
-d "return_uri=https://example.com/orders/345678/complete" \
-H "Omise-Version: 2019-05-29"
{
  "object": "charge",
  "id": "chrg_test_5g2hvak2zoseiam51ps",
  "livemode": false,
  "location": "/charges/chrg_test_5g2hvak2zoseiam51ps",
  "created_at": "2019-05-30T07:43:46Z",
  "amount": 500000,
  "currency": "THB",
  "funding_amount": 500000,
  "funding_currency": "THB",
  "fee": 18250,
  "fee_vat": 1278,
  "interest": 13000,
  "interest_vat": 910,
  "net": 466562,
  "description": "Installment Payment Charge",
  "metadata": {
  },
  "status": "pending",
  "capture": true,
  "authorized": false,
  "schedule": null,
  "reversed": false,
  "reversed_at": null,
  "expires_at": "2019-06-06T07:43:46Z",
  "expired": false,
  "expired_at": null,
  "voided": false,
  "paid": false,
  "paid_at": null,
  "transaction": null,
  "refunded_amount": 0,
  "refunds": {
    "object": "list",
    "from": "1970-01-01T00:00:00Z",
    "to": "2019-05-30T07:43:47Z",
    "offset": 0,
    "limit": 20,
    "total": 0,
    "order": "chronological",
    "location": "/charges/chrg_test_5g2hvak2zoseiam51ps/refunds",
    "data": [

    ]
  },
  "link": null,
  "return_uri": "https://example.com/orders/345678/complete",
  "failure_code": null,
  "failure_message": null,
  "card": null,
  "customer": null,
  "ip": null,
  "dispute": null,
  "source": {
    "object": "source",
    "id": "src_test_5g2hv9yy2k9n0640fox",
    "livemode": false,
    "location": "/sources/src_test_5g2hv9yy2k9n0640fox",
    "type": "installment_kbank",
    "flow": "redirect",
    "amount": 500000,
    "currency": "THB"
  },
  "disputable": false,
  "capturable": false,
  "reversible": false,
  "refundable": false,
  "authorize_uri": "https://pay.omise.co/offsites/ofsp_test_5g2hvak9ayf70bg0gm6/pay"
}

Creating a Source and Charge Server-side

Alternatively, if the source must be specified at charge creation time (i.e. server-side), the Charge API can be used to create and charge a source using one API request.

curl https://api.omise.co/charges \
  -X POST \
  -u $OMISE_SECRET_KEY: \
  -d "amount=500000" \
  -d "currency=THB" \
  -d "return_uri=http://example.com/orders/345678/complete" \
  -d "source[type]=installment_kbank" \
  -d "source[installment_term]=4" \
  -H "Omise-Version: 2019-05-29"

Authorization

The charge object created from the above API call contains the attribute authorize_uri. This is the URI for the bank-operated webpage to which you should redirect the customer to review and authorize the charge.

In test mode, you can simulate this behavior by visiting the URI to manually mark the charge as successful or failed.

Installment Payments Authorize URI Test

Checking the Status

Automatic via Webhooks

Use the Events API to get notified when a charge completes. Once configured, a request with the event key charge.complete will be sent to your configured webhook endpoint whenever an installment payment charge is completed. See Webhooks for more information.

Charge objects can have the following values for status: failed, expired, pending, or successful. If the charge status is successful, the value of authorized and paid should be true.

If the charge status is failed or expired, check the failure_code and failure_message attributes in the charge object for an explanation of the reason. Here are the possible values for failure_code and a description for each.

failure_code Description
insufficient_balance Insufficient funds in the account or the card has reached the credit limit.
payment_cancelled Payment cancelled by payer.
timeout Payer did not take action before charge expiration.
failed_processing General payment processing failure.

Manual

You can check any attribute of the charge by retrieving it via its id as described in Charges API. Here is an example using a JSON filter tool jq:

curl -s https://api.omise.co/charges/$CHARGE_ID \
  -u $OMISE_SECRET_KEY: | jq -M .status
"pending"

Refunds

See the Refunds API documentation for information on how to refund an installment payment charge.

Note: installment payment charges cannot be partially refunded. Only full refunds are supported.

Enabling Installment Payments

You will be required to review additional Terms & Conditions before using the API for live transactions.

The minimum API version required is 2017-11-02. See API Versioning for guidance on updating your API version.