Description
n8n-nodes-ivanti-neurons-for-itsm


A comprehensive n8n community node package for automating Ivanti Neurons for ITSM from your n8n workflows.
Ivanti Neurons for ITSM is an enterprise IT service management platform for managing incidents, changes, service requests, problems, and other ITSM processes. This package provides deep integration with the Ivanti REST/OData API, enabling sophisticated automation workflows for IT operations.
—
Table of Contents
- Features
- Installation
- Quick Start
- Nodes Overview
- Credentials Setup
- Resources & Operations
- Usage Examples
- Advanced Topics
- Troubleshooting
- Best Practices
- API Reference
- FAQ
- Support & Contributing
- License
- Full OData Support: Complete CRUD operations on any Ivanti business object
- Smart Polling: Trigger node with filtering; from trigger version 1.2 it emits only new or changed records
- Webhook Integration: Seamless integration with Ivanti automation runbooks
- Attachment Management: Upload, download, and delete file attachments
- Relationship Traversal: Navigate complex object relationships
- Service Catalog: Create and manage service requests programmatically
- Advanced Search: Full-text search, keyword search, and saved searches
- Quick Actions: Trigger Ivanti quick actions from workflows
- On-Premises Support: Works with both cloud and on-premises instances
- Comprehensive Error Handling: Detailed error messages and validation
—
Features
—
Installation
Option 1: Community Node Installation (Recommended)
1. In n8n, navigate to Settings → Community Nodes
2. Click Install a community node
3. Enter @synergyconsulting/n8n-nodes-ivanti-neurons-for-itsm in the search field
4. Click Install
Option 2: Manual Installation
For self-hosted n8n instances, install the package into the nodes folder of the n8n user folder
(in Docker, first open a shell with docker exec -it n8n sh):
mkdir -p ~/.n8n/nodes
cd ~/.n8n/nodes
npm install @synergyconsulting/n8n-nodes-ivanti-neurons-for-itsm
Then restart n8n.
Option 3: Docker Installation
From n8n 2.21.0, n8n can install community packages from environment variables at startup.
Add to your Docker Compose file:
services:
n8n:
image: n8nio/n8n:latest
environment:
- N8NCOMMUNITYPACKAGESMANAGEDBY_ENV=true
- 'N8NCOMMUNITYPACKAGES=[{"name":"@synergyconsulting/n8n-nodes-ivanti-neurons-for-itsm"}]'
# ... other configuration
With N8NCOMMUNITYPACKAGESMANAGEDBY_ENV=true, n8n makes the installed packages match the
list on every start: it uninstalls any community package that is not in the list, and the
Community Nodes settings page becomes read-only. List every community package you use. See
n8n: install community nodes with environment variables.
Queue Mode
In queue mode, workflows run on the worker processes, so **every worker and webhook processor needs
the package**, not only the main instance. A worker without it fails every run of a workflow that
uses these nodes with Unrecognized node type, including the error workflow. Install the package
on each process with Option 2, or set the two environment variables of Option 3 on every main,
worker and webhook process, so a recreated container installs it again.
—
Quick Start
1. Set Up Credentials
Before using any nodes, configure your Ivanti credentials:
1. In n8n, go to Credentials → New
2. Search for “Ivanti Neurons for ITSM API”
3. Fill in:
– Tenant: Your Ivanti hostname (e.g., mytenant.ivanticloud.com)
– API Key: Your Ivanti REST API key
– Is On Prem: Check if using on-premises instance
4. Click Test & Save
2. Create Your First Workflow
┌─────────────────┐ ┌──────────────────────┐ ┌──────────────┐
│ Slack Trigger │────▶│ Ivanti Neurons │────▶│ Slack Reply │
│ /incident cmd │ │ Create Incident │ │ with IncNum │
└─────────────────┘ └──────────────────────┘ └──────────────┘
This workflow allows users to create Ivanti incidents directly from Slack using a slash command, bridging your collaboration tool with your ITSM platform.
—
Nodes Overview
This package includes four nodes for comprehensive Ivanti integration:
1. Ivanti Neurons for ITSM (Action Node)
Purpose: Perform CRUD operations and interact with the Ivanti API
Icon: Ivanti Neurons logo
Use Cases:
2. Ivanti Neurons for ITSM Polling Trigger
Purpose: Start workflows based on new or changed Ivanti records
Icon: Ivanti Neurons logo with trigger indicator
Use Cases:
How It Works:
1. Polls the Ivanti OData API at configurable intervals
2. Version 1.2 and later: emits only records created or modified since the previous poll
– The trigger remembers the LastModDateTime and RecId of the last record it emitted (in the workflow static data) and reads on from there, in order of LastModDateTime, then RecId. Your filter is kept; any Order By is replaced by this order.
– The first poll after the workflow is activated only records the starting point (the most recently modified matching record) and emits nothing.
– With a Limit, records beyond the limit are emitted on the next polls, so none are skipped.
– A changed record is emitted again each time it is modified.
– Testing the node in the editor shows the most recently modified records and does not move the starting point.
3. Versions 1 and 1.1: emit every matching record on every poll. Nothing is remembered between polls, so narrow the filter (for example on LastModDateTime) or remove duplicates downstream. Open the node and update it to the latest version to get the behaviour above.
3. Ivanti Neurons for ITSM Connector (Action Node)
Purpose: Report automation job results back to Ivanti
Icon: SYNERGY logo
Use Cases:
Note: Requires the Ivanti Neurons Connector package installed on your Ivanti instance. Contact SYNERGY for details.
4. Ivanti Neurons for ITSM Connector Trigger
Purpose: Receive webhook calls from Ivanti automation runbooks
Icon: SYNERGY logo with trigger indicator
Use Cases:
Security Features:
—
Credentials Setup
Ivanti Neurons for ITSM API
This credential is used by the main action nodes and polling trigger.
| Field | Type | Description | Example |
|——-|——|————-|———|
| Tenant | string | Your Ivanti hostname (without protocol) | mytenant.ivanticloud.com |
| API Key | password | Your Ivanti REST API key | abc123...xyz789 |
| Is On Prem | boolean | Enable for on-premises instances | false (cloud) / true (on-prem) |
| Skip SSL Verification | boolean | Disable SSL cert validation | false (recommended) |
#### Obtaining an API Key
For Cloud Instances:
1. Log into Ivanti Neurons for ITSM
2. Navigate to Configure → Security → API Keys
3. Click Create API Key
4. Assign appropriate permissions (typically “REST API User” role)
5. Copy the generated key
For On-Premises Instances:
1. Log into HEAT with admin credentials
2. Navigate to Configuration → Security → REST API
3. Create a new API key or use an existing one
4. Enable the /HEAT path prefix in credentials
#### Credential Testing
When you save the credential, n8n automatically tests it by making a GET request to:
https://{tenant}/api/odata/businessobject/Incidents?$top=1
If the test fails, check:
—
Ivanti Neurons for ITSM Connector Auth
This credential is used by the webhook trigger to validate inbound requests.
| Field | Type | Description |
|——-|——|————-|
| Type | dropdown | Authentication method: Base, Header, or API Key |
| Username | string | Used for Basic Auth (when Type = Base) |
| Password | password | Used for Basic Auth (when Type = Base) |
| Header | string | Custom header name (when Type = Header) |
| Webhook API Key | password | Token value for Header or API Key auth |
#### Authentication Methods
Basic Authentication:
Authorization: Basic base64(username:password)
Used when Ivanti automation sends standard HTTP Basic Auth.
Custom Header:
X-Custom-Auth: your-secret-token
Used when you define a custom authentication header.
API Key:
Authorization: your-api-key
Simple bearer-style authentication.
—
Resources & Operations
Options (all resources except Automation)
Every operation except those in the Automation resource has an Options section at the bottom of the node.
| Option | Type | Description |
|——–|——|————-|
| Override Headers | collection | HTTP headers (name and value) sent with every request the operation makes. A header set here replaces the default header of the same name. |
If you add an Authorization header, it is sent as-is and the API key from the credential is not used. The credential still supplies the tenant URL and the SSL setting. Use this when a request has to run with a different key or token than the one stored in the credential.
Example:
Name: Accept-Language
Value: de-DE
Business Object
Interact with any Ivanti OData business object. Common objects include:
IncidentsChangesServiceReqsProblemsEmployeesTeamsConfigurationItems> Important: Business object names must be plural and end with s.
#### Operations
##### Get Many
Retrieve multiple records with powerful filtering and pagination.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Plural entity name (e.g., Incidents) |
| Return All | boolean | If true, fetch all records across all pages |
| Limit | number | Max records to return (when Return All = false) |
| Mode | dropdown | Node version 1.1+. Manual (build the query field by field) or JSON (write the OData query yourself) |
| OData Query (JSON) | json | JSON mode. The OData options $filter, $select and $orderby, sent to Ivanti as written |
| Select All Fields | boolean | Manual mode. Return all fields or specify subset |
| Select Fields | collection | Manual mode. Array of field names to return |
| OData Filter | collection | Manual mode. Structured filters (field, operator, value) |
| Order By | string | Manual mode. Field name for sorting |
| Order Direction | dropdown | Manual mode. asc or desc |
| Define Filter as JSON | boolean | Node version 1 only. Switch from the filter builder to a JSON filter |
| Raw Filter (JSON) | json | Node version 1 only. Filter conditions as a JSON array (when Define Filter as JSON = true) |
Example OData Filter:
Field Name: Priority
Field Type: string
Operation: eq
Value: High
Logical Operator: andField Name: Status
Field Type: string
Operation: ne
Value: Closed
This generates:
$filter=Priority eq 'High' and Status ne 'Closed'
Example Raw Filter (JSON) (node version 1 only; same fields as the filter builder; fieldType defaults to string, logicalOperator to and):
[
{ "fieldName": "Status", "operation": "ne", "value": "Closed" },
{ "fieldName": "Priority", "fieldType": "number", "operation": "le", "value": 2, "logicalOperator": "or" }
]
This generates:
$filter=Status ne 'Closed' or Priority le 2
JSON mode (node version 1.1+): set Mode to JSON and write the OData query options yourself. They are sent to Ivanti exactly as written, so any OData syntax Ivanti supports can be used, including functions the filter builder does not offer (such as contains). Paging stays with Return All and Limit, so $top and $skip cannot be set here.
{
"$filter": "Status eq 'Active' and contains(Subject,'printer')",
"$select": "RecId,Subject,Status",
"$orderby": "CreatedDateTime desc"
}
This sends:
$filter=Status eq 'Active' and contains(Subject,'printer')&$select=RecId,Subject,Status&$orderby=CreatedDateTime desc
Because nothing is checked or escaped in JSON mode, quote text values yourself ('Active') and double any single quote inside them ('O''Brien').
JSON mode in node version 1.3 checks the keys and accepts more ways to write them:
$filter, $select and $orderby are accepted, with or without the $ sign and in any letter case: {"filter": "…"} and {"$Filter": "…"} both send $filter. Ivanti ignores any other key, so a typo such as "$filtr" would read every record; instead the node fails with Unknown OData option: $filtr. $search is refused too: Ivanti does not support it here, so use Business Object → Search by Keyword. The same option given twice ("filter" and "$filter") is refused.$select and $orderby may also be lists, which are sent joined with commas:{
"$filter": "Status eq 'Active'",
"$select": ["RecId", "Subject", "Status"],
"$orderby": ["LastModDateTime asc", "RecId asc"]
}
Versions 1.1 and 1.2 still pass any key as written and do not accept lists.
Values from the input: switch the field to Expression and write the values into the JSON, for example { "$filter": "Owner eq '{{ $json.owner }}'" }, or pass a whole query object built by an earlier node with {{ $json.query }}. In both cases the values are still sent as written, so quote and escape text values yourself.
Node versions: workflows created before version 1.1 keep version 1, with the “Define Filter as JSON” toggle and no Mode field. Workflows keep the version they were built with; new nodes are added as the latest version (1.3). Version 1.2 also changes the Automation › Report Transaction Status options, and version 1.3 checks the keys of the JSON mode.
The same options are available on the Ivanti Neurons for ITSM Polling Trigger.
n8n Expression Example:
// In Select Fields
{{ $json.fieldList.split(',') }}// In Order By
{{ $json.sortField || 'CreatedDateTime' }}
—
##### Get By Record ID
Fetch a single record by its unique identifier.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Plural entity name |
| Record ID | string | The GUID of the record |
| Select All Fields | boolean | Return all fields or subset |
| Select Fields | collection | Fields to return |
Example:
Business Object: Incidents
Record ID: 8A7F6E5D4C3B2A1F8A7F6E5D4C3B2A1F
n8n Expression:
// Use RecId from previous node
{{ $('Trigger').item.json.RecId }}
—
##### Create
Create a new record in the business object.
Input Modes:
Parameters (Define Below mode):
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Plural entity name |
| Mode
| Fields | collection | Array of field name/value pairs |
Example Fields:
Field Name: Subject
Field Value: New incident from n8nField Name: Priority
Field Value: High
Field Name: Category
Field Value: Hardware
Field Name: Status
Field Value: Active
Raw JSON Example:
{
"Subject": "Network connectivity issue",
"Priority": "High",
"Category": "Network",
"Status": "Active",
"Owner": "[email protected]",
"Description": "Users cannot access shared drives"
}
Common Fields:
| Field | Type | Required | Description |
|——-|——|———-|————-|
| Subject | string | Yes* | Title/subject line |
| Description | string | No | Detailed description |
| Priority | string | No | Priority level |
| Category | string | No | Categorization |
| Status | string | Yes* | Current status |
| Owner | string | No | Assigned user email |
| Team | string | No | Assigned team |
*Required fields vary by object and configuration
—
##### Update
Update an existing record.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Plural entity name |
| Record ID | string | The GUID to update |
| Input Mode | dropdown | Define Below or Raw JSON |
| Fields | collection | Fields to update |
Important: Only fields you specify are updated. Omitted fields remain unchanged.
Example:
Record ID: {{ $json.RecId }}
Fields:
- Status: Resolved
- Resolution: Applied Windows updates
- ResolvedDateTime: {{ $now.toISO() }}
—
##### Delete By Record ID
Permanently delete a record.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Plural entity name |
| Record ID | string | The GUID to delete |
Warning: This operation is irreversible. Consider updating status instead.
—
##### Search By Keyword
Search records using OData’s $search parameter.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Plural entity name |
| Search Term | string | Keyword or phrase to search |
| Return All | boolean | Fetch all results or limit |
| Limit | number | Max results |
Example:
Business Object: Incidents
Search Term: printer offline
Limit: 20
This searches across all searchable fields (Subject, Description, etc.) for the term “printer offline”.
n8n Expression:
// Search from user input
{{ $('Webhook').item.json.body.searchQuery }}
—
Attachment
Manage file attachments on business object records.
#### Upload
Upload a file to a record.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Parent object (e.g., Incidents) |
| Record ID | string | Parent record GUID |
| Binary Property | string | Name of n8n binary property |
| File Name | string | Optional: override filename |
Workflow Example:
┌───────────────┐ ┌──────────────┐ ┌────────────────┐
│ HTTP Request │───▶│ Read Binary │───▶│ Upload │
│ Download File │ │ File │ │ Attachment │
└───────────────┘ └──────────────┘ └────────────────┘
Binary Property: Usually data (the default binary property name).
Supported File Types: All file types supported by Ivanti (PDFs, images, Office docs, logs, etc.)
—
#### Read
Download an attachment from a record.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Attachment ID | string | The attachment GUID |
| Put Output File in Field | string | The binary field the file is written to. Default data |
Output: The input item’s JSON and binary fields, with the file added in the named binary field
(a field of the same name on the input is replaced). The file name comes from Ivanti’s
Content-Disposition header, including UTF-8 names such as résumé.pdf, and is unknown when
Ivanti sends none.
The file is streamed rather than read into memory first. To keep large attachments out of n8n’s
memory as well, check that n8n keeps binary data on disk or in S3 rather than in memory
(N8NDEFAULTBINARYDATAMODE).
The file is ready for:
Example:
// Attachment ID from Get Related operation
{{ $json.attachments[0].RecId }}
—
#### Delete
Remove an attachment from a record.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Attachment ID | string | The attachment GUID |
Use Case: Clean up outdated attachments, remove duplicates, etc.
—
Relationship
Navigate and manage OData relationships between business objects.
#### Get Related
Traverse a relationship and fetch related records.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Source object |
| Record ID | string | Source record GUID |
| Relationship Name | string | Navigation property name |
| Merge Results | boolean | Merge related data into source item |
| Return All | boolean | Fetch all related or limit |
| Limit | number | Max related records |
Common Relationships:
| Object | Relationship | Returns |
|——–|————–|———|
| Incidents | Attachments | All attachments |
| Incidents | OwnerTeam | The team object |
| Incidents | ChildIncidents | Related child incidents |
| Changes | RelatedIncidents | Associated incidents |
| ServiceReqs | ServiceReqTemplateDetails | Template definition |
Merge Results Example:
// With Merge Results = true
{
"RecId": "incident-guid",
"Subject": "Printer issue",
"Attachments": [
{ "RecId": "attach-1", "FileName": "screenshot.png" },
{ "RecId": "attach-2", "FileName": "error-log.txt" }
]
}
—
#### Link
Create an OData $ref association between two records.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Source object |
| Record ID | string | Source record GUID |
| Relationship Name | string | Navigation property |
| Target Record ID | string | Target record GUID |
Example Use Case:
Link an incident to a change record:
Business Object: Incidents
Record ID: incident-guid
Relationship Name: RelatedChanges
Target Record ID: change-guid
—
#### Unlink
Remove an OData $ref association.
Parameters: Same as Link operation.
Example:
// Remove attachment reference
Business Object: Incidents
Record ID: {{ $json.incidentId }}
Relationship Name: Attachments
Target Record ID: {{ $json.attachmentId }}
—
Service Request
Programmatically create and manage service requests from the service catalog.
#### Get Subscription
Retrieve available service catalog offerings for an employee.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Profile Link | string | Employee GUID or email |
Returns: Array of service request templates the employee can access.
Example:
Profile Link: [email protected]
—
#### Get Service Request Parameters
Fetch the input parameters for a service request template.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Template ID | string | Service request template GUID |
Returns: Schema defining required and optional fields.
Use Case: Dynamically build forms or validate inputs before creating service requests.
—
#### Create
Submit a new service request.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Template | resource-locator | Select from published templates (serviceReqTemplateId) |
| Employee RecId | string (required) | GUID of the employee the request is created for (e.g. 07E1BD1BF5804E67B8E76B26FA6EF9A0). Sent as serviceReqData.ProfileLink_RecID and strUserId. |
| Subscription ID | string (required) | GUID of the catalogue subscription (e.g. 07E1BD1BF5804E67B8E76B26FA6EF9A0). Sent as subscriptionId. |
| Mode | dropdown | Manual (resource mapper form) or JSON (raw parameters object) |
| Parameters | resource-mapper | Dynamic form based on template (shown when Mode = Manual) |
| JSON | json | Raw parameters object (shown when Mode = JSON) |
| Optional Parameters | fixedCollection | Local Offset, Employee Location, Symptom, Subject |
Manual mode: Automatically loads the template schema and presents a form with all required/optional parameters.
JSON mode: The Template, Employee RecId and Subscription ID are still taken
from their own fields. The JSON input supplies only the inner parameters
object that is sent as body.parameters. Keys must use the parameter RecId in
the form par-{recId} for plain values and par-{recId}-recId for
dropdown/option values (the same keys the resource mapper produces in Manual
mode). Use Get Service Request Parameters to discover the RecIds.
JSON Example (value of the JSON field):
{
"par-1A2B3C4D5E6F7A8B9C0D1E2F3A4B5C6D": "Microsoft Office 365",
"par-9F8E7D6C5B4A39281706F5E4D3C2B1A0-recId": "11223344556677889900AABBCCDDEEFF"
}
—
Search
Advanced search capabilities across the Ivanti platform.
#### Full Text Search in Single Object
Search within a specific business object type.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Object to search |
| Search Text | string | Search query |
| Return All | boolean | All results or limit |
| Limit | number | Max results |
Search Syntax:
printerprinter offline error"out of paper"printer AND (offline OR error)—
#### Full Text Search Across All Objects
Search across all business object types simultaneously.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Search Text | string | Search query |
Returns: Results grouped by object type.
Use Case: Global search, knowledge base queries, cross-object discovery.
—
#### Saved Search
Execute a pre-configured saved search.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Business Object | string | Object type of saved search |
| Search Name | string | Display name of search |
| Search ID | string | GUID of saved search |
Use Case: Leverage complex searches configured in Ivanti UI without recreating filter logic.
—
Quick Action
#### Run
Run an action on a record, optionally supplying its prompt answers.
| Parameter | Description |
|———–|————-|
| Business Object | Plural OData collection, for example Incidents |
| Record ID | Target record ID; supports expressions such as {{ $json.RecId }} |
| Quick Action | REST action name, for example Resolve_Incident; use the tenant’s API name rather than assuming a toolbar label is callable |
| Quick Action ID | ID of that action in the selected tenant |
| Prompt Parameters (JSON) | The complete prompt array, sent as written; accepts JSON text or an expression such as {{ $json.promptParams }}. Empty or [] means no prompts |
Each entry is a DataLayer.PromptData object with at least FieldName and Value,
for example:
[
{
"__type": "DataLayer.PromptData",
"ActionId": null,
"ActionObjectId": null,
"PromptObjectId": "",
"ActionObjectType": "Incident#",
"PromptObjectType": "Incident#",
"Value": "Closed",
"FieldName": "Status",
"IsNewPrompt": true
}
]
Some actions also need action metadata or hidden entries on their prompts. The
tested Resolve Incident action has two visible prompts but requires five REST
entries. The prompt guide has a complete template
for it (issue #46).
Values supplied by expressions keep their JSON types, including false, 0, and
null; literal text stays text. With no prompts the request is unchanged. A
successful empty response produces one linked {} output item. Read the record
afterward when you need to confirm the effect.
—
Automation (Connector Node Only)
#### Report Transaction
Report the outcome of an Ivanti automation workflow back to the platform.
Parameters:
| Parameter | Type | Description |
|———–|——|————-|
| Transaction ID | string | Automation transaction GUID |
| Status | dropdown | Node version 1.2+: Queued, Completed (default), Failed or Aborted, the values Ivanti uses for automation transactions. Versions 1 and 1.1: Pending (default), In Progress, Completed or Failed. Read per item, so an expression can set a different status for each item |
| Result | string | Result message or error details |
| If Already Finished | dropdown | What to do when the transaction is already Completed, Failed or Aborted (for example after a retry, or when another branch reported it first). Error (default) fails the item. Skip returns the transaction unchanged with "alreadyFinished": true and does not update it |
Automatic Features:
Example:
Transaction ID: {{ $('Trigger').item.json.TransactionId }}
Status: Completed
Result: Successfully provisioned user account
—
Usage Examples
Example 1: Auto-Assign High Priority Incidents
Monitor for new high-priority incidents and auto-assign to the on-call team.
┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Polling Trigger │────▶│ Filter (IF) │────▶│ Update Incident │
│ Poll: Incidents │ │ Priority = High │ │ Set: Team │
│ Every 5 min │ └──────────────────┘ └─────────────────┘
└──────────────────┘ │
│ (else)
▼
┌──────────────────┐
│ No Operation │
└──────────────────┘
Polling Trigger Configuration:
Business Object: Incidents
Return All: false
Limit: 50
OData Filter:
- Priority eq 'High'
- Status eq 'Active'
Order By: CreatedDateTime
Order Direction: desc
Update Incident:
Record ID: {{ $json.RecId }}
Fields:
- OwnerTeam: On-Call Engineering
- Status: In Progress
—
Example 2: Incident Enrichment with External Data
Enrich incidents with asset data from an external CMDB.
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Webhook Trigger │────▶│ HTTP Request │────▶│ Update Incident │
│ New Incident │ │ Get Asset Info │ │ Add Details │
└──────────────────┘ └──────────────────┘ └──────────────────┘
HTTP Request:
Method: GET
URL: https://cmdb.company.com/api/assets/{{ $json.ConfigItemRecId }}
Authentication: API Key
Update Incident:
Record ID: {{ $('Webhook Trigger').item.json.RecId }}
Fields (Raw JSON):
{
"AssetSerialNumber": "{{ $json.serialNumber }}",
"AssetLocation": "{{ $json.location }}",
"AssetOwner": "{{ $json.owner }}",
"WarrantyExpiration": "{{ $json.warrantyExpiry }}"
}
—
Example 3: Service Request Approval Workflow
Route service requests through Slack for approval.
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Polling Trigger │────▶│ Slack Message │────▶│ Wait for Webhook │
│ New ServiceReqs │ │ Approval Request │ │ Slack Response │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│
▼
┌──────────────────┐
│ IF Node │
│ Check Response │
└──────────────────┘
│ │
(approved) │ │ (rejected)
▼ ▼
┌──────────────┐ ┌─────────────┐
│ Update to │ │ Update to │
│ Approved │ │ Rejected │
└──────────────┘ └─────────────┘
—
Example 4: Automated Documentation Upload
Automatically attach resolution documentation to resolved incidents.
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Polling Trigger │────▶│ HTTP Request │────▶│ Upload │
│ Resolved │ │ Generate Report │ │ Attachment │
│ Incidents │ │ (PDF API) │ │ │
└──────────────────┘ └──────────────────┘ └──────────────────┘
HTTP Request (example with a PDF generation service):
Method: POST
URL: https://pdf-service.company.com/generate
Body:
{
"template": "incident-resolution",
"data": {
"incidentId": "{{ $json.IncidentNumber }}",
"subject": "{{ $json.Subject }}",
"resolution": "{{ $json.Resolution }}",
"resolvedBy": "{{ $json.ResolvedBy }}",
"resolvedDate": "{{ $json.ResolvedDateTime }}"
}
}
Attachment → Upload:
Business Object: Incidents
Record ID: {{ $('Polling Trigger').item.json.RecId }}
Binary Property: data
File Name: Resolution-{{ $json.IncidentNumber }}.pdf
—
Example 5: SLA Monitoring and Escalation
Automatically link related incidents from external monitoring systems to Ivanti incidents.
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Webhook Trigger │────▶│ Search Ivanti │────▶│ IF Node │
│ Alert from │ │ Search By │ │ Incident Exists? │
│ Monitoring Tool │ │ Keyword │ └──────────────────┘
└──────────────────┘ └──────────────────┘ │
┌────────┴────────┐
(found) │ │ (not found)
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Update │ │ Create New │
│ Incident │ │ Incident │
│ Add Note │ │ │
└──────────────┘ └──────────────┘
│ │
└────────┬────────┘
▼
┌──────────────────┐
│ Upload │
│ Attachment │
│ (Alert Details) │
└──────────────────┘
Webhook Payload (from monitoring system):
{
"alert_id": "ALT-12345",
"severity": "critical",
"hostname": "web-server-01",
"message": "High CPU usage detected",
"metric_value": "95%",
"timestamp": "2024-01-15T10:30:00Z"
}
Search Ivanti (Search By Keyword):
Business Object: Incidents
Search Term: {{ $json.hostname }}
Limit: 10
IF Node (Check if incident exists):
{{ $('Search Ivanti').item.json.Status === 'Active' }}
Create New Incident (if not found):
Business Object: Incidents
Fields (Raw JSON):
{
"Subject": "{{ $('Webhook Trigger').item.json.message }} - {{ $('Webhook Trigger').item.json.hostname }}",
"Description": "Alert received from monitoring systemnnAlert ID: {{ $json.alertid }}nSeverity: {{ $json.severity }}nMetric: {{ $json.metricvalue }}nTimestamp: {{ $json.timestamp }}",
"Priority": "{{ $json.severity === 'critical' ? 'High' : 'Medium' }}",
"Category": "Infrastructure",
"Status": "Active",
"Source": "Monitoring System"
}
Update Incident (if found – add note):
Record ID: {{ $('Search Ivanti').item.json.RecId }}
Fields:
- WorkNotes: "Additional alert received at {{ $now.toISO() }}nAlert ID: {{ $('Webhook Trigger').item.json.alertid }}nMetric: {{ $('Webhook Trigger').item.json.metricvalue }}"
—
Advanced Topics
Working with OData
Ivanti uses OData (Open Data Protocol) for its REST API. Understanding OData query syntax helps you build powerful filters and queries.
#### Select Specific Fields
$select=RecId,Subject,Priority,Status,CreatedDateTime
In n8n: Add fields in “Select Fields” collection.
#### Filter Results
$filter=Priority eq 'High' and Status ne 'Closed'
In n8n: Use “OData Filter” collection.
Operators:
eq (equals)ne (not equals)gt (greater than)ge (greater than or equal)lt (less than)le (less than or equal)and, or, not (logical)Functions:
contains(field, 'text') – substring matchstartswith(field, 'text') – prefix matchendswith(field, 'text') – suffix match#### Order Results
$orderby=CreatedDateTime desc
In n8n: Use “Order By” and “Order Direction” fields.
#### Pagination
OData uses $top and $skip for pagination:
$top=50&$skip=100
The nodes handle pagination automatically when “Return All” is enabled.
—
Error Handling
All nodes throw detailed errors for troubleshooting.
#### Common Error Patterns
Authentication Errors:
Error: Unauthorized (401)
Not Found Errors:
Error: Not Found (404)
Incidents not Incident)Validation Errors:
Error: Bad Request (400) - Field 'Priority' is required
#### Error Handling Workflow Pattern
┌──────────────────┐
│ Try │
│ Ivanti Operation │
└──────────────────┘
│
▼
┌──────────────────┐
│ Error Trigger │
│ On Error │
└──────────────────┘
│
▼
┌──────────────────┐
│ Log to Database │
│ or Monitoring │
└──────────────────┘
│
▼
┌──────────────────┐
│ Send Alert │
└──────────────────┘
Use n8n’s built-in error workflows to handle failures gracefully.
—
Performance Optimization
#### Batch Processing
Process multiple records in a single workflow execution:
// Code node to batch process
const items = $input.all();
const batchSize = 10;
const batches = [];for (let i = 0; i < items.length; i += batchSize) {
batches.push(items.slice(i, i + batchSize));
}
return batches.map(batch => ({ json: { items: batch } }));
#### Selective Field Retrieval
Only fetch fields you need to reduce payload size and improve speed:
Select All Fields: false
Select Fields:
- RecId
- Subject
- Status
- Priority
#### Polling Optimization
For polling triggers:
—
Security Best Practices
1. Credential Management
– Never hardcode API keys in workflows
– Use n8n credential system
– Rotate API keys regularly
– Use separate keys for dev/staging/production
2. Webhook Security
– Always enable authentication on webhook triggers
– Use HTTPS endpoints only
– Validate workflow ID header
– Implement rate limiting if needed
3. Access Control
– Use least-privilege API keys
– Restrict API user permissions in Ivanti
– Audit API key usage regularly
– Disable unused credentials
4. Data Protection
– Be cautious with sensitive data in workflows
– Use n8n’s workflow permissions
– Avoid logging sensitive information
– Implement data retention policies
—
Troubleshooting
Connection Issues
Problem: Credential test fails with timeout
Solutions:
curl -H "Authorization: restapikey=YOUR_KEY"
https://YOUR_TENANT/api/odata/businessobject/Incidents?$top=1
—
SSL Certificate Errors
Problem: UNABLETOVERIFYLEAFSIGNATURE or similar SSL errors
Solutions:
—
Polling Trigger Not Finding New Records
Problem: New incidents exist but trigger doesn’t fire
Solutions:
RecId field is included in select https://tenant/api/odata/businessobject/Incidents?$filter=YOUR_FILTER
—
Webhook Trigger Returns 400
Problem: Ivanti automation gets 400 Bad Request or 401 Unauthorized
Solutions:
WWW-Authenticate: Basic realm="Webhook".Message says which check failed:Content-Type: application/json header is setX-Workflow-Id matches the n8n workflow ID—
Create/Update Operations Fail
Problem: Bad Request (400) - Invalid field errors
Solutions:
—
Attachment Upload Fails
Problem: Attachment upload returns error
Solutions:
—
Performance Issues
Problem: Workflows run slowly or timeout
Solutions:
—
Best Practices
Workflow Design
1. Use Descriptive Names
– Name nodes clearly: “Get High Priority Incidents” not “Ivanti 1”
– Add notes to complex nodes
– Document workflow purpose in workflow description
2. Error Handling
– Always implement error workflows
– Log errors to external system
– Send alerts for critical failures
– Include context in error messages
3. Testing
– Test with small data sets first
– Use n8n’s test execution mode
– Validate outputs at each node
– Test error scenarios
4. Modularity
– Break complex workflows into sub-workflows
– Use Execute Workflow node for reusable logic
– Keep workflows focused on single responsibility
—
Data Management
1. Field Selection
– Only fetch fields you need
– Use $select to reduce payload
– Consider network and processing costs
2. Filtering
– Apply filters server-side (OData) not client-side
– Use indexed fields in filters when possible
– Avoid filtering large result sets in Code nodes
3. Pagination
– Use limits for large queries
– Process in batches if needed
– Monitor memory usage with large data sets
—
Maintenance
1. Monitoring
– Set up workflow execution monitoring
– Track success/failure rates
– Monitor execution times
– Alert on anomalies
2. Updates
– Keep n8n and community nodes updated
– Review changelog for breaking changes
– Test updates in non-production first
– Have rollback plan
3. Documentation
– Document custom workflows
– Maintain runbooks for common issues
– Keep credential information updated
– Document dependencies
—
API Reference
Base URLs
Cloud Instances:
https://{tenant}/api
On-Premises Instances:
https://{tenant}/HEAT/api
Endpoints Used
> All paths below are relative to the base URL above. The node automatically
> prepends /api (cloud) or /HEAT/api (on-premises) to every path, so do not
> add /api yourself.
| Endpoint | Method | Purpose |
|———-|——–|———|
| /odata/businessobject/{object} | GET | Query records (Get Many) |
| /odata/businessobject/{object} | POST | Create record |
| /odata/businessobject/{object}('{id}') | GET | Get single record |
| /odata/businessobject/{object}('{id}') | PUT | Update record |
| /odata/businessobject/{object}('{id}') | DELETE | Delete record |
| /odata/businessobject/{object}('{id}')/{relationship} | GET | Get related records |
| /odata/businessobject/{object}('{recordId}')/{relationship}('{targetId}')/$Ref | PATCH | Link records |
| /odata/businessobject/{object}('{recordId}')/{relationship}('{targetId}')/$Ref | DELETE | Unlink records |
| /odata/businessobject/{object}('{recordId}')/{quickAction} | POST | Run quick action |
| /odata/businessobject/{object}/{savedSearchName}?ActionId={guid} | GET | Run saved search |
| /rest/Attachment | POST | Upload attachment (multipart/form-data) |
| /rest/Attachment?ID={id} | GET | Download attachment |
| /rest/Attachment?ID={id} | DELETE | Delete attachment |
| /rest/search/fulltext | POST | Full-text search in a single object |
| /rest/Search | POST | Full-text search across all objects |
| /odata/businessobject/ServiceReqTemplateParams | GET | Get service request template parameters |
| /rest/Template/{employeeId}/All | GET | Get service request subscriptions/templates |
| /rest/ServiceRequest/new | POST | Create service request |
Rate Limits
Ivanti does not publish a per-minute rate limit. Ask your Ivanti administrator which limits apply
to your tenant.
The node does not throttle or retry requests. A refused request, including HTTP 429, fails the item,
or becomes an error item with Continue On Fail. To retry, use n8n’s Retry On Fail node
setting.
To keep the number of calls down:
API Limits
Request parameter lookups) read 100 records per request and fetch further pages until the Limit
is reached, or all records with Return All.
Equal, Less Than, Less Than or Equal, Is Null and Is Not Null.
items, not an error.
shows Ivanti’s message.
—
FAQ
General Questions
Q: Which Ivanti versions are supported?
A: This package supports Ivanti Neurons for ITSM (cloud and on-premises). Tested with versions 2021.3 and later. Some features may require specific Ivanti modules or licenses.
Q: Can I use this with Ivanti Service Manager (ISM)?
A: Yes, Ivanti Neurons for ITSM is the evolution of ISM. The nodes work with both branding variants.
—
Credentials & Authentication
Q: Where do I find my API key?
A: In Ivanti, navigate to Configure → Security → API Keys. You need admin or appropriate security permissions.
Q: Can I use OAuth instead of API keys?
A: Not currently supported. Ivanti REST API primarily uses API key authentication.
Q: My API key expired. What happens?
A: Workflows will fail with 401 Unauthorized errors. Generate a new key in Ivanti and update the credential in n8n.
—
Operations & Functionality
Q: Can I query custom business objects?
A: Yes! Use the plural name of your custom object (e.g., CustomObjects).
Q: How do I find available relationships?
A: Use the Ivanti OData metadata endpoint:
https://tenant/api/odata/$metadata
Or query a record and examine the navigation properties.
Q: Can I execute Ivanti workflows from n8n?
A: Not directly via API. Use Quick Actions or create automation runbooks that call n8n webhooks.
—
Polling & Triggers
Q: How often should I poll?
A: Depends on your SLA requirements. Common intervals:
Q: Does polling create duplicate executions?
A: From trigger version 1.2, no: each poll emits only records created or modified since the previous poll (a record is emitted again when it changes). Versions 1 and 1.1 emit every matching record on every poll.
Q: Can I reset polling state?
A: Version 1.2 stores its starting point in the workflow static data, under the trigger node’s name. To start again from now, delete the trigger node and add it again (or give it a new name), then save the workflow. Deactivating and reactivating the workflow does not reset it.
—
Performance
Q: Why are my queries slow?
A: Common causes:
$select)Q: Can I run queries in parallel?
A: Yes, use n8n’s Split In Batches node and parallel execution settings.
—
Troubleshooting
Q: I get “Business object must end with ‘s'” error
A: Ivanti OData uses plural entity names. Use Incidents not Incident.
Q: SSL verification fails on my on-prem instance
A: Enable “Skip SSL Verification” in credentials. For production, install proper SSL certificate.
Q: Webhook trigger returns 400 Bad Request
A: Common causes:
Content-Type: application/json headerX-Workflow-Id headerA failed authentication answers 401 Unauthorized instead, with no response body.
—
Support & Contributing
Getting Help
1. Documentation: Start with this README and n8n docs
2. Community: Ask questions in n8n community forum
3. Issues: Report bugs on GitHub Issues
4. Support: For Connector nodes, contact SYNERGY
Contributing
Contributions are welcome! To contribute:
1. Fork the repository
2. Create a feature branch: git checkout -b feature/my-feature
3. Make your changes
4. Add or update unit tests in test/
5. Run linter: npm run lint
6. Build: npm run build
7. Test: npm test
8. Submit a pull request (CI runs lint, build and the tests on it)
Reporting Bugs
When reporting bugs, include:
Feature Requests
Have an idea? Open a GitHub issue with:
—
License
Copyright (c) 2024 SYNERGY
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
—
Acknowledgments
—
Made with ❤️ for IT automation


