Installment Plan Status Notifications

Installment plan status notifications enable you to track the progress of a plan.

Installment plan status notifications are only available for Flywire-managed recurring payments.

How do I get started?

When you register an application, you will receive a Shared Secret that you should use to validate the payload of the received notification. For more information about secure notifications see Validating Notifications.

Installment Plan Statuses

Status Notification Description

in_progress

in progress

The installment plan has started and is in progress.

Payments will be created by Flywire according to the plan.

You will receive notifications for each payment of the plan under the same notifications URL you provided for the plan, see Payment Status Notifications for details about those notifications.

paused -

The payer initiated a Pay in Full payment.

A Pay in Full payment is an out of schedule payment that can be manually triggered by the payer. With this option, the payer can pay the full remaining amount of the installment plan at once. If a payer has the option to do this depends on your settings for the installment plan.

  • If the Pay in Full payment has been successfully Delivered, the installment plan moves to Finished.

  • If the Pay in Full payment was not successful, the payment gets Cancelled and the installment plan moves back to In Progress.

Note that this status does not trigger a callback notification.

finished

finished

The installment plan has been successfully completed, meaning the total amount has been paid.

While you are getting this notification, your payer will get an email from Flywire informing them that the installment plan has successfully completed.

cancelled

cancelled

The installment plan has been cancelled.

Cancelling an installment plan means the plan was stopped before the total amount was paid. No more payments will be created for this plan.

Content of Installment Plan Status Notifications

data object

payment_method object

{
  "event_type": "in_progress",
  "event_date": "2024-04-04T13:47:11Z",
  "event_resource": "recurring_installment_plan",
  "callback_id": "My reference",
  "number_of_installments": 10
  "data": {
    "id": "IPLRP18EA95D0A57",
    "start_date": "2024-04-04T13:46:30Z",
    "end_date": "2025-01-04T14:46:30Z",
    "currency_from": "USD",
    "amount_to": 500000,
    "currency_to": "CAD",
    "payment_method": {
      "type": "card",
      "brand": "VISA",
      "card_classification": "credit",
      "card_expiration": "3/2030",
      "last_four_digits": "1111"
    }
  }

data object

{
  "event_type": "finished",
  "event_date": "2023-09-08T1429Z",
  "event_resource": "recurring_installment_plan",
  "callback_id": "My reference"
  "data": {
    "id": "IPLRP18EA95D0A57",
    "number of installments": 4,
    "start_date": "2023-09-30T00:00:00Z",
    "end_date": "2023-10-30T00:00:00Z"
    "total_amount": "1000000"
    "currency":"USD"
    }
}

data object

payment_method object

{
  "event_type": "cancelled",
  "event_date": "2024-04-04T13:47:11Z",
  "event_resource": "recurring_installment_plan",
  "callback_id": "My reference",
  "number_of_installments": 10,
  "amount_paid" : "2000",
  "data": {
    "id": "IPLRP18EA95D0A57",
    "start_date": "2024-04-04T13:46:30Z",
    "end_date": "2025-01-04T14:46:30Z",
    "currency_from": "USD",
    "amount_to": 500000,
    "currency_to": "CAD",
    "payment_method": {
      "type": "card",
      "brand": "VISA",
      "card_classification": "credit",
      "card_expiration": "3/2030",
      "last_four_digits": "1111"
    },
  }
}

How to set up Installment Plan Status Notifications

When you are creating an installment plan (see Checkout for Flywire-Managed Recurring Payments), you'll encounter two parameters that influence the status notifications:

Parameter Description

external_reference

string

The external reference.

The external reference is used to match a notification to an installment plan. All payments belonging to the plan will also use this external reference. It is included in notifications about the installment plan and all payments belonging to the plan. You can use any kind of identifier or reference from your own system that helps you identify the plan and its payments. Max size of 50 characters.

The external reference is called callback_id in the installment plan notifications.

For tracking installment plans via notifications see Installment Plan Status Notifications.

For tracking payments via notifications see Payment Status Notifications.

notifications_url

string (url)

The notifications URL to receive callbacks for the installment plan and all payments belonging to this plan.

For tracking installment plans via notifications see Installment Plan Status Notifications.

For tracking payments via notifications see Payment Status Notifications.

Validating Installment Plan Status Notifications

Validating notifications is optional, as it’s on your server side, but for security reasons it is recommended to validate all notifications.

How to validate a notification

To validate a notification, check its X-Flywire-Digest header. This value is generated by Flywire using your Shared Secret to encrypt the notification body. To verify the notification, generate the digest using the same method and compare it to the X-Flywire-Digest value in the header. If they match, the notification is legitimate and hasn't been tampered with.

  1. Retrieve the raw HTTP body of the notification you received.

    Make sure you use the raw HTTP body of the notification. You must generate the X-Flywire-Digest value using the exact payload you received in the notification. If you change the body in any way the values won't match later.

 

  1. Encrypt the received notification twice:

    1) Encrypt the raw HTTP body of the received notification with your Shared Secret using the SHA-256 algorithm.

    2) Take the result and encrypt it in Base64.

    The examples show you how to do this in different programming languages. In each example, exchange the shared_key with your Shared Secret and message_body with the raw HTTP body of the notification.

    digest = OpenSSL::Digest.new('sha256')
    encrypted_payload = OpenSSL::HMAC.digest(digest, shared_secret, notification_body)
    Base64.encode64(encrypted_payload).strip
    			
    # Step 1: Define the hashing algorithm to use for the HMAC.
    # This initializes the SHA-256 hashing mechanism.
    hash_algorithm = OpenSSL::Digest.new('sha256')
    
    # Step 2: Compute the HMAC in binary format.
    # This uses the shared secret and the message body to produce the HMAC signature.
    hmac_binary = OpenSSL::HMAC.digest(hash_algorithm, shared_secret, message_body)
    
    # Step 3: Encode the HMAC in Base64 for use in the X-Flywire-Digest header.
    x_flywire_digest = Base64.encode64(hmac_binary).strip
    public static string Digest(string shared_secret, string message_body)
    {
        // Step 1: Initialize the HMACSHA256 object with the shared secret.
        // This sets up the hashing algorithm (SHA-256) and the secret key for HMAC.
        using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(shared_secret)))
        {
            // Step 2: Convert the message body into a byte array.
            // The message body is the message payload you want to hash
            var bytes = Encoding.UTF8.GetBytes(message_body);
    
            // Step 3: Compute the HMAC hash of the message body.
            // This generates the HMAC using the shared secret and the message body.
            var hashedBytes = hmacsha256.ComputeHash(bytes);
    
            // Step 4: Convert the hashed byte array into a Base64 string.
            return Convert.ToBase64String(hashedBytes);
        }
    }
    const crypto = require('crypto');
    
    function createDigest(shared_secret, message_body) {
        // Step 1: Initialize the HMAC with the SHA-256 algorithm and the shared secret.
        const hmac = crypto.createHmac('sha256', shared_secret);
        
        // Step 2: Update the HMAC with the message body.
        // The message body is the message payload you want to hash
        hmac.update(message_body);
    
        // Step 3: Get the HMAC digest and encode it in Base64.
        const digestHeader = hmac.digest('base64');
        
        return digestHeader;  // The `digestHeader` is the X-Flywire-Digest header.
    }

     

  2. Compare your Base64 string to the value in the X-Flywire-Digest parameter of the notification you received.

    If the values match, the notification came from Flywire and hasn't been changed by a third party.

    If the values don't match, you shouldn't trust the notification.