Actions
Define automated actions triggered by policy lifecycle events or scheduled functions
Overview
Actions can be returned by lifecycle hooks, scheduled functions, and instruction functions in the product module code. If returned, they are added to the Root platform's job queue for execution.
The following categories of actions are currently supported:
- Change policy status - For example, mark an active policy as cancelled.
- Update policy data - Update standard policy fields, the package name, or module data.
- Change policy balance - Debit or credit the policy ledger.
- Update claim data - Update the module data stored on a claim.
- Trigger custom notification event - For example, trigger a custom email or SMS when a benefit is terminated.
- Archive alteration package - Archive a pending policy alteration package.
- Manage instructions - Schedule, cancel, or bulk-cancel instructions — the preferred mechanism for future-dated work.
- Create a task - Create an automated task for back-office workflows.
Action objects are returned inside an array, allowing multiple actions to be returned by the same function.
Actions are executed in the order specifiedActions are executed in the same order as specified in the
actionsarray in the product module code. For example, if you first want to update the policy module data and then trigger a custom notification event, you should include the notification action as the last object in the array.
The action object
The action to be queued is specified using the name property of the action object. The name of the action must match one of the predefined actions listed in this guide.
Actions that update policy or claim data require a second property, the data object. This data will be used to update the existing data.
Actions that change the policy balance require an amount by which to change the balance, and optionally a description for the ledger entry and the currency corresponding to the amount.
Example
The example below uses the after payment failed lifecycle hook to define custom logic for handling failed payments. In this example, the sum assured covered under the policy is reduced, and the policy status is changed to not_taken_up. (This example is for illustration only and the logic specifying under which conditions these actions are returned has been omitted).
const afterPaymentFailed = ({ policy, payment }) => {
// Custom logic omitted
const actions = [
{
name: "update_policy",
data: {
sumAssured: policy.sum_assured - 1000,
},
},
{ name: "mark_policy_not_taken_up" },
];
return actions;
};Change policy status
Actions can be queued to change a policy's status to active, cancelled, lapsed or not_taken_up.
Activate policy
This action changes a policy's status to active (for example if a policy has been lapsed or cancelled). Only the name of the action is required.
{ name: 'activate_policy' }Cancel policy
This action changes a policy's status to cancelled (for example as part of implementing custom lapse rules for a product).
{
name: 'cancel_policy',
reason: '<reason>',
cancellation_requestor: 'client',
cancellation_type: 'Alternate product'
}Properties
| Property name | Definition |
|---|---|
name | string. cancel_policy. |
cancellation_requestor | string. Who requested the cancellation. One of insurer, client. Required (unless reason is supplied — at least one of cancellation_requestor or reason must be present). |
cancellation_type | string. Required when cancellation_requestor is supplied. Allowed values depend on the requestor. For client: Too expensive, Alternate product, Unhappy with service, Unhappy with benefits, Financial constraints, Retrenched, Unemployed, Leaving the country, Cooling off period, Other. For insurer: Cooling off period, Dishonest client, Altered risk profile, Policy claimed. |
reason optional | string. A free-text reason for the cancellation. |
Lapse policy
This action changes a policy's status to lapsed (for example as part of implementing custom lapse rules for a product). Only the name of the action is required.
{ name: 'lapse_policy' }Mark policy not taken up
This action changes a policy's status to not_taken_up (for example as part of implementing custom not taken up checks for a product). Only the name of the action is required.
{ name: 'mark_policy_not_taken_up' }Properties
| Property name | Definition |
|---|---|
name | string. Specifies the action to be performed. Must equal one of the predefined action names. |
Update policy data
You can use the update_policy action to update selected standard fields (see the supported data properties section below) on a policy, including the policy's package name, as well as the module data. The values of these fields are set when the policy is issued via the policy issue hook.
Note: Only the fields that are to be updated on the policy need to be specified in the data object. Any properties not specified will not be changed.
Read more about the standard fields included on all policies in the policy object.
Data object property names are incamelCaseIn the
update_policyaction object, the names of the properties under the data object are specified incamelCase. These properties correspond tosnake_casefield names on the policy object. For example,sumAssuredin the data object corresponds tosum_assuredon the policy.
Update standard policy fields
The standard fields that can be updated on the policy are defined within the supported data properties section.
Example
The snippet below represents an update of the policy's sum assured.
{
name: 'update_policy',
data: {
sumAssured: newSumAssured,
}
}Update the policy package name
The packageName property is a free-text field used to label or group policies. Builders can set it to any string — for example, a package identifier, an external reference, or a human-readable label.
The value is included in the search index used by the list policies endpoint, so policies can be looked up by their package name via the standard policy search query.
packageNameis free textThe value is stored as-is — there is no validation against packages defined in the product module, and no length or format restrictions are enforced.
Updating
packageNamedoes not change the policy's premium, billing amount, sum assured, or module data. If any of these should change alongside the package, include them in the sameupdate_policyaction.Policy search uses PostgreSQL full-text tokenization, so values are matched on word boundaries (punctuation and underscores split tokens). Choose package names with this in mind if they will be used for lookup.
Example
{
name: 'update_policy',
data: {
packageName: 'comprehensive_plus_2026',
},
}Update module data
There are two ways to update the policy's module data:
- Merge selected fields into the existing module object using the dedicated
update_policy_module_dataaction. This is the preferred mechanism. - Replace the entire module object using
update_policywithdata.module— reserve this for the rare case where you genuinely need to replace the object wholesale.
Preferupdate_policy_module_data
update_policy_module_datamerges your changes into the existing module data, so you only specify the fields you're changing — there is no need to reconstruct the whole object, and no risk of clobbering fields written by other processes between your read and your write. A full replace viaupdate_policyoverwrites everything, so any field you forget to carry over is lost.
Update policy module data (merge — preferred)
The update_policy_module_data action shallow-merges the supplied data object into the policy's existing module data. Existing fields not present in data are preserved; matching keys are overwritten; new keys are added.
The snippet below shows how the product specific extraction_benefit field can be updated on the module object — only the changed field is specified:
const removeExtractionBenefit = ({ policy }) => {
return [
{
name: 'update_policy_module_data',
data: {
extraction_benefit: false,
}
}
];
}| Property name | Definition |
|---|---|
name | string. update_policy_module_data. |
data | object. Required. Fields to merge into the policy's existing module data. |
Replace the module object (update_policy)
update_policy)Changing the module field using the update_policy action will replace the entire module object on the policy. Only use this when a wholesale replacement is genuinely required — for example, removing fields entirely as part of restructuring the module data. If you do:
- Construct the new module object from the existing policy module object, which is passed to the function as
policy.module. - Replace the entire module object by returning the updated module object as
data.module.
const restructureModuleData = ({ policy }) => {
const newModule = {
...policy.module,
extraction_benefit: false,
};
return [
{
name: 'update_policy',
data: {
module: newModule,
}
}
];
}Supported data properties
| Data object property name | Corresponding policy field | Definition |
|---|---|---|
monthlyPremium | monthly_premium | integer. The amount, in cents, of the monthly premium, as written on the policy schedule. |
basePremium | base_premium | integer. The amount, in cents, of the minimum allowed monthly premium fee. This includes risk pricing and platform fees. |
billingAmount | billing_amount | integer. Deprecated — do not use. The amount, in cents, that will be billed on the next billing run. If less than monthly_premium, the difference is seen as a 'discount.' Can be updated to between base_premium and monthly_premium, inclusive. |
billingDay | billing_day | integer or null. The day of month on which the policy is billed. Should be between 1 and 31, or null. If it falls on a day that does not exist in the month (for example, 31 in February) the policy will be billed on the last day of the month. Setting this value to 31 will ensure that the policy is billed on the last day of every month. |
sumAssured | sum_assured | integer. The amount, in cents, of the total value insured. May be excluded for group scheme policies. |
module | module | object. Custom module-specific fields stored against the policy. Replaces the entire module object — prefer update_policy_module_data for partial updates. |
packageName | package_name | string. A free-text label for the policy's package. Stored as-is with no validation. Included in the policy search index. |
Top-level properties
| Property name | Definition |
|---|---|
name | string. Specifies the action to be performed. Must equal one of the predefined action names. |
data | object. New data with which to update existing policy data. In the case of update_policy, this object will reference standard top-level policy fields. |
Change policy balance
Debit policy
This action creates a new ledger entry debiting the policy. If the policy has an outstanding (negative) balance, this action will increase the outstanding balance in absolute terms. If the policy is in credit (has a positive balance), the balance will be reduced.
{
name: 'debit_policy',
amount: 100000,
description: 'Reactivation penalty',
currency: 'USD'
}Credit policy
This action creates a new ledger entry crediting the policy. If the policy has an outstanding (negative) balance, this will reduce the outstanding balance in absolute terms. If the policy is in credit (has a positive balance), this action will increase it.
{
name: 'credit_policy',
amount: policy.balance,
description: 'Forgive outstanding policy balance',
currency: 'USD'
}Properties
| Property name | Definition |
|---|---|
name | string. Specifies the action to be performed. Must equal one of the predefined action names. |
amount | integer. Required. The amount, in cents, with which to change the policy balance. |
description optional | string. The description of the ledger entry that will be created to debit or credit the policy. |
currency optional | string. Three-letter currency code representing the currency in which the policy will be debited or credited. Should match the product module currency. E.g. "USD" or "ZAR". |
Update claim data
update_claim_module_data
update_claim_module_dataThe update_claim_module_data action allows you to update the custom module data stored on a claim from within claim-related lifecycle hooks. It works similarly to update_policy_module_data but targets the claim's module data instead of the policy's.
{
name: 'update_claim_module_data',
data: {
// Object with fields to merge into claim.module
}
}Properties:
name(string, required): Must be'update_claim_module_data'data(object, required): An object containing the fields to merge into the claim's existing module data
How it works
When this action is executed, the provided data object is shallow-merged into the existing claim module data:
- Existing fields not in your
dataobject are preserved - Fields in your
dataobject overwrite existing fields with the same key - New fields in your
dataobject are added
Claim context required
Only lifecycle hooks that receive a claim object can use update_claim_module_data. Using it from a hook without a claim in context (e.g. afterPaymentSuccess) will throw an error.
Supported hooks include:
afterPolicyLinkedToClaimafterClaimApprovedafterClaimBlockUpdatedbeforeClaimSentToReviewafterClaimSentToReviewbeforeClaimSentToCaptureafterClaimSentToCaptureafterClaimClosed
Example: track claim workflow state
const afterClaimSentToReview = ({ policy, policyholder, claim }) => {
return [
{
name: 'update_claim_module_data',
data: {
review_started_at: moment().format(),
workflow_stage: 'in_review',
},
},
];
};Example: combined with other actions
const afterClaimApproved = ({ policy, policyholder, claim }) => {
return [
{
name: 'update_claim_module_data',
data: {
approved_at: moment().format(),
},
},
{
name: 'trigger_custom_notification_event',
custom_event_key: 'claim_approved_notification',
custom_event_type: 'claim',
claim_id: claim.claim_id,
},
];
};Important notes
- Merge behavior: The data is merged, not replaced. To remove a field, explicitly set it to
null. - Validation skipped: The update is performed without schema validation, so any module data can be stored.
- Use for audit trails: This action is useful for storing audit information, calculated values, or workflow state that should be tracked on the claim itself.
Limitations — what this action cannot do
This action can ONLY update the module field on a claim. It cannot modify any other claim properties:
status(open, in_review, closed, etc.)approval_status(approved, repudiated, goodwill, no_claim)claimantdetailsincident_dateincident_causeblocksorblock_states- Any other top-level claim fields
Trigger custom notification event
This action is used to trigger a custom notification event from the product module code.
{
name: 'trigger_custom_notification_event',
custom_event_key: 'policyholder_birthday',
custom_event_type: 'policy',
policy_id: policy.policy_id,
}Properties
| Property name | Definition |
|---|---|
name | string. Specifies the action to be performed. In this case, trigger_custom_notification_event. |
custom_event_key | string. The key of the custom event to trigger. Must be a token: alphanumeric characters and underscores only (no spaces or hyphens). |
custom_event_type | string. The type of the custom event to trigger. Must be one of [policy, payment_method, payment, claim]. |
policy_id optional | string. The UUID of the policy for which to trigger the notification. Required if custom_event_type is policy or payment_method, forbidden otherwise. |
payment_id optional | string. The UUID of the payment for which to trigger the notification. Required if custom_event_type is payment, forbidden otherwise. |
claim_id optional | string. The UUID of the claim for which to trigger the notification. Required if custom_event_type is claim, forbidden otherwise. |
Archive alteration package
This action archives the policy alteration package specified. Only pending alteration packages can be archived.
{
name: 'archive_alteration_package',
alteration_package_id: '184fa9a3-f967-4a98-9d8f-57152e7cbe64'
}Properties
| Property name | Definition |
|---|---|
name | string. Specifies the action to be performed. Must equal one of the predefined action names. |
alteration_package_id | string. Required. The UUID of the policy alteration package to archive. |
Manage instructions
Instructions are the platform's preferred mechanism for scheduling work at a future date and time — anniversary benefit resets, time-bounded reminders, deferred state changes. Three actions let product module code schedule and cancel them.
Add instruction
Schedules the named product module function to run at a specific future datetime for the current policy.
{
name: 'add_instruction',
function_name: 'reset_benefit_home_contents_theft',
module: {
benefit_key: 'home_contents_theft',
},
execution_datetime: '2026-06-01T14:00:00.000Z',
description: 'Reset the home contents theft benefit on its anniversary',
}| Property name | Definition |
|---|---|
name | string. add_instruction. |
function_name | string. Required. The product module function to invoke at execution time. |
module | object. Required. Free-form payload passed to the function as instruction_data. |
execution_datetime | string. Required. ISO datetime. Must be at least 15 minutes in the future and land on a 30-minute boundary (:00 or :30). |
description optional | string. Human-readable description. Surfaces in admin tooling and logs. |
hidden optional | boolean. Default false. Hides the instruction from standard listings. |
manually_executable optional | boolean. Default false. Allows triggering via the API before execution_datetime. |
claim_id optional | string. UUID. Associates the instruction with a claim. In a claim lifecycle hook, defaults to the context claim when omitted. |
Exact duplicates are idempotent — re-returning the same add_instruction from a hook that fires multiple times creates the instruction only once. See the Instructions guide for full validation, ordering, and failure-mode details.
Cancel instruction
Cancels a single pending instruction by ID.
{
name: 'cancel_instruction',
instruction_id: 'aabbccdd-1122-3344-5566-778899aabbcc',
}| Property name | Definition |
|---|---|
name | string. cancel_instruction. |
instruction_id | string. Required. The UUID of the pending instruction to cancel. |
Bulk cancel instructions
Cancels all matching pending instructions for the current policy in one go — useful on policy lapse or when a benefit is removed. The policy is taken from the lifecycle-hook context.
{
name: 'bulk_cancel_instructions',
function_name: 'reset_benefit_home_contents_theft',
}| Property name | Definition |
|---|---|
name | string. bulk_cancel_instructions. |
function_name optional | string. Cancels only pending instructions for that function. Omit to cancel pending instructions for all functions on the policy. |
claim_id optional | string. UUID. Cancels only pending instructions associated with that claim. In a claim lifecycle hook, defaults to the context claim. |
The action is safe to return defensively: if nothing matches, it's a no-op.
Create a task
Creates an automated task for back-office workflows, referencing the current policy or claim.
Feature flag requiredThe
create_taskaction requires the task management feature to be enabled for your organization. If the feature is not enabled, the action is skipped (with a warning) rather than failing the hook. Contact Root support to enable it.
{
name: 'create_task',
task_name: 'Review flagged claim',
priority: 'high',
description: 'Claim flagged for manual review by fraud rules',
reference_type: 'claim',
dedupe_key: `fraud-review-${claim.claim_id}`,
}| Property name | Definition |
|---|---|
name | string. create_task. |
task_name | string. Required. The name of the task. |
priority | string. Required. The task priority. |
status optional | string. The initial task status. |
description optional | string. A description of the task. |
reference_type optional | string. One of policy, claim. What the task references — the referenced entity is taken from the hook context. claim requires a claim in the hook context. |
trigger_key optional | string. Identifies the trigger that created the task. |
dedupe_key optional | string. Prevents duplicate tasks — a task with the same dedupe key is only created once. |
assigned_to_user_id optional | string. UUID of the user to assign the task to. |
assigned_to_group_id optional | string. UUID of the group to assign the task to. |
Updated 2 days ago