Skip to main content

Scripting Reference

This document provides a comprehensive reference for writing scripts in workflow rules. Scripts allow you to implement advanced automation logic using JavaScript.


Overview​

The Run Script action in workflow rules executes JavaScript code to automate complex ticket handling scenarios. Scripts run in a sandboxed environment with access to ticket data, message context, and helper functions.

Key features:

  • Read and modify ticket properties
  • Access customer and owner information
  • Work with custom fields
  • Use conditional logic and loops
  • 10-second execution timeout for safety

Ticket Object​

The ticket object is the primary context for your scripts. It provides both read and write access to ticket data.

Read-Only Properties​

// Basic ticket information
ticket.id // UUID string
ticket.subject // Ticket subject line

// Current status (object)
ticket.status.id // Status UUID
ticket.status.code // Status code (e.g., "open", "closed")
ticket.status.name // Status display name

// Current priority (object)
ticket.priority.id // Priority UUID
ticket.priority.name // Priority display name

// Current department (object)
ticket.department.id // Department UUID
ticket.department.name // Department display name

// Assigned owner (object, may be undefined)
ticket.owner.id // User UUID
ticket.owner.email // User email
ticket.owner.firstname // User first name
ticket.owner.lastname // User last name

// Customer information (object)
ticket.customer.id // Customer UUID
ticket.customer.email // Customer email
ticket.customer.firstname // Customer first name
ticket.customer.lastname // Customer last name
ticket.customer.name // Customer full name

// Folder and tags
ticket.folder // Current folder: "INBOX", "ASSIGNED", "SPAM", "ARCHIVE"
ticket.tags // Array of tag strings

Writable Properties​

You can modify these properties by direct assignment:

// Set status by code or ID
ticket.status = "closed";
ticket.status = "550e8400-e29b-41d4-a716-446655440000";

// Set priority by name or ID
ticket.priority = "High";
ticket.priority = "550e8400-e29b-41d4-a716-446655440001";

// Set department by name or ID
ticket.department = "Sales";
ticket.department = "550e8400-e29b-41d4-a716-446655440002";

// Set owner by email or ID
ticket.owner = "[email protected]";
ticket.owner = "550e8400-e29b-41d4-a716-446655440003";

// Set folder
ticket.folder = "ASSIGNED";
ticket.folder = "SPAM";
ticket.folder = "ARCHIVE";
ticket.folder = "INBOX";

// Set tags (replaces all existing tags)
ticket.tags = ["urgent", "vip"];

Custom Fields​

Custom fields can be read and written using their code (not the display name).

Reading Custom Fields​

// Access custom field value directly
var orderId = ticket.order_id; // Text field
var amount = ticket.order_amount; // Number field
var isVip = ticket.is_vip; // Boolean field
var region = ticket.region; // Select field

Writing Custom Fields​

// Set text custom field
ticket.order_id = "ORD-12345";

// Set number custom field
ticket.order_amount = 199.99;

// Set boolean custom field
ticket.is_vip = true;

// Set select custom field
ticket.category = "billing";

// Set date custom field (ISO 8601 format)
ticket.due_date = "2024-12-31T23:59:59Z";
ticket.due_date = "2024-12-31";

Message Object​

The message object is available when the rule is triggered by a message event (New Customer Reply, New Staff Reply, etc.).

if (message) {
message.id // Message UUID
message.body_text // Message content (plain text)
message.body_html // Message content (HTML)
message.createdAt // ISO 8601 timestamp
}

Example:

if (message && message.body_text) {
var bodyLower = message.body_text.toLowerCase();

if (bodyLower.includes("cancel subscription")) {
ticket.department = "Retention";
ticket.priority = "High";
}
}

Helper Functions​

getStatuses()​

Returns an array of all available statuses.

var statuses = getStatuses();
// Returns: [{ id: "...", code: "open", name: "Open" }, ...]

// Find a specific status
for (var i = 0; i < statuses.length; i++) {
if (statuses[i].code === "pending") {
ticket.status = statuses[i].id;
break;
}
}

getPriorities()​

Returns an array of all available priorities.

var priorities = getPriorities();
// Returns: [{ id: "...", name: "Low" }, { id: "...", name: "High" }, ...]

getDepartments()​

Returns an array of all available departments.

var departments = getDepartments();
// Returns: [{ id: "...", name: "Support" }, { id: "...", name: "Sales" }, ...]

