Event Handlers
Event Handlers are event-driven scripts that execute automatically when something happens in Jira. When an issue is created, a comment is added, a sprint starts, or any of 37+ events occur - your event handler script runs in response.
How Event Handlers Work
[User Action in Jira] → [Jira Event Fired] → [ScriptForge Matches Event Handlers]
→ [Condition Evaluated] → [Script Executes]
- A user (or system) performs an action in Jira that triggers an event
- ScriptForge's event trigger handler receives the event
- It finds all enabled event handlers subscribed to that event
- For each matching event handler, it evaluates the condition expression (if configured)
- If the condition passes (or there is no condition), the script executes
- Output and results are logged to the activity log
Available Events (37+)
Issue Events
avi:jira:created:issue- Issue createdavi:jira:updated:issue- Issue updated (any field change)avi:jira:deleted:issue- Issue deleted
Comment Events
avi:jira:created:comment- Comment addedavi:jira:updated:comment- Comment editedavi:jira:deleted:comment- Comment deleted
Attachment Events
avi:jira:created:attachment- File attachedavi:jira:deleted:attachment- Attachment removed
Sprint Events
avi:jira:created:sprint- Sprint createdavi:jira:updated:sprint- Sprint updated (started, completed, etc.)avi:jira:deleted:sprint- Sprint deleted
Issue Link Events
avi:jira:created:issuelink- Link added between issuesavi:jira:deleted:issuelink- Link removed
Version Events
avi:jira:created:version- Version createdavi:jira:updated:version- Version updated (released, etc.)avi:jira:deleted:version- Version deleted
Worklog Events
avi:jira:created:worklog- Work loggedavi:jira:updated:worklog- Worklog editedavi:jira:deleted:worklog- Worklog removed
Project Events
avi:jira:created:project- Project createdavi:jira:updated:project- Project updatedavi:jira:deleted:project- Project deleted (soft-delete)
User Events
avi:jira:created:user- User added to siteavi:jira:updated:user- User profile updated
Filter Events
avi:jira:created:filter- Saved filter createdavi:jira:updated:filter- Saved filter updatedavi:jira:deleted:filter- Saved filter deleted
Issue Type Events
avi:jira:created:issuetype- Issue type createdavi:jira:updated:issuetype- Issue type updatedavi:jira:deleted:issuetype- Issue type deleted
Event Handler Configuration
Each event handler has:
| Field | Description |
|---|---|
| Name | A descriptive name for the event handler |
| Description | Optional - what the event handler does |
| Events | One or more events that trigger this event handler |
| Projects | Which projects to listen in (empty = all projects) |
| Condition Expression | Optional JavaScript expression that must return true for the script to run |
| Script | The JavaScript code to execute |
| Run As | app (service account - full access) or user (triggering user's permissions) |
| Enabled | Toggle on/off without deleting |
Script Context
When an event handler fires, your script receives the event data through the context:
// The event payload is available - contains the issue/entity that triggered the event
const issue = await WorkItems.getByKey(event.issue.key);
console.log(`Issue ${issue.key} triggered event`);
// For issue events, you get the issue data directly
// For comment events, you get the comment and parent issue
// For sprint events, you get the sprint details
Condition Expressions
Conditions are JavaScript expressions that gate whether the script runs. They have access to the same event data:
// Only run if issue is a Bug
event.issue.fields.issuetype.name === 'Bug'
// Only run if priority is High or Critical
['High', 'Critical'].includes(event.issue.fields.priority.name)
// Only run if issue is in a specific status
event.issue.fields.status.name === 'To Do'
If a condition returns false or throws an error, the script does not execute.
Loop Detection
ScriptForge includes a loop detector to prevent infinite recursion. If an event handler updates an issue, which fires another event, which triggers the same (or another) event handler - the system detects the loop and stops execution after a configured depth to prevent runaway automation chains.
Real-World Examples
Auto-assign issues to a team lead when priority is Critical:
const issue = await WorkItems.getByKey(event.issue.key);
if (issue.priority === 'Critical') {
await issue.update(b => {
b.setAssignee('5a_team_lead_account_id');
});
await issue.addComment('Auto-assigned to team lead due to Critical priority.');
}
Add a comment when an issue is linked:
const issue = await WorkItems.getByKey(event.issueLink.sourceIssueId);
await issue.addComment(
`Linked to ${event.issueLink.destinationIssueId} via "${event.issueLink.type.name}"`
);
Auto-create a sub-task checklist when a Story is created:
const issue = await WorkItems.getByKey(event.issue.key);
const tasks = ['Write tests', 'Code review', 'Update documentation'];
for (const task of tasks) {
await issue.createSubTask('Sub-task', b => {
b.setSummary(task);
});
}