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:

Action objects are returned inside an array, allowing multiple actions to be returned by the same function.

📘

Actions are executed in the order specified

Actions are executed in the same order as specified in the actions array 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 nameDefinition
namestring. cancel_policy.
cancellation_requestorstring. 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_typestring. 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 optionalstring. 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 nameDefinition
namestring. 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 in camelCase

In the update_policy action object, the names of the properties under the data object are specified in camelCase. These properties correspond to snake_case field names on the policy object. For example, sumAssured in the data object corresponds to sum_assured on 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.

📘

packageName is free text

The 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 packageName does 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 same update_policy action.

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:

  1. Merge selected fields into the existing module object using the dedicated update_policy_module_data action. This is the preferred mechanism.
  2. Replace the entire module object using update_policy with data.module — reserve this for the rare case where you genuinely need to replace the object wholesale.
📘

Prefer update_policy_module_data

update_policy_module_data merges 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 via update_policy overwrites 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 nameDefinition
namestring. update_policy_module_data.
dataobject. Required. Fields to merge into the policy's existing module data.

Replace the module object (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:

  1. Construct the new module object from the existing policy module object, which is passed to the function as policy.module.
  2. 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 nameCorresponding policy fieldDefinition
monthlyPremiummonthly_premiuminteger. The amount, in cents, of the monthly premium, as written on the policy schedule.
basePremiumbase_premiuminteger. The amount, in cents, of the minimum allowed monthly premium fee. This includes risk pricing and platform fees.
billingAmountbilling_amountinteger. 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.
billingDaybilling_dayinteger 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.
sumAssuredsum_assuredinteger. The amount, in cents, of the total value insured. May be excluded for group scheme policies.
modulemoduleobject. Custom module-specific fields stored against the policy. Replaces the entire module object — prefer update_policy_module_data for partial updates.
packageNamepackage_namestring. 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 nameDefinition
namestring. Specifies the action to be performed. Must equal one of the predefined action names.
dataobject. 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 nameDefinition
namestring. Specifies the action to be performed. Must equal one of the predefined action names.
amountinteger. Required. The amount, in cents, with which to change the policy balance.
description optionalstring. The description of the ledger entry that will be created to debit or credit the policy.
currency optionalstring. 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

The 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 data object are preserved
  • Fields in your data object overwrite existing fields with the same key
  • New fields in your data object 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:

  • afterPolicyLinkedToClaim
  • afterClaimApproved
  • afterClaimBlockUpdated
  • beforeClaimSentToReview
  • afterClaimSentToReview
  • beforeClaimSentToCapture
  • afterClaimSentToCapture
  • afterClaimClosed

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

  1. Merge behavior: The data is merged, not replaced. To remove a field, explicitly set it to null.
  2. Validation skipped: The update is performed without schema validation, so any module data can be stored.
  3. 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)
  • claimant details
  • incident_date
  • incident_cause
  • blocks or block_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 nameDefinition
namestring. Specifies the action to be performed. In this case, trigger_custom_notification_event.
custom_event_keystring. The key of the custom event to trigger. Must be a token: alphanumeric characters and underscores only (no spaces or hyphens).
custom_event_typestring. The type of the custom event to trigger. Must be one of [policy, payment_method, payment, claim].
policy_id optionalstring. 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 optionalstring. The UUID of the payment for which to trigger the notification. Required if custom_event_type is payment, forbidden otherwise.
claim_id optionalstring. 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 nameDefinition
namestring. Specifies the action to be performed. Must equal one of the predefined action names.
alteration_package_idstring. 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 nameDefinition
namestring. add_instruction.
function_namestring. Required. The product module function to invoke at execution time.
moduleobject. Required. Free-form payload passed to the function as instruction_data.
execution_datetimestring. Required. ISO datetime. Must be at least 15 minutes in the future and land on a 30-minute boundary (:00 or :30).
description optionalstring. Human-readable description. Surfaces in admin tooling and logs.
hidden optionalboolean. Default false. Hides the instruction from standard listings.
manually_executable optionalboolean. Default false. Allows triggering via the API before execution_datetime.
claim_id optionalstring. 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 nameDefinition
namestring. cancel_instruction.
instruction_idstring. 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 nameDefinition
namestring. bulk_cancel_instructions.
function_name optionalstring. Cancels only pending instructions for that function. Omit to cancel pending instructions for all functions on the policy.
claim_id optionalstring. 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 required

The create_task action 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 nameDefinition
namestring. create_task.
task_namestring. Required. The name of the task.
prioritystring. Required. The task priority.
status optionalstring. The initial task status.
description optionalstring. A description of the task.
reference_type optionalstring. 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 optionalstring. Identifies the trigger that created the task.
dedupe_key optionalstring. Prevents duplicate tasks — a task with the same dedupe key is only created once.
assigned_to_user_id optionalstring. UUID of the user to assign the task to.
assigned_to_group_id optionalstring. UUID of the group to assign the task to.

Did this page help you?