Design custom steps

You can create your own steps with whatever inputs, outputs, and internal logic you need. This gives you the power to integrate even more systems into your toolchain, perform actions that aren't baked in (yet), or tailor a step to exactly your needs.

For example, you might create a custom step to:

  • Integrate your proprietary, internal logging software into your incident resolution workflow.
  • Transform the timestamp coming from a monitoring tool into the format your service desk system expects.
  • Check for a substring in the payload and populate outputs based on the value of that string.

As we go through the steps below, we'll design a step to create a ticket in another system (Zendesk in our example but you could replace that with whatever tool you're familiar with). Along the way, we'll look at what the basic framework needs to be, what inputs we need to bring information in, what outputs we want to create to pass information to steps downstream, and what transformation needs to happen to the information inside the step.

Once you create the step, you can reuse it in any flows for any forms in the communication plan it belongs to.

Creating a custom step is pretty straightforward — define inputs, map to outputs, transform the data — but it can be as simple or as complex as you need. Editing or deleting a custom step is a little different because the changes might impact flows where the step is already used.

We recommend being discrete when creating a custom step — don't try to do everything in one step. Focusing the step on a specific task makes it easier to create, update, and troubleshoot. It'll also be more reusable in multiple flows.

Step 1: Create the custom step

When you create a new custom step, the first thing to do is set up how it appears in the palette: the name, description, and icon.

Step 2: Define the endpoint options

If your step needs an endpoint — for example, you want it to request information from or post information to another system — you can define a label and authentication.

The endpoint label lets you reference the endpoint in the transformation script rather than hard-coding it. It doesn't need to match the endpoint name used when the step is added to the flow. For example, if you set the label to "TrackingSystem", someone adding the step to a flow could select an endpoint named "Jira Cloud", and the script would perform the TrackingSystem requests in the script on the Jira Cloud endpoint.

Step 4: Determine the inputs

When you define the inputs, you're setting up the fields people populate when adding the step to their flow. You only need to create inputs that bring in the information this step needs to run its script and populate its outputs with new information (you don't need inputs that simply pass the information through the step from previous steps; once a step is in a flow, its outputs are available to all the steps further downstream).

Consider what your step needs for it to successfully execute the script and populate its outputs. Here's some questions you might think about:

  • What information do you need from another system? Do you want to look up user information to populate an assignee output? Then you might need an input that lets people include a user ID or username to use in the lookup.
  • What do you want to send to another system? Do you want to post event information to an internal dashboard? You'd want inputs that can be populated with the information used to create the request body.
  • What outputs from this step do you want available to steps further downstream? Do you need to make sure there's a timestamp output that uses decimal time? You'd want an input that captures incoming timestamps so you can convert them using the script.

Also consider which inputs are optional and which are required — is that timestamp necessary while the user information for the lookup is nice to have?

Step 3: Determine the outputs

When you define the outputs, you're deciding what information this step should provide to steps further downstream. Some examples to consider:

  • Is this step posting to a status website? Do you want to provide the name of the page so it can be sent to a chat channel or added to the ticket details using another step? You might want a Page Name output that you can populate from the response.
  • Is this step posting to a chat app? Do you want to provide the message in an output so it can be added as a comment in your service desk source of truth? Then you might want a Message output.
  • Is this step converting the time formats of the world into the one used by your dashboard? You probably need a Dashboard Timestamp output.

Step 4: Design the logic

The script is the heart of your custom step. It's where you design the internal logic that uses the inputs to request information from another application, structures the information into a payload to send to an application, transforms all that information, and maps it to the outputs.

For example, you might concatenate multiple inputs into a single output, transform information from an input into a format another system will accept (for example, all uppercase or a unique time format), or compile input values into a payload to post to another system and print a message to an output based on whether the post was successful.

The Script tab includes an example script to get you started. It shows you inputs, outputs, and endpoints available to use in the script. You can also use any constants you've defined or shared libraries. The editor opens within the confines of the custom step dialog; click Full Screen to expand it (this changes to Reduce so you can shrink it when you're done). Once you're done creating your script, click Save to save your custom step.

The basics

When working in the script editor, there are some handy bits of JavaScript that you use to reference resources outside your script and to post to the log as the script is processed. Before you get started, you should be aware that xMatters supports ECMAScript 5.1.

Example: A step to create a ticket in Zendesk

This example script walks through creating a basic "Create a ticket" step, wrapping up the example we followed in the steps above. It constructs a payload from the step inputs, sends it to Zendesk, and populates the outputs based on the response from Zendesk.

console.log("Begin Step: Zendesk Create Ticket");
Writes a message to the log in the Activity panel that the step started processing.
var apiRequest = http.request({ 
    'endpoint': 'Zendesk End', 
    'path': '/api/v2/tickets.json', 
    'method': 'POST' 
Prepares the POST request to another application (in this case, Zendesk). Remember to use the name you gave the endpoint in the Settings tab, which is also displayed on the right of the script editor.
var zdPayload = {  
   "ticket": {} 

Sets up the payload that will be sent to Zendesk (in this example, the information to create a ticket).
if (input.Summary !== "") { 
    console.log("Subject = " + input["Summary"]); 
    zdPayload.ticket.subject = input["Summary"]; 

Checks if the "Summary" input contains text. If it does, it posts that text to the log and sets it as the "Subject" of the Zendesk ticket that will be created.

In this example, because "Summary" is one word, it can be referenced using either input.Summary or input["Summary"]. If it were more than one word, you'd have to use bracket notation (input["Summary line"]).

if (typeof input["Urgency"] !== 'undefined') { 
    zdPayload.ticket.priority = input["Urgency"]; 

Checks that the "Urgency" input is not undefined, then sets that as the "Priority" in the Zendesk ticket.
zdPayload.ticket.comment = { "body": input["Ticket Body"] }; 

Sets the contents of the "Ticket Body" input as the body of the Zendesk ticket. When someone adds this step to their flow, they could populate the field with multiple outputs, for example a Jira Issue ID, a ServiceNow Incident Number, a Statuspage Incident Name, and a Details output from the originating event.
console.log("Ticket = " + JSON.stringify( zdPayload, null, 3 ) ); 

Prints the entire contents of the ticket payload to the log. It uses JSON.stringify to convert it to JSON; otherwise, it appears in the log as "[object Object]"
var apiResponse = apiRequest.write( zdPayload ); 
if (apiResponse.statusCode == 201) { 
    var response = JSON.parse( apiResponse.body ); 
    output["ID"] =; 
    output["Ticket Created"] = "true"; 
    console.log("Ticket Created: " +; 
else { 
    output["Ticket Created"] = "false"; 
    console.log("Ticket Creation Failed"); 

Sends the final payload to Zendesk.

If a 201 response is returned, the "ID" output is populated with the Zendesk ticket ID, the "Ticket Created" output is populated with true, and "Ticket Created: <Zendesk ID>" is written to the log.

If another response is returned, the "Ticket Created" output is populated with false and "Ticket Creation Failed" is written to the log.

console.log("End Step: Zendesk Create Ticket");
Wraps up the step processing by writing a message to the log.

Step 5: Test your custom step

After you're happy with your custom step configuration, we recommend you test it by adding it to a flow and kicking off whatever action triggers the flow. If you encounter runtime issues, check the Activity panel for clues about what the problem might be.