Journey webhooks are secure connections that enable you to send and fetch data from an external app or service when users reach a particular step in a journey. You can use journey webhooks to:
Send data to external services (Webhook tile):
- Send data to business intelligence tools like Amplitude or Looker
- Save data to Segment
- Set up a direct mail integration with Inkit or Lob
- Launch NPS surveys with Delighted
- Trigger an action on Zapier
- Automate phone calls with Twilio
- Update your users' Iterable profiles
- Save data to your own servers
Fetch real-time data into a journey (Live Data tile — beta):
- Fetch live data (beta) from external sources for real-time decisioning and personalization in journeys
NOTE
Journey webhooks always make outbound HTTP calls from Iterable to your endpoint,
using the HTTP method you configure (GET, POST, PUT, PATCH, or DELETE).
What differs is how the response is handled — and that depends on which tile type
calls the webhook:
- Webhook tiles discard the response.
-
Live Data tiles (beta) capture the response and make it available to
downstream tiles in the journey via
{{liveData.objectName.fieldName}}references.
:::
Once you've configured a journey webhook, you can use an integration tile to call it when users reach that step of a journey.
Read on to learn how to create webhooks and use them in your journeys.
IMPORTANT
Journeys were previously known as "Workflows." Iterable's API endpoints and
field names still use this legacy term (for example, workflowId). When setting
up journey webhooks, be sure to use the correct field names and endpoint URLs in
your configuration to avoid errors.
# In this article
# How journey webhooks work
Create a journey webhook, then add it to a journey using a Call Webhook tile. When a user reaches that tile, Iterable sends a request to the endpoint you configured.
The request includes the user profile fields you selected, journey trigger data, and any custom body you defined.
# Delivery characteristics
- Delivery is not guaranteed. Iterable retries some failed requests, but a user can still exit a journey at this step if the request keeps failing.
- Order is not guaranteed. Journey processing and webhook retries can cause webhook requests to arrive out of order.
- Duplicate deliveries are possible when a previous attempt times out or fails and a retry is sent.
# Response times, retries, and timeouts
Iterable applies a 10-second timeout to journey webhook requests.
If a call times out after 10 seconds or returns a retryable status code, Iterable retries after a 3-minute delay, up to 3 times.
# HTTP response code handling
Iterable uses the webhook response status code to determine next steps:
| HTTP status | How Iterable responds |
|---|---|
2xx | User continues to the next step in the journey. |
401 | For OAuth 2.0 authentication, Iterable fetches a new access token and retries the webhook request. |
429, 502, 503, 504
| Iterable retries after 3 minutes, up to 3 retries. |
| All other status codes | User exits the journey. |
If the webhook request still fails after 3 retries, the user exits the journey at this step. When future users enter the tile, Iterable still attempts to call the webhook.
# OAuth 2.0 behavior for 401 responses
If a journey webhook configured with OAuth 2.0 receives a 401 response,
Iterable fetches a new access token and retries the webhook request.
# Other failure conditions and notifications
- If the webhook has an invalid URL or returns an SSL exception, the user exits the journey at this step.
- For User Profile tiles, if the response body is not a valid JSON object, the user exits the journey at this step.
- If a webhook's request to fetch an OAuth 2.0 access token fails, the user exits the journey at this step.
# Journey webhook endpoint requirements
To work reliably with Iterable, your endpoint should:
- Support the HTTP method you configure in the journey webhook (
GET,POST,PUT,PATCH, orDELETE). - Respond within 10 seconds.
- Return
2xxfor successful requests. - Handle duplicate deliveries safely (idempotent processing is recommended).
- Return a valid JSON object if you use a User Profile tile to process the webhook response.
If your endpoint URL is invalid, or if the endpoint returns an SSL exception, the user exits the journey at this step.
# Creating journey webhooks
To create a journey webhook:
-
Go to Integrations > Journey webhooks and click New webhook. This takes you to the Create Journey Webhook page:
Give the webhook a name for display purposes. You'll use this name to select the webhook when you add it to a journey.
-
For Destination, choose one of the following:
- Custom to set up the webhook to any other endpoint than Inkit.
- Inkit to use the Iterable + Inkit integration. (When you select Inkit, Iterable automatically preselects the required properties in the Journey Webhook form. All you have to do is fill them in.)
Select the HTTP method that the webhook endpoint requires:
GET,POST,PUT,PATCH, orDELETE. (If you're unsure which one to choose, ask the endpoint's owner.)For Endpoint, enter the destination URL for the HTTP request. You may enter Handlebars expressions to include user profile fields in the URL. For endpoint formatting and Handlebars guidance, including how to add variables, see Endpoint.
-
Select an Authentication option to set up the
AuthorizationHTTP header.- None - No authentication header. (You can still use custom headers.)
-
Basic - Basic authentication. Enter your token in the
Authentication Token field. Iterable adds the
Authorizationheader to the webhook request with the valueBasic <YOUR_AUTH_TOKEN>. - OAuth 2.0 - OAuth 2.0 authentication using client credentials. Provide your Client ID, Client secret, and Token URL.
For more information about these authentication options, see Authentication.
NOTE
Iterable does not encode your authentication token. If needed, encode it before saving it to the journey webhook.
-
Add the webhook request Body (the data that the webhook should send to the app or service you're connecting to the journey).
For body formats, payload field behavior, and request field options, see Body, Include
emailandworkflowId, and User fields. -
(Optional, for Live Data beta only) Check the Data Retrieval box to define specific fields from the webhook's payload to make available as live data in journeys (required for journey webhooks that will be referenced in Live Data tiles) (beta). In this section, you need to run a successful test of your journey webhook configuration to fetch a response, then select which fields from the response you wish to make available for referencing as live data.
Under Test Connection, enter sample JSON data to populate any dynamic parameters included in the endpoint URL. For example, for an endpoint that contains
{{email}}:{ "email": "user@example.com" }
Click Run Test to test the connection to the external app. Iterable populates the URL with your sample data and makes a call to the endpoint with the method and request body configured above. If the test is successful, Iterable shows the response and generates a list of returned objects and fields available to be defined as live data fields in journeys. The webhook cannot be saved until a successful test is completed — this ensures that broken or mistyped configurations never reach your production journeys.
In the Live Data Fields section, select up to 10 fields and associated data types from the JSON response that you wish to save as live data fields that can be referenced in journeys. To learn more about configuring and using live data in journeys, see Journey Live Data Overview.
BETA FEATURE
The Data Retrieval option is currently available as part of the Journey Live Data beta for select Iterable customers. If you're interested in using this feature while it's in beta, talk to your customer success manager to request access.
# Journey webhook properties
When you create a journey webhook, you can set the following properties:
# Name
The name of the webhook. You'll use this name to select the webhook when you add it to a journey.
# Destination
The destination of the webhook. You can choose from the following destinations:
- Custom - Set up the webhook yourself. When you select Custom, you can enter the Method, Endpoint, Authentication, and Body properties.
- Inkit - Set up the webhook to send data to Inkit. When you select Inkit, Iterable automatically preselects the required properties. All you have to do is fill them in. To learn more about setting up a journey webhook for Inkit, see Inkit + Iterable Integration.
# Method
The HTTP method of the webhook. You can choose from the following methods: GET,
POST, PUT, PATCH, and DELETE. Most use cases use POST, but check with
the endpoint's owner to confirm the correct method.
NOTES
- If you want to update a user profile based on a
GETresponse from your endpoint, use a User Profile tile in a journey to update the user profile, rather than a Call Webhook tile. To learn more, read User Update Tiles. - To learn about the different HTTP request methods, check out MDN's guide to HTTP Request Methods.
# Endpoint
The URL of the webhook.
You can use Handlebars expressions to pass user profile fields to the webhook
URL. If the values in those expressions can contain anything other than
letters, numbers, periods, hyphens, asterisks, or underscores, wrap those
parameters with {{#urlEncode}}:
https://api.example.com/update?email={{#urlEncode}}{{email}}{{/urlEncode}}
Handlebars expressions defined in the endpoint URL here apply to all journey tiles that reference this webhook. If you need different values per tile—for example, to pass a different experiment ID depending on the journey—you can instead add Handlebars expressions via the Dynamic Parameters field when configuring a Live Data or Webhook tile. The Dynamic Parameters field lets you reuse one webhook across multiple tiles and populate dynamic data specific to each one.
# Authentication
The authentication method of the webhook. This creates an Authorization
HTTP header that's included in the webhook request.
You can choose from the following authentication options:
# None
Choose None for authentication if your webhook endpoint does not require authentication, or if you use a custom authentication method such as a different header name.
# Basic
Choose Basic authentication if your webhook endpoint requires Basic authentication.
When you select Basic, and enter your token in the webhook's Authentication Token field, Iterable adds this header:
Authorization: Basic <YOUR_AUTH_TOKEN>
NOTE
Iterable does not encode your authentication token. If needed, encode it before saving it to the journey webhook.
# OAuth 2.0
Choose OAuth 2.0 to authenticate your webhook with OAuth 2.0 client credentials.
In the journey webhook properties, provide:
- Client ID
- Client secret
- Token URL - The endpoint that Iterable uses to fetch an access token using the OAuth 2.0 flow.
To fetch an access token, Iterable sends a POST request to your Token URL with:
content-type: application/x-www-form-urlencoded-
This form-encoded body:
client_id=<CLIENT_ID>&client_secret=<CLIENT_SECRET>&grant_type=client_credentials
Then, the OAuth 2.0 endpoint should respond with these JSON fields:
-
access_token(Required) - Access token for subsequent webhook requests. -
expires_in(Optional) - Number of seconds until the token expires on your servers.
An example token response:
{ "access_token": "<ACCESS_TOKEN>", "expires_in": 432000 }
Iterable then sends Authorization: Bearer <ACCESS_TOKEN> in the webhook request
to the webhook endpoint.
NOTE
OAuth token caching in Iterable:
Iterable caches OAuth 2.0 access tokens for up to 10 days. Iterable continues
to use the cached token until your server responds with a 401 error, or
after 10 days, whichever comes first.
The value your server provides for expires_in does not change Iterable's
token cache duration.
If Iterable receives a 401 error for an OAuth 2.0 webhook call, it fetches a new
token and retries the request (up to three times).
# Custom headers
The custom headers to include in the webhook request. These are added as HTTP headers to the webhook request in addition to the header specified in the Authentication property, if used.
# Security considerations for custom headers
IMPORTANT
Custom headers are less secure than Authorization headers. Use them with caution.
Custom headers are visible as plain text to any Iterable user with the Manage Integrations project permission.
Keep this in mind if you need to include sensitive information in a custom header.
To have Iterable securely handle tokens, consider using Authentication headers whenever possible.
# Adding custom headers
To add a custom header, click Add Header, then specify a Name and Value.
# Body
A custom request body to add additional fields to the webhook payload. Use this field to enter any additional fields that aren't already included in the default payload. The custom body is merged into the default payload, and all fields are sent to your destination.
# Custom body formats
Select JSON or URL-encoded:
JSON - Enter JSON directly in the field provided.
-
URL-encoded - Add form fields as name-value pairs.
For example, if your project stores first names in
firstName, you can set:-
Name:
firstName -
Value:
{{firstName}}
-
Name:
# Include email and workflowId
Whether to include email and workflowId in the webhook request body. This
adapts to the payload type selected (JSON or URL-encoded).
# User fields
User profile fields to include in the webhook request body.
Add fields by clicking Add user field and selecting the fields to include.
NOTES
- If a referenced field exists on both the user profile and in the event or API payload that entered the journey, Iterable uses the value from the event or API payload.
- If a referenced field is not on the user profile, Iterable omits it from the webhook request (unless it is present in the event or API payload that triggered the journey).
- Available fields can vary by journey entry source. For example, a journey
with a Purchase entry source can include
total, while a List Subscribe entry source cannot. - Always test a journey webhook before using it in a live journey.
# Journey webhook payloads
When a user reaches a Call Webhook tile that uses a saved journey webhook, Iterable sends URL-encoded form fields, or a JSON object, to your destination.
That payload includes the following data:
- The user profile fields you add with Add user field.
- The journey trigger data (for example, if the journey was triggered by a purchase event, the payload will include the purchase amount and product details).
-
emailand/orworkflowId(when IncludeemailandworkflowIdis enabled). - Your webhook's custom body (if you define one).
# Field name conflicts
If the same field name appears in multiple data sources for the payload, values from trigger data or your custom body replace values from selected user profile fields. In other words, fields in the custom body overwrite fields in the trigger data or user profile fields.
For example, if you add a custom body with a firstName field, and the user
profile has a firstName field, the value from the custom body is sent
to the destination.
# Send rate and processing time for journey webhooks
Journey webhooks can have rate limits set on them, indirectly, by setting a rate limit on the Call Webhook tile in a journey. To learn about setting a rate limit on a Call Webhook tile, see Setting a Rate Limit.
A webhook tile's rate limit controls the maximum request throughput for that tile. Lower limits and higher retry volume can increase queueing time before users move to the next tile.
Overall processing time for journey webhooks varies based on your configured rate limit (as defined in the Call Webhook journey tile), journey volume (how many users are in the journey at once), retry behavior, and destination endpoint performance.
If your endpoint is used in multiple journeys, the overall rate limits for the total number of requests to your endpoint is the sum of the rate limits for all journeys that use it.
Use rate limits to match what your destination can handle, and plan for processing time to vary with traffic and endpoint responsiveness.
# Managing journey webhooks
To view the journey webhooks that have been set up for your Iterable project, navigate to Integrations > Journey Webhooks. From this page, you can create, copy, edit, and delete journey webhooks.
# Viewing journey webhooks
To view the details for a particular journey webhook, click the arrow next to its name. You'll see information about the request body that's included with the webhook, as well as a list of journey tiles that rely on it.
# Copying journey webhooks
To make a copy of an existing journey webhook, click the overflow menu (three dots) for your desired webhook, and select Duplicate Webhook.
NOTE
When you duplicate a journey webhook, the copy doesn't automatically include the same authentication settings as the original. You'll need to set up authentication manually.
# Editing journey webhooks
To edit an existing journey webhook, click the overflow menu (three dots) for your desired webhook, and select Edit Webhook.
When you edit an existing journey webhook, the changes take some time to propagate due to caching. For example, if you change the URL, Iterable may continue to send data to the old webhook URL for a short time after you update it.
# Deleting journey webhooks
To delete a journey webhook, click the overflow menu (three dots) for your desired webhook, and click Delete Webhook.
Before deleting a journey webhook, check whether any live journeys currently reference it. If a user reaches a Webhook or Live Data tile that references a deleted journey webhook, they'll exit the journey.
IMPORTANT
To prevent failed webhook calls and unintended user exits, journey webhooks that are referenced in Live Data tiles in published journeys cannot be edited or deleted. To make changes to a journey webhook that's in use, first stop or unpublish the journey, then edit the journey webhook and republish the journey.
# Testing journey webhooks
As you're setting up a journey webhook, it can be useful to check the requests it sends to make sure that everything is working as you expect. However, sometimes it's difficult to access a webhook's data.
Try using a service like Webhook.site or RequestBin to set up a test webhook URL and check its incoming requests.
# Example journey webhook requests
Let's say you have a journey called "Welcome Sequence" (journey ID: 12345),
which uses the API call entry source and contains three journey webhooks. Here
are some sample calls and responses for this journey.
# POST request
Let's say you add a user to the Welcome Sequence journey by calling Iterable's
POST /api/workflows/triggerWorkflow
API endpoint, and you include this data in the request:
{ "workflowId": 12345, "email": "test.user@example.com", "dataFields": { "promotionId": 123, "color": "red" } }
If the journey contains a Webhook tile that makes a POST request,
that request includes the items contained in the dataFields of the triggering
API call, like this:
{ "promotionId": 123, "color": "red", "email": "test.user@example.com", "workflowId": 12345 }
# PUT request
Let's say you make a call to the Iterable POST /api/workflows/triggerWorkflow API endpoint that looks like
this:
{ "workflowId": 12345, "email": "user@example.com", "dataFields": { "promotionId": 123, "color": "red" } }
This call would add the user user@example.com to the Welcome Sequence journey.
If the journey contains a webhook that includes the user profile fields city
and state in the JSON request body, Iterable would send the following PUT
request when the user reaches that tile:
{ "city": "San Francisco", "state": "California", "promotionId": 123, "color": "red" }
# GET request
When you configure a User profile tile in a journey to retrieve data from a
webhook, it makes GET requests to the URL that you specify (appending
email as a query parameter). For example:
https://api.example.com/webhook/endpoint?email=user@example.com
This endpoint might return JSON data such as:
{ "firstName": "Test", "lastName": "User" }
After receiving this response, Iterable would update user@example.com to have
a firstName of Test and a lastName of User.
# Marketing example: Button-click journey with custom fields
Let's reuse the earlier POST /api/workflows/triggerWorkflow example. Imagine
you run a campaign where users click a Claim offer button in an email, and
that click triggers a journey webhook call to an external attribution or ad platform.
The journey is triggered with:
{ "workflowId": 12345, "email": "test.user@example.com", "dataFields": { "promotionId": 123, "color": "red", "buttonName": "Claim offer", "buttonUrl": "https://example.com/spring-sale" } }
Without a custom JSON body, the webhook payload can include:
{ "promotionId": 123, "color": "red", "buttonName": "Claim offer", "buttonUrl": "https://example.com/spring-sale", "email": "test.user@example.com", "workflowId": 12345 }
If you add a custom JSON body, Iterable adds those custom fields to the payload.
For example, you might add a custom JSON body that includes:
{ "campaignName": "Spring Launch 2026", "journeyStep": "clicked_offer_button", "marketingContext": { "channel": "email", "audienceSegment": "high_intent_returning_users" } }
And then Iterable sends the following payload to your destination.
{ "promotionId": 123, "color": "red", "buttonName": "Claim offer", "buttonUrl": "https://example.com/spring-sale", "email": "test.user@example.com", "workflowId": 12345, "campaignName": "Spring Launch 2026", "journeyStep": "clicked_offer_button", "marketingContext": { "channel": "email", "audienceSegment": "high_intent_returning_users" } }
# Want to learn more?
For more information about some of the topics in this article, check out these resources:
Support docs