Alteration hooks

Configure how existing policy information can be changed

Overview

After a policy has been issued, it is often necessary to change policy information. This can range from a simple amendment to correct the spelling of a family member's name, to changing the rating factors and recalculating the premium, and even adding benefits or changing the sum assured.

Alteration hooks are a flexible tool for allowing both simple and more complex changes to policies after they have been issued. You can define multiple alteration hooks for your product, in each case specifying the policy fields that can be changed. Alternatively, you could define a single alteration hook that allows the user to change all available fields on a policy.

The following sequential steps are required to apply alterations to policies:

  1. The alteration parameters are passed to the create alteration package endpoint from your system or the Root dashboard.
  2. This data is then fed to a validation function you specify in the product module code, validateAlterationPackageRequest().
  3. Once validated, this data is fed to the getAlteration() function, where you can include custom logic to specify how the policy parameters should be altered. This function returns an alteration package, which is also returned over the API for display and confirmation by the user or customer.
  4. The final step is to apply the alteration package to the policy. This done by passing the alteration_package_id and policy_id to the apply alteration package endpoint. This executes the applyAlteration() function in the product module code.

You need to define at least the following three functions in the product module code: validateAlterationPackageRequest(), getAlteration() and applyAlteration(). By doing so, you configure how the create alteration package and apply alteration package endpoints will function for your product.

Defining a new alteration hook

There are no predefined alteration hooks. If you want to add this functionality to your product, you will need to define each alteration hook you want to enable. Each alteration hook has a name and a key:

  • Name - The name of the alteration hook is displayed as one of the options on the policy summary screen on the Root management dashboard. For example, the name of an alteration hook to add or remove a spouse on a funeral policy could be "Add / remove spouse".
  • Key - The unique identifier for the alteration hook. The key is included as a parameter in the create alteration package request payload to identify the alteration hook to be executed. The key should be in snake case, for example add_remove_spouse.

The name and key are defined in the .root-config.json file in the product module's Workbench directory, as in the example below.

{
  "configVersion": "2021-05-09",
  "productModuleName": "Dinosure",
  "productModuleKey": "dinosure",
  ...
  "alterationHooks": [
    {
      "key": "add_remove_spouse",
      "name": "Add / remove spouse"
    }
  ]
}

After an alteration hook has been added to the product, it can be selected and used on the dashboard as shown in the picture below.

943

How an alteration hook called "Add / remove spouse" can be selected on the dashboard.

Specifying the alteration package parameters

For each alteration hook, you need to specify the input parameters that will be included in the request payload to create an alteration package. This would typically be one or more of the policy parameters saved to the policy's module object, although this is not a strict requirement.

Below is an example payload for adding a spouse to an existing funeral policy. Read more about the create alteration package request endpoint.

{
  "key": "add_remove_spouse",
  "data": {
    "spouse_included": "true",
    "spouse": {
      "age": 35,
      "first_name": "Jane",
      "last_name": "Doe"
    }
  }
}

The "key" parameter is mandatory and standard across all product modules and alteration hooks. The platform expects this parameter to identify the alteration hook to be executed.

The "data" parameter is also standard and mandatory. It is defined as an object which contains the input parameters. You need to customise these input parameters for your product module and for the specific alteration hook.

Both the key and data parameters are passed to the validateAlterationPackageRequest() function in the product module code.

📘

Dashboard dependency

If the Root dashboard will be used to capture alteration parameters and apply them to policies, the alteration package request payload structure needs to match the schema defined for the alteration hook.

Defining an alteration hook schema is how you configure the frontend form elements that will be used to capture the alteration parameters on the Root dashboard. Note: To allow pre-filling these form inputs, the alteration hook schema references the policy's module object.

Validating an alteration package request

Since you are configuring the create alteration package endpoint for your product module, you also need to define the validation rules for what data is allowed. Root uses the popular and powerful Joi library to define these validations.

Joi validation schemas allow for both basic validation, such as checking data types, and enforcing product specific business rules, such as limiting the allowed age range for a specific input field.

Below is an example of the validateAlterationPackageRequest() for adding or removing a spouse to a funeral policy. This function accepts four parameters, the alteration hook key, the alteration parameter data and the related policy and policyholder object.

