Restricted data
Overview
Root allows your product module code to store sensitive, product-specific data on quotes, applications, and policies using the restricted_data field. This field works alongside the standard module field, but its visibility in API responses is controlled by permissions — allowing you to hide sensitive information from certain API consumers.
Common use cases for restricted data include:
- Underwriting details that should not be visible to end users or embedded flows.
- Internal pricing breakdowns such as risk scores, reinsurance premiums, or loss ratios.
- Compliance-related fields that only authorised back-office users should access.
The restricted_data field is available on quotes, applications, and policies. It is returned as a top-level field on the API response object, separate from the module field.
Protected featureRestricted data is a protected feature, and is disabled by default. To enable this feature for your organisation, please contact our support team at [email protected].
Returning restricted data from hooks
You can return restricted_data from any product module hook that produces a quote, application, or policy object. The field is optional — if you don't include it, the API response will simply not contain a restricted_data field.
Quote hook
The getQuote() function can return a restricted_data object alongside the standard quote fields. This data is saved to the quote package and carried through to subsequent steps in the policy issue flow.
const getQuote = (data) => {
const basePremium = calculateBasePremium(data);
const riskScore = calculateRiskScore(data);
return new QuotePackage({
package_name: 'comprehensive_cover',
sum_assured: data.cover_amount,
base_premium: basePremium,
suggested_premium: basePremium,
module: {
cover_type: data.cover_type,
cover_amount: data.cover_amount,
},
restricted_data: {
risk_score: riskScore,
underwriting_notes: 'Auto-accepted based on risk profile',
reinsurance_premium: Math.round(basePremium * 0.35),
},
});
};Application hook
The getApplication() function can also return restricted_data. Typically, you would carry over the restricted data from the quote package and add any additional sensitive application-specific information.
const getApplication = (data, policyholder, quote_package) => {
return new Application({
package_name: quote_package.package_name,
sum_assured: quote_package.sum_assured,
base_premium: quote_package.base_premium,
monthly_premium: quote_package.suggested_premium,
module: {
...quote_package.module,
...data,
},
restricted_data: {
...quote_package.restricted_data,
kyc_status: 'verified',
screening_result: 'clear',
},
input_data: data,
});
};Policy issue hook
The getPolicy() function can include restricted_data on the policy object. The restricted data will persist on the policy for its entire lifecycle and can be referenced in lifecycle hooks and scheduled functions.
const getPolicy = (application, policyholder, billing_day) => {
return new Policy({
package_name: application.package_name,
sum_assured: application.sum_assured,
base_premium: application.base_premium,
monthly_premium: application.monthly_premium,
start_date: moment().add(1, 'day').format(),
end_date: moment().endOf('month').add(1, 'year').format(),
module: {
...application.module,
},
restricted_data: {
...application.restricted_data,
issued_by_system: true,
},
});
};Requote hook
When a policy is requoted using the requotePolicy() function, you can update or preserve the restricted_data on the requoted policy.
const requotePolicy = (policy, requote_data) => {
const newPremium = recalculatePremium(policy, requote_data);
return new RequotePolicy({
package_name: policy.package_name,
sum_assured: policy.sum_assured,
base_premium: newPremium,
monthly_premium: newPremium,
module: {
...policy.module,
...requote_data,
},
restricted_data: {
...policy.restricted_data,
previous_premium: policy.monthly_premium,
requote_reason: requote_data.reason,
},
});
};
Carry restricted data through the flowIf you set
restricted_dataat the quote step, remember to carry it forward to the application and policy hooks. The platform does not automatically propagaterestricted_databetween steps — your product module code controls what is included at each stage.
How restricted data is stored
The restricted_data field is stored alongside the module column. It is not nested inside the module object. This means:
- Restricted data does not affect or interfere with the standard
modulefield. - Restricted data is persisted independently on
quote_packages,applications, andpoliciestables. - Restricted data can be queried and filtered independently of module data in data exports.
Access control
Visibility of restricted_data in API responses is determined by the requestee's identity and permissions. The platform evaluates access at the HTTP layer before returning data to the caller.
Access rules by requestee type
| Requestee type | Access to restricted_data | Details |
|---|---|---|
| Embed JWT | Never | Embed tokens represent end users and should never see restricted data. |
| Product module code | Always | Internal product module code (lifecycle hooks, scheduled functions) always has full access. |
| API keys & dashboard users | Permission-based | Access depends on whether the requestee has the required domain-specific permission. |
Required permissions
Each domain (quotes, applications, policies) has its own permission that controls access to restricted data. These permissions can be assigned to roles in the Root management dashboard.
| Domain | Permission |
|---|---|
| Quotes | ReadQuoteRestrictedModuleData |
| Applications | ReadApplicationRestrictedModuleData |
| Policies | ReadRestrictedModuleData |
When a requestee does not have the required permission, the restricted_data field is excluded from the API response entirely — it will not appear as null or an empty object.
Webhooks always include restricted dataWebhook payloads always include
restricted_dataregardless of the access rules described above. This is because webhooks are system-level events intended for server-to-server integrations where the data consumer is trusted.
API response examples
The examples below show how the restricted_data field appears in API responses depending on the requestee's access level.
With access
When the requestee has the required permission, the full restricted_data object is included in the response.
{
"policy_id": "128ba0c0-3f6a-4f8b-9b40-e2066b02b59e",
"status": "active",
"package_name": "comprehensive_cover",
"monthly_premium": 15000,
"module": {
"cover_type": "comprehensive",
"cover_amount": 50000000
},
"restricted_data": {
"risk_score": 42,
"underwriting_notes": "Auto-accepted based on risk profile",
"reinsurance_premium": 5250,
"kyc_status": "verified"
}
}Without access
When the requestee does not have the required permission (or is using an Embed JWT), the restricted_data field is omitted from the response.
{
"policy_id": "128ba0c0-3f6a-4f8b-9b40-e2066b02b59e",
"status": "active",
"package_name": "comprehensive_cover",
"monthly_premium": 15000,
"module": {
"cover_type": "comprehensive",
"cover_amount": 50000000
}
}Restricted data in lifecycle hooks
When your product module code runs in response to lifecycle events or scheduled functions, the restricted_data field is always available on the policy, application, and quote objects passed as arguments. This allows you to reference sensitive data in your business logic without exposing it to external consumers.
const afterPaymentSuccess = (policy, payment) => {
const riskScore = policy.restricted_data?.risk_score;
if (riskScore > 80) {
return [actions.sendCustomNotification('high_risk_payment_received', policy.policy_id)];
}
return [];
};Restricted data and alteration hooks
When an alteration package is applied to a policy, you can update the restricted_data on the altered policy using the applyAlteration() function.
const applyAlteration = (policy, alteration_package) => {
const newPremium = recalculatePremium(policy, alteration_package);
return new AlteredPolicy({
package_name: policy.package_name,
sum_assured: alteration_package.sum_assured || policy.sum_assured,
base_premium: newPremium,
monthly_premium: newPremium,
module: {
...policy.module,
...alteration_package.module,
},
restricted_data: {
...policy.restricted_data,
previous_premium: policy.monthly_premium,
alteration_applied_at: new Date().toISOString(),
},
});
};Best practices
- Separate concerns — Use
modulefor data that should be visible to all API consumers (including embedded flows), andrestricted_datafor sensitive information that should be limited to authorised users. - Carry data forward — If you set restricted data at the quote step, explicitly include it in subsequent hooks (application, policy issue). The platform does not auto-propagate between steps.
- Don't duplicate — Avoid storing the same data in both
moduleandrestricted_data. Choose one location based on the data's sensitivity. - Plan for webhooks — Remember that
restricted_datais always included in webhook payloads. Ensure your webhook consumers handle this data securely.
Related guides
Updated about 16 hours ago