Learn how to send custom HTTP requests and Webhooks to any 3rd party software.
Introduction
Custom actions are an advanced workflow feature that allow you to interact with any third-party software that has an API. Here are some examples of what can be achieved:
- Integrating with Zapier / Workato / Make by sending a webhook
- Sending a message to Microsoft Teams or Google Chat
- Creating a Jira or ServiceNow ticket
- Sending a highly customized message to Slack
- Interacting with software built in-house
- Sending a webhook from Torii
Prerequisites
- The third-party software has a public REST/GraphQL API.
- The third-party API provides the action you want via a standard HTTP request.
How to Use?
Start by creating a workflow in Torii from the Workflows page and add a trigger that will control when the workflow should run.
Step 1 — Add a custom action to a workflow
Now, add the "Custom action (HTTP Request)" by picking it from the list:

Step 2 — Add description (optional)
We recommend adding a short description that briefly describes what the custom action is supposed to do.

Step 3 — Choose HTTP method
Pick the method of the HTTP request:

Step 4 — Choose URL
Choose the URL to send the request to. In this example, we are using a Zapier webhook:

Step 5 — Add Query Parameters (optional)
You can now add Query Parameters to the request by providing key and value pairs.

You can use @ to customize the value field.
Step 6 — Add headers (optional)
If your request requires additional headers, for authentication, for example, you can add them as key-value pairs:

You can use @ to customize the value field.
By default, the body is sent with Content-Type of "application/json". If you wish to use a different content type:
1. Adjust the Content-Type header with either application/x-www-form-urlencoded or multipart/form-data
2. Keep the "body" (step 7 below) as JSON and it will be sent based on the selected content type
Step 7 — Add body (optional)
You can add a body with a valid JSON payload. In this example, we are sending a JSON payload and using the @ to add customization:

{ "query": "{ allFilms { edges { node { id } } } }" }
For "application/x-www-form-urlencoded" or "multipart/form-data" requests, keep using JSON to define the form fields and they will be sent based on the selected content type.
Step 8 — Add response mapping (optional)
Using the response mapping you can chain custom action's output and use it as another action's input — map the HTTP response and use it as a placeholder in subsequent actions. For each mapped field, you can also set a field type (Text, Number, or Boolean) so Torii correctly interprets the value. Mapping is only relevant when the response is a valid JSON; it is not allowed to use the characters {} as the mapping key.
Example
The mapping key (left-side) is the name that will be used to refer to this mapping. The mapping value (right-side) is where to read the value from. For this Response Body:
{
"app": {
"id": 1,
"name": "Torii",
"users": ["Alice", "Bob"]
}
}
Setting the field type
For each mapped field, you must also set a field type (Text, Number, or Boolean) so Torii correctly interprets the value.
Setting the correct type is important if you plan to use the mapped field in an IF/ELSE branch later in the workflow. The type determines which operators are available in the condition:
Advanced mapping using JMESPath syntax
JMESPath is a query language for working with JSON data. It is helpful when you need to extract values from arrays or nested objects. With it, you can pick specific fields from API responses, work with lists, join text, and more. To learn more about JMESPath, head over to our Advanced data transformations using JSON path queries (JMESPath) article, which walks you step by step from the basics of JMESPath to advanced concepts.
Here are some examples of JMESPath usage:
For the following response object:
{
"apps": [
{
"id": 1,
"name": "Torii",
"users": ["Alice", "Bob"]
},
{
"id": 2,
"name": "AWS",
"users": ["Bob", "Claire"]
}
]
}
Using the following mapping syntax will produce:
# EXAMPLE 1: Get all names to a string
join(',', apps[].name) ---> "Torii,AWS"
# EXAMPLE 2: Get all names to a string, alternative syntax
apps[].name | join(',', @) ---> "Torii,AWS"
# EXAMPLE 3: Get all ids to a string
# This will:
# 1. pick all ids from the apps[] array
# 2. convert each item from a number to a string (map + &to_string)
# 3. join the array to a string using comma delimeter
join(',', map(&to_string(@), apps[].id)) ---> "1,2"
# EXAMPLE 4: Filter list and get names from nested array
# This will:
# 1. filter the apps array and only keep the AWS entry
# 2. pick the users and flat them out ([])
# 3. join the array to a string using " and " delimeter
apps[?name == 'AWS'].users[] | join(' and ', @) ---> "Bob and Claire"
Testing the Custom Action
You can test the custom action by clicking the Run now button of the workflow.
