Skip to main content
Version: Latest (4.5.0)

Function: Flow(config, triggerInstance, body)

Creates a Flow record (sys_hub_flow) that defines a series of actions to execute when triggered.

Parameters

config

FlowDefinition<Record<string, FlowValueType>>

Flow configuration — name, description, priority, variables, and protection settings.

Properties:

  • $id (required): string | number | ExplicitKey<string>

  • name (required): string

  • description (optional): string

  • flowPriority (optional): 'LOW' | 'MEDIUM' | 'HIGH'

  • flowVariables (optional): Record<string, FlowValueType>

  • protection (optional): '' | 'read'

  • runAs (optional): 'user' | 'system'

  • runWithRoles (optional): (string | Role)[]

triggerInstance

undefined | ReturnType<TriggerInstance>

The trigger that starts this flow, created by calling wfa.trigger.

body (optional)

(params: FlowBodyParams<ReturnType<TriggerInstance>, OutputsWithDotwalk<Record<string, FlowValueType>>>) => void

The flow body function. Receives params containing trigger (the trigger outputs) and flowVariables (any flow-level variables declared in config).

Function Parameters:

  • params: FlowBodyParams<F, OutputsWithDotwalk<V>>
    • flowVariables: Record<string, FlowValueType>

    • trigger: I

Examples

Basic Flow Example

Demonstrates basic usage of the Flow function to create a Flow that fires an event when an incident is created.

/**
* @title Basic Flow Example
* @description Demonstrates basic usage of the Flow function to create a Flow that fires an event when an incident is created.
*/
import { action, Flow, wfa, trigger } from '@servicenow/sdk/automation'

export const testFireEvent = Flow(
{
$id: Now.ID['test_fire_event_flow'],
name: 'Test Fire Event',
description: 'Tests the fireEvent core action',
},
wfa.trigger(
trigger.record.created,
{ $id: Now.ID['test_fire_event_trigger'] },
{
table: 'incident',
condition: 'active=true',
run_flow_in: 'background',
}
),
(params) => {
wfa.action(
action.core.fireEvent,
{ $id: Now.ID['test_fire_event_action'] },
{
event_name: 'custom.incident.created',
table: 'incident',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
parm1: 'Test parameter 1',
parm2: 'Test parameter 2',
}
)

wfa.action(
action.core.log,
{ $id: Now.ID['test_fire_event_log'] },
{
log_level: 'info',
log_message: 'no output',
}
)
}
)

Service Catalog Trigger Flow

Demonstrates service catalog flows with variable sets, approval handling, and catalog task creation using the serviceCatalog trigger.

/**
* @title Service Catalog Trigger Flow
* @description Demonstrates service catalog flows with variable sets, approval handling, and catalog task creation using the serviceCatalog trigger.
*/
import { Flow, wfa, action, trigger } from '@servicenow/sdk/automation'
import {
CatalogItem,
VariableSet,
HtmlVariable,
EmailVariable,
IpAddressVariable,
LabelVariable,
MultiLineTextVariable,
RichTextLabelVariable,
SingleLineTextVariable,
UrlVariable,
YesNoVariable,
ReferenceVariable,
StringColumn,
} from '@servicenow/sdk/core'

// Variable Sets - defined using VariableSet plugin with variables
const userInfoVarSet = VariableSet({
$id: Now.ID['user_info_varset'],
title: 'User Information',
description: 'Basic user information required for this request',
internalName: 'user_info_varset',
type: 'singleRow',
layout: 'normal',
order: 100,
displayTitle: true,
version: 4,
variables: {
userName: ReferenceVariable({
question: 'User Name',
referenceTable: 'sys_user',
mandatory: true,
order: 100,
tooltip: 'user name',
}),
userEmail: EmailVariable({
question: 'Email Address',
mandatory: true,
order: 200,
}),
userPhone: SingleLineTextVariable({
question: 'Phone Number',
order: 300,
}),
},
name: 'User information',
})

