Product module code
Configure custom product logic in JavaScript
What is product module code?
Product module code is a low-code environment in which custom logic can be written for insurance products on the Root platform.
While some product functionality is configured in the general product settings, product module code allows you to build more complex business rules in JavaScript. This offers a large degree of flexibility in customising a product module to meet product requirements.
The platform references the product module code to execute customised functions (or hooks) relating to a specific event for your product. For example, when the quote API endpoint is called for your product, the platform will look in your product module code for the validateQuoteRequest()
and getQuote()
functions to execute.
Product module code is contained in multiple virtual JavaScript files. The published code is run by the platform in a secured Node.js virtual environment. Specific built-in Node.js globals, as well as external modules for dates, validation and API requests, are made available in this environment.
Root also enables a set of SDK methods to retrieve policy and related information directly from the platform's runtime environment, without having to route requests through the externally exposed API endpoints.
Type checking in JavaScript
By default, we add a VS Code setting to your product module code directory to enable type checking. This allows you to leverage some of TypeScript's type checking and error reporting functionality in regular JavaScript files - a great way to catch common programming mistakes.
These type checks use the type declaration files included under
code > types
andcode > unit-tests > types
.To turn off type checking, open the relevant
jsconfig.json
file and setcompilerOptions.checkJs
tofalse
.
Helper functions
Aside from the specific functions that correspond to individual hooks, you may need to define a wide variety of your own helper functions and constants to make the product module code efficient, readable, maintainable and testable. This is in the form of abstracted JavaScript functions. Helper functions make it easy to share logic with other hooks in the product module code.
Pricing and charges helpers
The platform relies on the getQuote()
function to generate a quote. This means the product module code will typically include functions to calculate the premium based on the rating factors (parameters relevant to pricing) received via the quote endpoint.
This could also include calculating variable cover amounts and other policy-specific information, depending on how the product has been designed to work.
Validation helpers
Helper functions can also be useful to perform additional validations. In some cases Joi validation schemas are not ideal for performing complex validations, especially where the validation of some parameters depend, in complex ways, on the value of other parameters. In these cases helper functions can be used to define custom validation of the input data.
To return error messages via the API in case of invalid input, the command throw new Error('<Error message>');
can be used in the product module code. This will halt execution and result in a 400 Bad Request
API response.
Miscellaneous helpers
Examples of other helper functions could be a function to calculate the policyholder's age from her ID number, or a function to merge data received at the quote and application stage into a single object.
Examples of constants could be a constant percentage to calculate commissions, or an array containing a list of valid country codes.
Environment variables
You can access the following Root-specific environment variables related to the context in which the product module code is run. This is useful when you need to execute environment-specific code, such as calling the staging or production instance of an external service depending on whether the product module code is executed for a sandbox or live policy.
Property | Definition |
---|---|
process.env.ENVIRONMENT | String. One of [sandbox , production ]. See the Overview guide for more details. |
process.env.ORGANIZATION_ID | String. The UUID of the organization. For example, for product module code hooks that are triggered by an API call, this will be the organization linked to the API key. |
process.env.ORGANIZATION_TIMEZONE | String. The organization timezone. |
Root globals
When the product module code is run by the platform, various classes and modules are passed to the virtual machine environment as globals. These globals can be referenced in the product module code without defining them explicitly.
Returned objects
The classes in the table below can be accessed as globals in the product module code. Specific functions in the product module code related to policy issuing and other lifecycle events return instances of these classes. For example, the getPolicy()
function returns an instance of the Policy
class. Typically, these response objects are also returned in JSON format via the corresponding API endpoint.
Class name | Guide | API reference |
---|---|---|
QuotePackage | Quote hook | Quote package object |
Application | Application hook | Application object |
Policy | Policy issue hook | Policy object |
AlterationPackage | Alteration hooks | Alteration package object |
AlteredPolicy | Alteration hooks | See the guide. |
ReactivationOption | Reactivation hook | See the guide. |
RequotePolicy (deprecated) | Requote hook | Requote policy endpoint |
Throwing errors
To throw an error from the product module code, simply throw a standard JavaScript error. For example,
throw new Error('Policyholder date of birth does not match age provided at quote step)
.The error message you specified will be returned in the API response, will be visible in the product module execution logs, and may be displayed to on the dashboard, depending on the context.
UUIDs
The following function generates a universally unique identifier (UUID).
const uuidString = createUuid();
External modules
Built-ins
The following built-in JavaScript modules can be accessed in the product module code:
Math
- Properties and methods for mathematical constants and functions. Useful, for example, for rounding currency values to the nearest integer in the product module codeJSON
- Methods for parsing JavaScript Object Notation (JSON) and converting values to JSON. Useful, for example, for making external API calls from the product module code.Promise
- Representing the eventual completion (or failure) of an asynchronous operation and its resulting value. Useful, for example, for making external API calls and calling the Root SDK methods.
Validation
Root enables the popular and powerful Joi validation library in the product module code. This is particularly useful for validating the product-specific input parameters received via your product's quote, application and alteration endpoints.
Note:
- Root currently supports version 11.3.4 of Joi. Methods released in later versions of Joi are not currently supported.
- The
Joi.date()
andJoi.string().isoDate()
methods have been customised by Root and therefore won’t work exactly as per the Joi docs. Please refer to the list of extensions below.
The Joi module used in the product module code includes a number of custom Root extensions for insurance applications. The available extensions are listed below.
Dates
Normally when you use the Joi.date()
and Joi.string().isoDate()
methods to validate inputs and the date input doesn't explicitly include the timezone offset, the offset is assumed to be UTC.
Root has customised these methods to use the organisation's timezone as the default if the timezone offset is not explicitly included in the date input being validated.
To override the timezone offset used as the default for the date input, you can either explicitly include the timezone offset in the date input (e.g. 2022-12-15T00:00:00+02:00) or you can pass the timezone as a parameter in the joi method schema (list of supported timezones).
// Organisation timezone used as default
const dateSchema = Joi.date();
const isoDateSchema = Joi.string().isoDate();
// New York timezone used as default
const dateSchema = Joi.date('America/New_York');
const isoDateSchema = Joi.string().isoDate('America/New_York');
ID number
This extension checks whether a string is a valid South African ID number.
const joiIdNumberSchema = Joi.string().idNumber();
IMEI
This extension checks whether a string is a valid 15-digit IMEI number. Dashes (the -
character) are not allowed.
const joiImeiSchema = Joi.string().imei();
Digits
This extension checks whether a string contains only digits between 0 - 9.
const joiDigitsSchema = Joi.string().digits();
JSON string
This extension checks whether a string represents valid JavaScript Object Notation (JSON).
Note: This method does not allow single '
quotes. Only escaped double quotes are allowed, e.g. { \"key\": \"value\" }
not { 'key': 'value' }
.
const joiJsonSchema = Joi.string().jsonString();
RFC email
This extension checks whether a string conforms to the RFC 5322 standard for email addresses.
const joiRfcEmailSchema = Joi.string().rfcEmail();
Validation of contact details does not guarantee correct input
Joi validation extensions like RFC email and cellphone are only a "first line of defence" against erroneous data input. The fact that these validation checks are passed does not guarantee that the correct data has been provided by the customer, or that this data was correctly captured (for example by a call centre agent).
Cellphone
Checks that a string is a valid South African phone number.
const joiCellphoneSchema = Joi.cellphone();
Date of birth
This extension checks the following:
- The value must be a string.
- The value must be parseable as a date in the specified format. If no format is specified, "YYYYMMDD" and "YYYY-MM-DD" will be attempted.
- The date must be equal to or earlier than the start start of the day the code is executed.
const joiDateOfBirthSchema = Joi.dateOfBirth().format("YYYY-MM-DD");
Dates
Root enables the moment.js library for working with dates in the product module code. This is useful, for example, for manipulating and setting policy start and end dates. Root currently supports version 2.29.4 of moment.js.
Note: The moment module available in the product module code is in UTC mode. This means that dates will be represented in and timezone offsets assumed as UTC. Please refer to the parsing docs and guide for more information.
const getPolicy = (application, policyholder) => {
// Function body omitted
return new Policy({
start_date: moment().format(),
end_date: moment().add(1, 'year').format(),
// Other properties omitted
});
}
Root also enables the moment-timezone extension which allows you to parse and display dates in any timezone. Root currently supports version 0.5.40 of moment-timezone.
const getPolicy = (application, policyholder) => {
// Function body omitted
return new Policy({
start_date: momentTimezone().tz('America/New_York').format(),
end_date: moment().tz('America/New_York').add(1, 'year').format(),
// Other properties omitted
});
}
External API calls
Root enables the use of the node-fetch module for making API calls from within the product module code. This is a Node.js implementation of the JavaScript fetch API. Root currently supports version 2.6.0 of node-fetch.
const getNewPremium = async ({ requestBody }) => {
const response = await fetch('https://domain.client.co.za/premium-engine'
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${API_KEY}`,
},
});
const json = await response.json();
checkForAPIErrors({ response, json });
return json;
};
Root SDK methods
The following methods can be used within the product module code to retrieve policy and related platform data from within the platform's runtime environment.
Policies and payments
root.policies.getPolicy(policyId)
root.policies.getPolicy(policyId)
This method can be used to retrieve a policy using its policy_id
(a string representing a UUID). This could be useful, for example, to retrieve information from an earlier policy issued to the same policyholder.
Parameters
policyId
: String. Required. The UUID of the policy to be retrieved.
Returns
- A
Promise
that resolves to aPolicy
object.
Example
const policy = await root.policies.getPolicy('ec62de5e-354b-4e2e-96ec-ecf358da6d53');
root.policies.getPolicies({ filters?, pagination? })
root.policies.getPolicies({ filters?, pagination? })
This method can be used to retrieve a policy using the 10-digit policy number that was created when the policy was issued, or the identification or passport number of the policyholder. This could be useful, for example, to retrieve information from an earlier policy issued to the same policyholder.
Note: Using both the filters
and pagination
parameters at the same time can result in unexpected behaviour. These parameters should be used in the alternative - if one is included, the other should be excluded.
Parameters
params
: Object. Required.filters
: Object. Optional.policyNumbers
: Array<String>. Optional. A list of policy numbers to filter for.policyholderIdentificationNumber
: String. Optional. A valid RSA ID or passport number to filter for. Only policies linked to the policyholder with that identification number will be returned.
pagination
: Object. Optional.limit
: Integer. Optional. The maximum number of policies to return. Defaults to1000
, which cannot be exceeded.offset
: Integer. Optional. The (zero-based) index of the first item in the collection to return
Returns
- A
Promise
that resolves to an array ofPolicy
objects.
Examples
const policies = await root.policies.getPolicies({
filters: { policyNumbers: ['C8E819EEA7']},
});
const policies = await root.policies.getPolicies({
filters: { policyholderIdentificationNumber: '9201235036089'},
});
root.policies.getPolicyEvents(policyId)
root.policies.getPolicyEvents(policyId)
This method can be used to retrieve all the policy events related to an existing policy. These events include policy status changes (e.g. lapsing or cancelling the policy), policy data updates, and claims being linked to the policy, among others.
Parameters
policyId
: String. Required. The UUID of the policy for which to retrieve its events.
Returns
- A
Promise
that resolves to an array of policy event objects.
Example
const policyEvents = await root.policies.getPolicyEvents('ec62de5e-354b-4e2e-96ec-ecf358da6d53');
root.policies.getPolicyPayments(policyId, params?)
root.policies.getPolicyPayments(policyId, params?)
This method can be used to retrieve all payments related to an existing policy. Retrieving the full payment history from within the product module code can be useful, for example, for specifying product-specific lapse rules.
Note: Using both the filters
and pagination
parameters at the same time can result in unexpected behaviour. These parameters should be used in the alternative - if one is included, the other should be excluded.
Parameters
policyId
: String. Required. The UUID of the policy for which to retrieve its payments.params
: Object. Optional.filters
: Object. Optional.statuses
: Array<String>. Optional. A list of payment statuses to include in the query. One or more of['pending', 'submitted', 'processing', 'failed', 'successful', 'cancelled']
. If this parameter is omitted, all payment statuses will be included.paymentDateFrom
: String. Optional. ISO date after which to return payments.
pagination
: Object. Optional.limit
: Integer. Required (optional ifoffset
is specified). The maximum number of events to return. Cannot exceed1000
.offset
: Integer. Required (optional iflimit
is specified). The (zero-based) index of the first item in the collection to return.
Returns
- A
Promise
that resolves to an array ofPayment
objects.
Example
const policyPayments = await root.policies.getPolicyPayments(
'ec62de5e-354b-4e2e-96ec-ecf358da6d53',
{
filters: {
statuses: ['processing', 'successful'],
paymentDateFrom: '2021-01-01',
},
pagination: {
limit: 10,
offset: 10,
},
}
);
root.policies.countPolicyPayments(policyId, params?)
root.policies.countPolicyPayments(policyId, params?)
This method can be used to retrieve the number of payments on a policy. This is useful for paginating the getPolicyPayments()
SDK method.
Parameters
policyId
: String. Required. The UUID of the policy for which to retrieve the payment count.params
: Object. Optional.filters
: Object. Optional.statuses
: Array<String>. Optional. A list of payment statuses to include in the query. One or more of['pending', 'submitted', 'processing', 'failed', 'successful', 'cancelled']
.paymentDateFrom
: String. Optional. ISO date after which to return the payment count.
Returns
- A
Promise
that resolves to an integer.
Example
const policyPaymentCount = await root.policies.countPolicyPayments(
'ec62de5e-354b-4e2e-96ec-ecf358da6d53',
{
filters: {
statuses: ['processing', 'successful'],
paymentDateFrom: '2021-01-01',
},
}
);
Payment coupons
root.policies.getPaymentCoupons(params)
root.policies.getPaymentCoupons(params)
This method can be used to retrieve all the payment coupons for the given policy.
Parameters
params
: Object. Required.policyId
: String. Required. The UUID string of the policy for which the coupons are to be retrieved.includes
: Object. Optional.policy
. Boolean. Optional.
filters
: Object. Optional.status
: Array<String>. Optional. A list of payment coupon statuses to filter for. One or more ofpending
,redeemed
,cancelled
, andreversed
.type
: Array<String>. Optional. A list of payment coupon types to filter on. One or more ofad_hoc
andpayment_holiday
.redeemableOn
: String. Optional. A date, for example with a format ofYYYY-MM-DD
, on which the coupons should be redeemable. This should only be used forpayment_holiday
coupons.expiredOn
: String. Optional. A date, for example with a format ofYYYY-MM-DD
, at which the coupons should have expired by. This should only be used forpayment_holiday
coupons.updatedAfter
: String. Optional. A date, for example with a format ofYYYY-MM-DD
, after which the coupons should have been updated.updatedTo
: String. Optional. A date, for example with a format ofYYYY-MM-DD
, up to which the coupons could have been updated.
Returns
- A
Promise
that resolves to an array of the retrievedPayment Coupon
objects. This Promise can be resolved with the.then()
and.catch()
Promise methods or withawait
in anasync
function.
Example
const paymentCoupons = await getPaymentCoupons({
policyId: 'ec62de5e-354b-4e2e-96ec-ecf358da6d53',
includes: { policy: true },
filters: {
status: ['pending', 'cancelled'],
type: ['payment_holiday'],
redeemableOn: '2021-02-15',
expiredOn: '2021-03-01',
updatedAfter: '2021-01-15',
updatedTo: '2021-02-20',
},
});
root.policies.createPaymentCoupons(params)
root.policies.createPaymentCoupons(params)
This method can be used to create new payment coupons.
Parameters
params
: Object. Required.policyId
: String. Required. The UUID string of the policy for which the coupons are to be created.newPaymentCoupons
: Array<Object>. Required. A list of payment coupon objects to be created.type
: String. Required. Eitherad_hoc
orpayment_holiday
.redeemableFrom
: String. Required for a type ofpayment_holiday
. The date from which the coupon is redeemable.redeemableTo
: String. Required for a type ofpayment_holiday
. The date up to which the coupon is redeemable.amount
: Number. Required for a type ofad_hoc
.The currency amount that will be credited on the policy ledger when the coupon is redeemed. This is only used withad_hoc
payment coupons. Forpayment_holiday
coupons, the ledger is credited with the policy premium when the coupon is redeemed.reason
: String. Optional. The reason for the payment coupon being created.
Returns
- A
Promise
that resolves to an array of the createdPayment Coupon
objects. This Promise can be resolved with the.then()
and.catch()
Promise methods or withawait
in anasync
function.
Example
const paymentCoupons = await createPaymentCoupons({
policyId: 'ec62de5e-354b-4e2e-96ec-ecf358da6d53',
newPaymentCoupons: [
{
type: 'ad_hoc',
amount: 4000,
},
{
type: 'ad_hoc',
amount: 5000,
reason: 'Campaign',
},
{
type: 'payment_holiday',
redeemableFrom: '2021-02-01',
redeemableTo: '2021-02-31',
},
{
type: 'payment_holiday',
redeemableFrom: '2022–05-01',
redeemableTo: '2022-06-31',
reason: 'Promotion',
},
]
});
root.policies.cancelPaymentCoupon(params)
root.policies.cancelPaymentCoupon(params)
This method can be used to cancel payment coupons.
Parameters
params
: Object. Required.paymentCouponId
: String. Required. The UUID string of the coupon to be canceled.
Returns
- A
Promise
that resolves to the canceledPayment Coupon
object. ThisPromise
can be resolved with the.then()
and.catch()
Promise
methods or withawait
in anasync
function.
Example
const paymentCoupons = await cancelPaymentCoupon({
paymentCouponId: 'cef52505-8506-44b1-b623-2ef8c6fefa16',
});
root.policies.redeemPaymentCoupon(params)
root.policies.redeemPaymentCoupon(params)
This method can be used to redeem payment coupons.
Parameters
params
: Object. Required.paymentCouponId
: String. Required. The UUID string of the coupon to be redeemed.action
: Object. Required.paymentDate
: String. Required. The payment date for which the coupon is being redeemed.billingDate
: String. Optional. The billing date for which the coupon is being redeemed.
Returns
- A
Promise
that resolves to the redeemedPayment Coupon
object. ThisPromise
can be resolved with the.then()
and.catch()
Promise
methods or withawait
in anasync
function.
Example
const paymentCoupons = await redeemPaymentCoupon({
paymentCouponId: 'cef52505-8506-44b1-b623-2ef8c6fefa16',
action: { paymentDate: '2021-02-15' },
});
root.policies.reversePaymentCoupon(params)
root.policies.reversePaymentCoupon(params)
This method can be used to reverse payment coupons.
Parameters
params
: Object. Required.paymentCouponId
: String. Required. The UUID string of the coupon to be reversed.
Returns
- A
Promise
that resolves to the reversedPayment Coupon
object. ThisPromise
can be resolved with the.then()
and.catch()
Promise
methods or withawait
in anasync
function.
Example
const paymentCoupons = await reversePaymentCoupon({
paymentCouponId: 'cef52505-8506-44b1-b623-2ef8c6fefa16',
});
Data stores
root.dataStores.store(key).find()
root.dataStores.store(key).find()
This method can be used to retrieve a data store's entities. This is how data store data is retrieved from inside the product module code. See the data stores guide (work in progress) for more details
Parameters
key
: String. Required. The key of the datastore to retrieve.
Returns
- A
Promise
that resolves to an array of data store entities.
Example
const dataStoreEntities = await root.dataStores.store('data_store_key').find();
Notifications
root.notifications.triggerCustomEvent(params)
root.notifications.triggerCustomEvent(params)
This method can be used to trigger a custom notification event. See the custom notification events guide for more details.
Parameters
params
: Object. Required.customEventKey
: String. Required. The key identifying the custom event to trigger.customEventType
: String. Required. The type of custom event. Must match the type on the Root management dashboard. One of [policy
,payment_method
,payment
,claim
].id
: String. Required. The UUID of the entity for which to trigger the event. IfcustomEventType
ispolicy
orpayment_method
, it must be apolicy_id
. IfcustomEventType
isclaim
, it must be aclaim_id
. IfcustomEventType
ispayment
, it must be apayment_id
.
Returns
- Void
Example
await root.notifications.triggerCustomEvent({
customEventKey: 'policyholder_birthday',
customEventType: 'policy',
id: policy.policy_id,
});
Updated 4 months ago