getUsers()​

Returns an array of all available users (agents).

var users = getUsers();
// Returns: [{ id: "...", email: "[email protected]", firstname: "John", lastname: "Doe" }, ...]

fetch()​

Makes HTTP requests to external APIs. Synchronous - returns result directly.

var response = fetch(url, options);
// response: { ok, status, statusText, text, json }

Options: method (GET/POST/PUT/DELETE), headers (object), body (string or object)

Example: Fetch from CRM and update custom fields

var response = fetch("https://api.example.com/customers/" + ticket.customer.email, {
headers: { "Authorization": "Bearer YOUR_API_KEY" }
});

if (response.ok && response.json) {
ticket.customer_tier = response.json.tier;
ticket.lifetime_value = response.json.lifetime_value;

if (response.json.tier === "enterprise") {
ticket.priority = "High";
}
}

Example: POST to webhook

var response = fetch("https://hooks.example.com/helpdesk", {
method: "POST",
body: { ticket_id: ticket.id, customer_email: ticket.customer.email }
});

Notes: HTTPS only, 5s timeout, 1MB response limit, internal networks blocked.


Common Patterns​

Conditional Assignment​

// Set priority based on subject
if (ticket.subject.toLowerCase().includes("urgent")) {
ticket.priority = "High";
} else if (ticket.subject.toLowerCase().includes("question")) {
ticket.priority = "Low";
}

Department Routing​

var subject = ticket.subject.toLowerCase();

if (subject.includes("billing") || subject.includes("payment") || subject.includes("invoice")) {
ticket.department = "Billing";
} else if (subject.includes("technical") || subject.includes("bug") || subject.includes("error")) {
ticket.department = "Technical Support";
} else if (subject.includes("sales") || subject.includes("pricing") || subject.includes("quote")) {
ticket.department = "Sales";
}

Customer Domain-Based Logic​

if (ticket.customer && ticket.customer.email) {
var email = ticket.customer.email;
var domain = email.split("@")[1];

// Enterprise customer handling
if (domain === "bigcorp.com" || domain === "enterprise.org") {
ticket.priority = "High";
ticket.department = "Enterprise Support";
ticket.is_enterprise = true;
}

// Educational institution
if (domain.endsWith(".edu")) {
ticket.segment = "education";
}
}

Tag Management​

// Add tags without losing existing ones
var existingTags = ticket.tags || [];
existingTags.push("processed");
existingTags.push("automated");
ticket.tags = existingTags;

Working with Messages​

if (message && message.body_text) {
var body = message.body_text.toLowerCase();

// Detect frustration keywords
var frustrationKeywords = ["frustrated", "angry", "terrible", "worst", "unacceptable"];
for (var i = 0; i < frustrationKeywords.length; i++) {
if (body.includes(frustrationKeywords[i])) {
ticket.priority = "High";
ticket.needs_attention = true;
break;
}
}
}

Round-Robin Assignment​

var users = getUsers();
if (users.length > 0) {
// Simple round-robin based on ticket ID hash
var ticketHash = 0;
for (var i = 0; i < ticket.id.length; i++) {
ticketHash += ticket.id.charCodeAt(i);
}
var assigneeIndex = ticketHash % users.length;
ticket.owner = users[assigneeIndex].email;
}

Error Handling​

Scripts are executed in a safe environment:

  • Syntax errors are caught and logged; the script is skipped.
  • Invalid field values (e.g., non-existent status name) are ignored.
  • Timeouts (10 seconds) prevent infinite loops.
  • Errors don't cascade to other rules or system components.

Best practices:

// Check for null/undefined before accessing properties
if (ticket.customer && ticket.customer.email) {
// Safe to access ticket.customer.email
}

if (message) {
// Safe to access message properties
}

// Use try-catch for complex logic
try {
var data = JSON.parse(ticket.custom_json);
ticket.parsed_field = data.value;
} catch (e) {
// Handle error gracefully
}

Limitations​

  • Execution timeout: Scripts are terminated after 10 seconds.
  • No file system access: File operations are not available.
  • No persistent state: Variables don't persist between script executions.
  • Read-only fields: ticket.id, ticket.subject, ticket.customer cannot be modified.
  • ES5 JavaScript: Modern JavaScript features (arrow functions, const/let, etc.) may not be available.