const softwareInstallationCatalogItem = CatalogItem({
$id: Now.ID['software_installation_catalog_item'],
flow: Now.ref('sys_hub_flow', 'test_flow_for_service_catalog'),
name: 'Software Installation Test',
shortDescription: 'Request software installation test',
description: 'Use this form to request installation of software on your company device.',
variables: {
email: EmailVariable({
question: 'Email',
order: 12,
}),
html: HtmlVariable({
question: 'HTML',
order: 13,
mandatory: true,
}),
ipAddress: IpAddressVariable({
question: 'IP Address',
order: 14,
}),
label: LabelVariable({
question: 'Label',
order: 15,
}),
multilineText: MultiLineTextVariable({
question: 'Multi-line Text',
order: 20,
}),
richTextLabel: RichTextLabelVariable({
richText: 'Rich Text Label',
order: 25,
}),
url: UrlVariable({
question: 'URL',
order: 30,
}),
yesNo: YesNoVariable({
question: 'Yes No',
includeNone: true,
order: 32,
}),
singleline: SingleLineTextVariable({
question: 'singleline',
order: 330,
}),
},
variableSets: [{ variableSet: userInfoVarSet, order: 100 }],
ignorePrice: false,
})

Flow(
{
$id: Now.ID['test_flow_for_service_catalog'],
name: 'Test flow for service catalog using fluent',
description: 'Test flow for service catalog using fluent desc',
flowVariables: {
approverUser1: StringColumn({
label: 'Approver User 1',
mandatory: true,
}),
},
},
wfa.trigger(
trigger.application.serviceCatalog,
{ $id: Now.ID['test_flow_for_service_catalog_trigger'] },
{
run_flow_in: 'background',
}
),
(params) => {
wfa.flowLogic.setFlowVariables(
{
$id: Now.ID['init_approval_vars'],
annotation: 'Initialize approval variables',
},
params.flowVariables,
{
approverUser1: '62826bf03710200044e0bfc8bcbe5df1',
}
)

const getCatalogVariablesAction = wfa.action(
action.core.getCatalogVariables,
{
$id: Now.ID['test_flow_for_service_catalog_step1'],
annotation: 'Get catalog variables for Apple iPhone 13',
},
{
requested_item: `${wfa.dataPill(params.trigger.request_item, 'reference')}`,
template_catalog_item: `${softwareInstallationCatalogItem}`,
catalog_variables: [
softwareInstallationCatalogItem.variables.html,
softwareInstallationCatalogItem.variables.email,
softwareInstallationCatalogItem.variables.ipAddress,
softwareInstallationCatalogItem.variables.userName,
softwareInstallationCatalogItem.variables.userEmail,
softwareInstallationCatalogItem.variables.userPhone,
],
}
)

wfa.flowLogic.if(
{
$id: Now.ID['test_flow_for_service_catalog_if_condition'],
annotation: 'Check if email is test@gmail.com and phone is 999999999',
condition: `${wfa.dataPill(getCatalogVariablesAction.email, 'email')}=test@gmail.com^${wfa.dataPill(getCatalogVariablesAction.userPhone, 'string')}=999999999`,
},
() => {
const askForApprovalAction = wfa.action(
action.core.askForApproval,
{
$id: Now.ID['test_flow_for_service_catalog_ask_for_approval'],
annotation: 'Ask for approval',
},
{
record: `${wfa.dataPill(params.trigger.request_item, 'reference')}`,
table: 'sc_req_item',
approval_reason:
'Approval required for catalog request with email test@gmail.com and phone 999999999.',
approval_field: 'approval',
approval_conditions: wfa.approvalRules({
conditionType: 'OR',
ruleSets: [
{
action: 'Approves',
conditionType: 'AND',
rules: [
[
{
ruleType: 'Any',
users: [wfa.dataPill(params.flowVariables.approverUser1, 'string')],
groups: [],
manual: false,
},
],
],
},
],
}),
}
)

wfa.flowLogic.if(
{
$id: Now.ID['test_flow_for_service_catalog_if_approved'],
annotation: 'Check if approval state is Approved',
condition: `${wfa.dataPill(askForApprovalAction.approval_state, 'string')}=approved`,
},
() => {
const createCatalogTaskAction = wfa.action(
action.core.createCatalogTask,
{
$id: Now.ID['test_flow_for_service_catalog_create_task'],
annotation: 'Create catalog task for approved request',
},
{
ah_requested_item: `${wfa.dataPill(params.trigger.request_item, 'reference')}`,
ah_short_description: 'Complete the approved software installation request',
template_catalog_item: `${softwareInstallationCatalogItem}`,
catalog_variables: [
softwareInstallationCatalogItem.variables.email,
softwareInstallationCatalogItem.variables.html,
softwareInstallationCatalogItem.variables.ipAddress,
],
ah_wait: true,
}
)

wfa.flowLogic.if(
{
$id: Now.ID['test_flow_for_service_catalog_if_task_closed'],
annotation: 'Check if catalog task is Closed Complete',
condition: `${wfa.dataPill(createCatalogTaskAction.catalog_task.state, 'string')}=3`,
},
() => {
wfa.action(
action.core.updateRecord,
{
$id: Now.ID['test_flow_for_service_catalog_update_record'],
annotation: 'Update requested item state to Closed Complete',
},
{
table_name: 'sc_req_item',
record: `${wfa.dataPill(params.trigger.request_item, 'reference')}`,
values: TemplateValue({
state: '3',
}),
}
)
}
)
}
)

wfa.flowLogic.else(
{
$id: Now.ID['test_flow_for_service_catalog_else_not_approved'],
annotation: 'Handle not approved - update state to Closed Incomplete',
},
() => {
wfa.action(
action.core.updateRecord,
{
$id: Now.ID['test_flow_for_service_catalog_update_closed_incomplete'],
annotation: 'Update requested item state to Closed Incomplete',
},
{
table_name: 'sc_req_item',
record: `${wfa.dataPill(params.trigger.request_item, 'reference')}`,
values: TemplateValue({
state: '4',
}),
}
)
}
)
}
)

wfa.action(
action.core.log,
{
$id: Now.ID['test_flow_for_service_catalog_step2'],
annotation: 'Log catalog variable color value',
},
{
log_level: 'info',
log_message: `Catalog variable, html = ${wfa.dataPill(getCatalogVariablesAction.email, 'email')} ${wfa.dataPill(getCatalogVariablesAction.html, 'html')} ${wfa.dataPill(getCatalogVariablesAction.ipAddress, 'string')} `,
}
)
}
)