/**
 * Validates the alteration package request data.
 * @param {object} params
 * @param {string} params.alteration_hook_key The alteration hook identifier, as specified in `.root-config.json`.
 * @param {Record<string, any>} params.data The data received in the body of the
 *     <a href='https://docs.rootplatform.com/reference/create-an-alteration-package-1' target='_blank'>Create an alteration package</a> request
 *     (without the `key` property).
 * @param {PlatformPolicy} params.policy The policy to which the alteration package will be applied.
 * @param {PlatformPolicyholder} params.policyholder The policyholder linked to the policy.
 * @return {{error: any; result: any}} The <a href='https://joi.dev/api/?v=12.1.0#validatevalue-schema-options-callback' target='_blank'>validation result</a>.
 *    If there are no errors, the `value` property will contain the validated data, which is passed to `getAlteration`.
 * @see {@link https://docs.rootplatform.com/docs/alteration-hooks Alteration hooks}
 */
const validateAlterationPackageRequest = ({ alteration_hook_key, data, policy, policyholder }) => {
  let validationResult;
  switch(alteration_hook_key) {
    case 'add_remove_spouse':
      if (moment(policyholder.date_of_birth).isBefore('1975-01-01')) {
        throw new Error(`The 'add_remove_spouse' alteration can only be applied for policyholders born on or after 1 January 1975`);
      }
      validationResult = Joi.validate(data, Joi.object().keys({
        spouse_included: Joi.boolean().required(),
        spouse: Joi.object().keys({
          age: Joi.number().integer().min(18).max(65).required(),
          first_name: Joi.string().required(),
          last_name: Joi.string().required(),
        }).when("spouse_included", {
          is: true,
          then: Joi.required(),
          otherwise: Joi.forbidden().allow(null),
        }),
      }).required());
      return validationResult;
    default:
      throw new Error(`Invalid alteration hook key "${alteration_hook_key}"`);
  }
}

In this example, the validateAlterationPackageRequest() function must be able to deal with all the alteration hooks defined for your product. Extracting the validation for each alteration hook into a separate helper function can helps to keep things neat.

It is best practice to throw an error if the alteration hook key does not match any of the alteration hooks defined for your product. This helps with debugging when creating alteration packages over the API.

If no errors are thrown, Joi.validate() returns an object containing the validated data, which is then automatically passed into the getAlteration() function to create an alteration package.

📘

Alteration hook functions accept a single object argument

The three alteration hook functions in the product module code - validateAlterationPackageRequest(), getAlteration() and applyAlteration() - accept a single params object as their only argument. The actual parameters are passed as key value pairs within this object.

These parameters can easily be unpacked and assigned using object destructuring, as in the example.

Creating an alteration package

In the getAlteration() function, you can use the the alteration parameters together with the existing policy and policyholder information to specify how the policy should be altered.

For simple amendments that do not affect the premium, little additional logic will be required. For changes that affect the premium, you will need to re-apply the pricing logic to the new input parameters, and possibly include additional logic from the quote hook or application hook.

/**
 * Generates an alteration package from the alteration package request data, policy and policyholder.
 * @param {object} params
 * @param {string} params.alteration_hook_key The alteration hook identifier, as specified in `.root-config.json`.
 * @param {Record<string, any>} params.data The validated data returned by `validateAlterationPackageRequest` as `result.value`.
 * @param {PlatformPolicy} params.policy The policy to which the alteration package will be applied.
 * @param {PlatformPolicyholder} params.policyholder The policyholder linked to the policy.
 * @return {AlterationPackage} Alteration package returned by the
 *     <a href='https://docs.rootplatform.com/reference/create-an-alteration-package-1' target='_blank'>Create an alteration package</a>
 *     endpoint.
 * @see {@link https://docs.rootplatform.com/docs/alteration-hooks Alteration hooks}
 */
const getAlteration = ({ alteration_hook_key, data, policy, policyholder }) => {
  let alterationPackage;
  switch(alteration_hook_key) {
    case 'add_remove_spouse':
      const moduleData = getPremiums({ data, policy });
      alterationPackage = new AlterationPackage({
        input_data: data,
        sum_assured: moduleData.sum_assured,
        monthly_premium: moduleData.premium,
        change_description: 'Alteration - add / remove spouse',
        module: moduleData,
      });
      return alterationPackage;
    default:
      throw new Error(`Invalid alteration hook key "${alteration_hook_key}"`);
  }
}