// Example Flow: Create Catalog Task with Variables
Flow(
{
$id: Now.ID['create_catalog_task_flow'],
name: 'Create Catalog Task with Variables',
description: 'Demonstrates creating a catalog task with variables from a template catalog item',
},
wfa.trigger(
trigger.application.serviceCatalog,
{ $id: Now.ID['create_catalog_task_trigger'] },
{
run_flow_in: 'background',
}
),
(params) => {
const createTaskAction = wfa.action(
action.core.createCatalogTask,
{
$id: Now.ID['create_catalog_task_step1'],
annotation: 'Create catalog task for software installation approval',
},
{
ah_requested_item: `${wfa.dataPill(params.trigger.request_item, 'reference')}`,
ah_short_description: 'Review and approve software installation request',
template_catalog_item: `${softwareInstallationCatalogItem}`,
catalog_variables: [
softwareInstallationCatalogItem.variables.email,
softwareInstallationCatalogItem.variables.html,
softwareInstallationCatalogItem.variables.ipAddress,
softwareInstallationCatalogItem.variables.singleline,
softwareInstallationCatalogItem.variables.userName,
],
ah_wait: true,
}
)

wfa.action(
action.core.log,
{
$id: Now.ID['create_catalog_task_step2'],
annotation: 'Log catalog task creation',
},
{
log_level: 'info',
log_message: `Catalog Task Created: ${wfa.dataPill(createTaskAction.catalog_task, 'reference')}. Status: ${wfa.dataPill(createTaskAction.__action_status__.message, 'string')}`,
}
)
}
)