The top-level fields under the AlterationPackage object, such as sum_assured and monthly_premium, are standard. Most of these fields (except change_description and input_data) correspond to standard fields on the policy object. For more details, see the API reference for the alteration package object and the policy object.

AlterationPackage propertiesDefinition
sum_assuredInteger. The amount, in cents, of the total value insured. May be excluded for group scheme policies.
monthly_premiumInteger. The amount, in cents, of the monthly premium, as written on the policy schedule.
moduleObject. Custom, product specific fields stored against the policy.
input_dataObject. The input data received over the API endpoint. Must be set equal to the data parameter passed to the getAlteration() function.
change_descriptionString. A description of the change to the policy.

Custom, product specific information is saved to the module object. Typically, the fields on the alteration package module will correspond to existing fields on the policy module, as defined in the policy issue hook.

The alteration package returned by the getAlteration() function is saved to the platform and then returned over the API. Each alteration package is assigned its own alteration_package_id. When they are created, alteration packages have a status of "pending", indicating that the alteration package has not yet been applied to a policy.

Once the customer has confirmed an alteration, the alteration package can be passed to the applyAlteration() function where it can be applied to the policy.

Applying an alteration package to a policy

Once an alteration package has been created, it can be applied to a policy to change policy data.

When the apply alteration package endpoint is hit, the alteration package, together with the policy and policyholder objects are passed to the applyAlteration() function in the product module code.

/**
 * Applies the alteration package to the policy.
 * Triggered by the <a href='https://docs.rootplatform.com/reference/apply-alteration-package-1' target='_blank'>Apply alteration package</a> endpoint.
 * @param {object} params
 * @param {string} params.alteration_hook_key The alteration hook identifier, as specified in `.root-config.json`.
 * @param {PlatformPolicy} params.policy The policy to which the alteration package will be applied.
 * @param {PlatformPolicyholder} params.policyholder The policyholder linked to the policy.
 * @param {PlatformAlterationPackage} params.alteration_package The alteration package to be applied to the policy.
 * @return {AlteredPolicy} The altered policy. This object is **not** returned over the endpoint.
 *    Instead, the alteration package is returned with a status of `applied`.
 * @see {@link https://docs.rootplatform.com/docs/alteration-hooks Alteration hooks}
 */
const applyAlteration = ({ alteration_hook_key, policy, policyholder, alteration_package }) => {
  let alteredPolicy;
  switch (alteration_hook_key) {
    case 'add_remove_spouse':
      alteredPolicy = new AlteredPolicy({
        package_name: policy.package_name,
        sum_assured: alteration_package.sum_assured,
        base_premium: alteration_package.monthly_premium,
        monthly_premium: alteration_package.monthly_premium,
        module: alteration_package.module,
        end_date: moment(policy.end_date),
        start_date: moment(policy.start_date),
        charges: policy.charges,
      });
      return alteredPolicy;
    default:
      throw new InvalidRequestError(`Invalid alteration hook key "${alteration_hook_key}"`);
  }
}

This function returns an AlteredPolicy object. The value of this object's properties will be used to overwrite the corresponding policy parameters. For each field, you need to specify whether the existing policy parameter should persist, or whether it should be replaced with the corresponding parameter from the alteration package.

In most cases, we would advise against including additional custom logic in the body of the applyAlteration() function. It is best practice to put custom logic in the getAlteration() function, such that each property of the AlteredPolicy object corresponds directly to a parameter on the policy or the alteration package.

Note: The altered policy is not returned over the API. Instead, the alteration package is returned, which will now have a status of "applied".

AlteredPolicy propertiesDefinition
package_nameString. The insurance package name.
sum_assuredInteger. The amount, in cents, of the total value insured. May be excluded for group scheme policies.
base_premiumInteger. The amount, in cents, of the minimum allowed monthly premium fee. This includes risk pricing and platform fees.
monthly_premiumInteger. The amount, in cents, of the monthly premium, as written on the policy schedule.
moduleObject. Custom, product specific fields stored against the policy.
start_date
optional
Date. The start date of the policy. Defaults to the existing policy start date.
end_date
optional
Date. The end date of the policy. Defaults to the existing policy start date.
charges
optional
Array. The premium breakdown to be applied to each policy payment. Defaults to the existing policy charges. See the policy issue hook guide for more details.