Inbound Email Trigger Flow

Processes inbound emails to create P1 tasks for internal senders or a P3 incident with copied attachments for all others.

/**
* @title Inbound Email Trigger Flow
* @description Processes inbound emails to create P1 tasks for internal senders or a P3 incident with copied attachments for all others.
*/
import { action, Flow, wfa, trigger } from '@servicenow/sdk/automation'

export const emailIncidentTaskFlow = Flow(
{
$id: Now.ID['email_incident_task_flow'],
name: 'Email Incident/Task Creation Flow',
description: 'Creates incidents or tasks based on email content with "raise incident or task" in subject',
},
wfa.trigger(
trigger.application.inboundEmail,
{ $id: Now.ID['inbound_email_trigger'] },
{
email_conditions: 'subjectLIKEraise incident or task',
target_table: 'incident',
}
),
(params) => {
wfa.action(
action.core.log,
{ $id: Now.ID['log_email_received'] },
{
log_level: 'info',
log_message: `Email received from: ${wfa.dataPill(params.trigger.from_address, 'string')}, Subject: ${wfa.dataPill(params.trigger.subject, 'string')}`,
}
)

const sender = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_sender'] },
{
table: 'sys_user',
conditions: `email=${wfa.dataPill(params.trigger.from_address, 'string')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

// Internal P1 path — two tasks
wfa.flowLogic.if(
{
$id: Now.ID['check_internal_p1'],
condition: `${wfa.dataPill(sender.Record.email, 'string')}LIKEservicenow^${wfa.dataPill(params.trigger.subject, 'string')}LIKEP1`,
annotation: 'Internal sender with P1 subject',
},
() => {
const senderManager = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_sender_manager'] },
{
table: 'sys_user',
conditions: `sys_id=${wfa.dataPill(sender.Record.manager, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.action(
action.core.createTask,
{ $id: Now.ID['task_for_manager'] },
{
task_table: 'incident',
field_values: TemplateValue({
priority: 1,
assigned_to: wfa.dataPill(senderManager.Record.sys_id, 'reference'),
short_description: wfa.dataPill(params.trigger.inbound_email.body, 'reference'),
urgency: 1,
impact: 1,
}),
}
)

wfa.action(
action.core.createTask,
{ $id: Now.ID['task_for_sender'] },
{
task_table: 'incident',
field_values: TemplateValue({
priority: 1,
assigned_to: wfa.dataPill(sender.Record.sys_id, 'reference'),
short_description: wfa.dataPill(params.trigger.subject, 'string'),
urgency: 1,
impact: 1,
}),
}
)
}
)

// External / non-P1 path — P3 incident + copy attachments
wfa.flowLogic.else({ $id: Now.ID['create_p3_incident_branch'] }, () => {
const p3Incident = wfa.action(
action.core.createRecord,
{ $id: Now.ID['create_p3_incident'] },
{
table_name: 'incident',
values: TemplateValue({
priority: 4,
short_description: wfa.dataPill(params.trigger.subject, 'string'),
description: `From: ${wfa.dataPill(params.trigger.from_address, 'string')}\n\n${wfa.dataPill(params.trigger.inbound_email.body, 'reference')}`,
contact_type: 'email',
caller_id: wfa.dataPill(sender.Record.sys_id, 'reference'),
}),
}
)

const attachments = wfa.action(
action.core.getAttachmentsOnRecord,
{ $id: Now.ID['get_email_attachments'] },
{ source_record: wfa.dataPill(params.trigger.inbound_email.sys_id, 'reference') }
)

wfa.flowLogic.forEach(
wfa.dataPill(attachments.parameter, 'records'),
{ $id: Now.ID['copy_attachments_loop'] },
() => {
wfa.action(
action.core.copyAttachment,
{ $id: Now.ID['copy_attachment'] },
{
target_record: wfa.dataPill(p3Incident.record, 'reference'),
attachment_record: wfa.dataPill(attachments.parameter, 'records'),
table: 'incident',
}
)
}
)

wfa.action(
action.core.sendEmail,
{ $id: Now.ID['confirm_p3_email'] },
{
table_name: 'incident',
ah_to: wfa.dataPill(params.trigger.from_address, 'string'),
ah_subject: `Incident Created: ${wfa.dataPill(params.trigger.subject, 'string')}`,
ah_body: `Your request has been received and a P3 incident has been created. Our team will be in touch shortly.`,
record: wfa.dataPill(p3Incident.record, 'reference'),
}
)
})
}
)

Record Trigger Flows

Demonstrates trigger.record.created, trigger.record.updated, and trigger.record.createdOrUpdated to respond to record lifecycle events.

/**
* @title Record Trigger Flows
* @description Demonstrates trigger.record.created, trigger.record.updated, and trigger.record.createdOrUpdated to respond to record lifecycle events.
*/
import { action, Flow, wfa, trigger } from '@servicenow/sdk/automation'

// ── trigger.record.created ────────────────────────────────────────────────────

export const incidentSeverityAlertFlow = Flow(
{
$id: Now.ID['incident_severity_alert_flow'],
name: 'Incident Severity Alert Flow',
description: 'Alerts managers and team members based on incident severity for incidents with empty origin',
},
wfa.trigger(
trigger.record.created,
{ $id: Now.ID['empty_origin_incident_trigger'] },
{
table: 'incident',
condition: 'origin=NULL',
run_flow_in: 'background',
run_on_extended: 'false',
run_when_setting: 'both',
run_when_user_setting: 'any',
run_when_user_list: [],
}
),
(params) => {
wfa.action(
action.core.log,
{ $id: Now.ID['log_incident_short_description'] },
{
log_level: 'info',
log_message: `Incident created: ${wfa.dataPill(params.trigger.current.short_description, 'string')}`,
}
)

wfa.flowLogic.if(
{
$id: Now.ID['check_severity_high'],
condition: `${wfa.dataPill(params.trigger.current.severity, 'string')}=1`,
annotation: 'High severity (1)',
},
() => {
const assignmentGroup = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_assignment_group'] },
{
table: 'sys_user_group',
conditions: `sys_id=${wfa.dataPill(params.trigger.current.assignment_group, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

const manager = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_manager_details'] },
{
table: 'sys_user',
conditions: `sys_id=${wfa.dataPill(assignmentGroup.Record.manager, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.action(
action.core.sendNotification,
{ $id: Now.ID['send_urgent_email_to_manager'] },
{
table_name: 'incident',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
notification: 'high_severity_incident_manager_notification',
}
)

wfa.flowLogic.forEach(
wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string'),
{ $id: Now.ID['foreach_additional_assignees_high'] },
() => {
const assignee = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_assignee_details_high'] },
{
table: 'sys_user',
conditions: `sys_id=${wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.action(
action.core.sendSms,
{ $id: Now.ID['send_sms_to_assignee_high'] },
{
recipients: `${wfa.dataPill(assignee.Record.phone, 'string')}`,
message: `High severity incident: ${wfa.dataPill(params.trigger.current.short_description, 'string')}`,
}
)
}
)

wfa.action(
action.core.updateRecord,
{ $id: Now.ID['update_work_notes_high'] },
{
table_name: 'incident',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
values: TemplateValue({
work_notes: `Manager ${wfa.dataPill(manager.Record.name, 'string')} notified via email and team notified via SMS.`,
}),
}
)
}
)

wfa.flowLogic.elseIf(
{
$id: Now.ID['check_severity_medium'],
condition: `${wfa.dataPill(params.trigger.current.severity, 'string')}=2`,
annotation: 'Medium severity (2)',
},
() => {
wfa.flowLogic.forEach(
wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string'),
{ $id: Now.ID['foreach_additional_assignees_medium'] },
() => {
const assignee = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_assignee_details_medium'] },
{
table: 'sys_user',
conditions: `sys_id=${wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.action(
action.core.sendSms,
{ $id: Now.ID['send_sms_to_assignee_medium'] },
{
recipients: `${wfa.dataPill(assignee.Record.phone, 'string')}`,
message: `Medium severity incident: ${wfa.dataPill(params.trigger.current.short_description, 'string')}`,
}
)
}
)
}
)

wfa.action(
action.core.updateRecord,
{ $id: Now.ID['update_incident_to_in_progress'] },
{
table_name: 'incident',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
values: TemplateValue({ state: '2' }),
}
)
}
)

// ── trigger.record.updated ────────────────────────────────────────────────────

export const changeRequestApprovalNotificationFlow = Flow(
{
$id: Now.ID['change_request_approval_notification_flow'],
name: 'Change Request Approval Notification Flow',
description: 'Sends formatted notification to requester when change request is approved',
},
wfa.trigger(
trigger.record.updated,
{ $id: Now.ID['change_request_approved_trigger'] },
{
table: 'change_request',
condition: 'approval=approved',
run_flow_in: 'background',
trigger_strategy: 'unique_changes',
run_when_user_list: [],
run_when_setting: 'both',
run_on_extended: 'false',
run_when_user_setting: 'any',
}
),
(params) => {
const requester = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_requester_details'] },
{
table: 'sys_user',
conditions: `sys_id=${wfa.dataPill(params.trigger.current.requested_by, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.action(
action.core.sendEmail,
{ $id: Now.ID['send_approval_notification_email'] },
{
table_name: 'change_request',
watermark_email: true,
ah_subject: `Change Request ${wfa.dataPill(params.trigger.current.number, 'string')} - Approved`,
ah_body: `Your change request has been approved.`,
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
ah_to: wfa.dataPill(requester.Record.email, 'string'),
}
)

wfa.action(
action.core.updateRecord,
{ $id: Now.ID['update_work_notes_notification_sent'] },
{
table_name: 'change_request',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
values: TemplateValue({
work_notes: `Approval notification sent to ${wfa.dataPill(requester.Record.name, 'string')} (${wfa.dataPill(requester.Record.email, 'string')})`,
}),
}
)
}
)

// ── trigger.record.createdOrUpdated ──────────────────────────────────────────

export const changeRiskTaggingFlow = Flow(
{
$id: Now.ID['change_risk_tagging_flow'],
name: 'Change Risk Tagging Flow',
description: 'Tags change requests with high-risk label when created or updated with high impact',
},
wfa.trigger(
trigger.record.createdOrUpdated,
{ $id: Now.ID['change_risk_trigger'] },
{
table: 'change_request',
condition: 'active=true^impact=1',
run_flow_in: 'background',
run_on_extended: 'false',
run_when_setting: 'both',
run_when_user_setting: 'any',
run_when_user_list: [],
}
),
(params) => {
wfa.action(
action.core.updateRecord,
{ $id: Now.ID['tag_high_risk'] },
{
table_name: 'change_request',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
values: TemplateValue({
risk: 'high',
work_notes: 'Automatically tagged as high-risk due to high impact.',
}),
}
)

const cab = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_cab_group'] },
{
table: 'sys_user_group',
conditions: 'name=CAB^active=true',
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.action(
action.core.sendNotification,
{ $id: Now.ID['notify_cab_high_risk'] },
{
table_name: 'change_request',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
notification: 'high_risk_change_cab_notification',
}
)

wfa.action(
action.core.log,
{ $id: Now.ID['log_risk_tagged'] },
{
log_level: 'warn',
log_message: `Change ${wfa.dataPill(params.trigger.current.number, 'string')} tagged as high-risk. CAB group ${wfa.dataPill(cab.Record.name, 'string')} notified.`,
}
)
}
)

Remote Table Query Trigger Flow

Enriches user records returned to remote systems with active incident counts using remoteTableQuery trigger.

/**
* @title Remote Table Query Trigger Flow
* @description Enriches user records returned to remote systems with active incident counts using remoteTableQuery trigger.
*/
import { action, Flow, wfa, trigger } from '@servicenow/sdk/automation'

export const remoteUserQueryFlow = Flow(
{
$id: Now.ID['remote_user_query_flow'],
name: 'Remote User Query Enrichment Flow',
description: 'Enriches user records returned to remote systems with active incident counts',
},
wfa.trigger(trigger.application.remoteTableQuery, { $id: Now.ID['remote_query_trigger'] }, {}),
(params) => {
wfa.action(
action.core.log,
{ $id: Now.ID['log_remote_query'] },
{
log_level: 'info',
log_message: `Remote query received - Query ID: ${wfa.dataPill(params.trigger.query_id, 'string')}, Parameters: ${wfa.dataPill(params.trigger.query_parameters, 'string')}, Table: ${wfa.dataPill(params.trigger.table_name, 'string')}}`,
}
)

wfa.flowLogic.if(
{
$id: Now.ID['check_user_table'],
condition: `${wfa.dataPill(params.trigger.table_name, 'table_name')}=sys_user`,
annotation: 'Query is for sys_user table',
},
() => {
const activeUsers = wfa.action(
action.core.lookUpRecords,
{ $id: Now.ID['lookup_active_users'] },
{
table: 'sys_user',
conditions: 'active=true^departmentISNOTEMPTY',
max_results: 500,
sort_column: 'name',
sort_type: 'sort_asc',
}
)

wfa.flowLogic.forEach(
wfa.dataPill(activeUsers.Records, 'records'),
{ $id: Now.ID['foreach_users'] },
() => {
const userIncidents = wfa.action(
action.core.lookUpRecords,
{ $id: Now.ID['lookup_user_incidents'] },
{
table: 'incident',
conditions: `assigned_to=${wfa.dataPill(activeUsers.Records, 'records')}^active=true`,
max_results: 100,
sort_column: 'priority',
sort_type: 'sort_asc',
}
)

wfa.action(
action.core.log,
{ $id: Now.ID['log_user_incident_count'] },
{
log_level: 'info',
log_message: `User enrichment complete — incidents: ${wfa.dataPill(userIncidents.Records, 'records')}`,
}
)
}
)
}
)

wfa.flowLogic.else({ $id: Now.ID['unhandled_table_branch'] }, () => {
wfa.action(
action.core.log,
{ $id: Now.ID['log_unhandled_table'] },
{
log_level: 'warn',
log_message: `Remote query for unhandled table: ${wfa.dataPill(params.trigger.table_name, 'table_name')} — no enrichment applied.`,
}
)
})
}
)

SLA Task Escalation Flow

Escalates tasks at 75% and 90% SLA milestones using slaPercentageTimer, then waits for resolution and sends confirmation.

/**
* @title SLA Task Escalation Flow
* @description Escalates tasks at 75% and 90% SLA milestones using slaPercentageTimer, then waits for resolution and sends confirmation.
*/
import { action, Flow, wfa, trigger } from '@servicenow/sdk/automation'

export const slaTaskEscalationFlow = Flow(
{
$id: Now.ID['sla_task_escalation_flow'],
name: 'SLA Task Escalation Flow',
description: 'Escalates tasks at 75% and 90% SLA milestones and confirms resolution',
},
wfa.trigger(trigger.application.slaTask, { $id: Now.ID['sla_task_trigger'] }, {}),
(params) => {
// ── 75% milestone ────────────────────────────────────────────────────────
wfa.action(
action.core.slaPercentageTimer,
{ $id: Now.ID['wait_75_percent'], annotation: 'Pause until 75% of SLA time elapsed' },
{ percentage: 75 }
)

const slat75 = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_sla_75'] },
{
table: 'task_sla',
conditions: `sys_id=${wfa.dataPill(params.trigger.task_sla_record, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

const task75 = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_task_75'] },
{
table: 'task',
conditions: `sys_id=${wfa.dataPill(slat75.Record.task, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.flowLogic.if(
{
$id: Now.ID['check_not_assigned_75'],
condition: `${wfa.dataPill(task75.Record.assigned_to, 'reference')}=NULL`,
annotation: 'Task is unassigned at 75%',
},
() => {
wfa.action(
action.core.updateRecord,
{ $id: Now.ID['worknote_unassigned_75'] },
{
table_name: 'task',
record: wfa.dataPill(task75.Record.sys_id, 'reference'),
values: TemplateValue({ work_notes: 'Warning: task is unassigned at 75% of SLA time.' }),
}
)
}
)

wfa.flowLogic.else({ $id: Now.ID['handle_assigned_75'] }, () => {
wfa.action(
action.core.updateRecord,
{ $id: Now.ID['worknote_assigned_75'] },
{
table_name: 'task',
record: wfa.dataPill(task75.Record.sys_id, 'reference'),
values: TemplateValue({ work_notes: 'SLA at 75% — manager notified.' }),
}
)

wfa.action(
action.core.sendNotification,
{ $id: Now.ID['notify_manager_75'] },
{
table_name: 'task',
record: wfa.dataPill(task75.Record.sys_id, 'reference'),
notification: 'sla_escalation_level_1_notification',
}
)
})

// ── 90% milestone ────────────────────────────────────────────────────────
wfa.action(
action.core.slaPercentageTimer,
{ $id: Now.ID['wait_90_percent'], annotation: 'Pause until 90% of SLA time elapsed' },
{ percentage: 90 }
)

const slat90 = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_sla_90'] },
{
table: 'task_sla',
conditions: `sys_id=${wfa.dataPill(params.trigger.task_sla_record, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

const task90 = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_task_90'] },
{
table: 'task',
conditions: `sys_id=${wfa.dataPill(slat90.Record.task, 'reference')}`,
sort_type: 'sort_asc',
if_multiple_records_are_found_action: 'use_first_record',
}
)

wfa.flowLogic.if(
{
$id: Now.ID['check_resolved_90'],
condition: `${wfa.dataPill(task90.Record.state, 'string')}=6`,
annotation: 'Task already resolved at 90%',
},
() => {
wfa.action(
action.core.updateRecord,
{ $id: Now.ID['worknote_resolved_90'] },
{
table_name: 'task',
record: wfa.dataPill(task90.Record.sys_id, 'reference'),
values: TemplateValue({
work_notes: 'Task resolved before 90% SLA milestone — no escalation needed.',
}),
}
)
}
)

wfa.flowLogic.else({ $id: Now.ID['handle_unresolved_90'] }, () => {
wfa.action(
action.core.sendNotification,
{ $id: Now.ID['urgent_escalation_90'] },
{
table_name: 'task',
record: wfa.dataPill(task90.Record.sys_id, 'reference'),
notification: 'sla_escalation_urgent_notification',
}
)

wfa.action(
action.core.waitForCondition,
{ $id: Now.ID['wait_for_resolution'] },
{
table_name: 'task',
record: wfa.dataPill(task90.Record.sys_id, 'reference'),
conditions: 'state=6',
timeout_duration: Duration({ days: 7 }),
}
)

wfa.action(
action.core.sendNotification,
{ $id: Now.ID['confirm_resolution'] },
{
table_name: 'task',
record: wfa.dataPill(task90.Record.sys_id, 'reference'),
notification: 'sla_resolution_confirmation_notification',
}
)
})
}
)