Webhook
Webhooks let you send journey data to external services such as analytics, CRM systems, and marketing tools. You can:
- Notify external systems when a customer takes an action in the journey
- Send customer data to analytics tools
- Trigger third-party emails, SMS, or WhatsApp on specific journey events
How to set up the Webhook element
Anchor link toAdd the Webhook element
Anchor link toDrag-and-drop the Webhook element to the canvas. Place Webhook anywhere you’d like, keeping in mind what journey info you’re going to send to a third-party service.

Name the Webhook step and specify the request URL and type
Anchor link toIn the STEP NAME field, enter a name for the webhook. It might be handy to name webhooks according to the services they send data to or the use case.
Next, in the URL field, specify the request URL to which the data should be sent. Next to the URL field, select the request type from the REQUEST TYPE dropdown: GET or POST.

Configure headers
Anchor link toIn the HEADERS section, set the content type.
By default, the content type is application/json. If the service you’re sending the webhook to requires another content type, enter the appropriate one in the Content-Type header value.
Examples of content types are:
x-www-form-urlencodedtext/plaintext/xml
Add additional headers if needed by clicking + ADD HEADER. You can remove any header by clicking the ‘x’ icon next to it.
Add whatever authentication header your endpoint requires, for example:
Authorization: Bearer <token>X-Api-Key: <key>Authorization: Basic <base64(user:pass)>
Only a static secret in a header is supported. OAuth2 token-exchange flows, mTLS, and request signing on the Pushwoosh side aren’t supported. You can also restrict the endpoint to Pushwoosh’s IP addresses instead of, or in addition to, a header secret. See Pushwoosh IP addresses.
For HTTP Basic authentication specifically, do the following:
- Open a plain text editor and type your username and password with no spaces, separated by a colon. For example:
<username>:<password> - Encode this string into Base64.
- Copy the resulting Base64 string (for example,
<base64-encoded-string>). - In the webhook settings, add an Authorization header with the value:
Basic <base64-encoded-string>. Make sure there is a space after the word “Basic”.

Mark a header value as secret
Anchor link toClick the eye icon next to a header’s value to mask it. Pushwoosh hides that value everywhere it would otherwise leave the service: in the UI, in API responses, and in the journey’s version history.

- Automatic masking. Headers whose names look like credentials are masked automatically, even if you never click the eye icon. This includes
Authorization,Proxy-Authorization,Cookie,Set-Cookie, and any name containingtoken,secret,password,credential,auth, orapi-key/api_key/apikey(with a hyphen, an underscore, or no separator). - Change a masked value. Click into the field showing
••••••••and type the new value. There’s no button to reveal the stored value. The eye icon stays locked while the mask is shown. To remove the secret flag from a header, type a new value first, then click the icon. - Rename a masked header. Renaming a header whose value is currently shown as the mask clears that value. Enter it again under the new name. Renaming a header that currently holds a value you just typed keeps that value.
Add the JSON request body
Anchor link toIn the DATA section, enter your JSON request body. Make sure the request body is in correct JSON format.
Example:
{ "hwid": "{{device:hwid}}"}Use dynamic data and macros
Anchor link toThe DATA BUILDER panel allows you to insert dynamic information (such as user, device, tag, or event data) directly into your JSON request body. With Dynamic Data, you can include values specific to the individual user progressing through the journey.
For this:
- Select a category. You can pull data from three categories:
-
Device: Use Device data when you need technical information tied to the user’s device.
-
Tag: Use Tag data when you want to send information stored in the user profile.
-
Event: Use Event data when the webhook should send values from the triggering event of the journey.
- Select a parameter (for example, HWID, favourite category, etc.).
- Pushwoosh generates a macro that looks like this:
{{tag:Language}}- Copy the macro and paste it into your JSON body in the DATA section.
When the webhook runs in a live journey, Pushwoosh automatically replaces the macro with the actual value for that user.

Map webhook response data to variables
Anchor link toBesides sending data out, the Webhook element can also capture data from the response it receives and turn it into variables. These variables can then be used later in the journey. For example, set a tag with Update user profile, or schedule a Time Delay based on a value returned by the external service. For a full journey example, see Using webhook response data in your journey.
In the RESPONSE MAPPING section, click + ADD MAPPING and fill in two fields for each value you want to capture:
- Path: the location of the value inside the response JSON body
- Attribute: the name you use to reference this value later in the journey

For example, if your CRM responds with:
{ "data": { "user": { "id": "789xyz" } }}Set Path to data.user.id and Attribute to crm_user_id to capture that ID.
Map every element of an array
Anchor link toPut * where the response has an array to capture a value from every element instead of just one, for example items.*.item_name. What you put in Attribute decides the shape of the result:
- Include
{n}in Attribute (for exampleitem_{n}) to get one attribute per element, counted from 1:item_1,item_2,item_3, and so on.{n}can sit anywhere in the name, for exampleitem_{n}_sku. - Leave
{n}out (for exampleitem_names) to join every element into a single attribute, separated by commas:Sofa, Lamp, Rug.
For example, if your CRM responds with:
{ "items": [ { "item_name": "Sofa" }, { "item_name": "Lamp" }, { "item_name": "Rug" } ]}Set Path to items.*.item_name and Attribute to item_{n} to get item_1 = Sofa, item_2 = Lamp, item_3 = Rug. Set Attribute to item_names instead to get a single item_names = Sofa, Lamp, Rug.
A numbered attribute like item_3 can be referenced anywhere a regular webhook response attribute can: in Update user profile, in a Time Delay, or in Dynamic Content.
Timeout, retries, and failed requests
Anchor link toPushwoosh waits up to 10 seconds for a response. The whole Webhook step, including sending the request and processing the response, is capped at 30 seconds.
Retries
Anchor link toOn a 500, 502, 503, or 504 response, or a network error, Pushwoosh retries the request once before giving up. Any other non-2xx response is not retried.
Rate limits
Anchor link toPushwoosh limits how many webhook requests an account can send per second. The limit is sized well above real traffic peaks, so normal journeys aren’t affected. A burst that exceeds it waits briefly for room before failing.
Endpoint cooldown
Anchor link toIf an endpoint fails several times in a row, Pushwoosh stops sending it requests for a while instead of retrying a broken endpoint on every traveler, starting at 30 seconds and doubling on further failures up to 5 minutes. A single successful request clears this and resumes normal delivery.
What happens when a request fails
Anchor link toThe Webhook element has no separate branch for failed requests. Any of the following drops the traveler from the journey at this step:
| Cause | What triggers it |
|---|---|
| Blocked endpoint address | The URL is private, internal, loopback, or link-local, including cloud metadata endpoints |
| Rate limit | The account’s per-second webhook request limit is exceeded and no room opens up during the brief wait |
| Endpoint cooldown | The endpoint failed several times in a row and Pushwoosh is temporarily skipping it |
| Timeout | No response within 10 seconds, or the step exceeds its 30-second cap |
| Network error | The request couldn’t reach the endpoint at all |
| Non-2xx response | The endpoint returned an error status that isn’t retried, or was retried once and failed again |
See Request error.
If you can’t afford to lose travelers here, have your endpoint always return a 2xx response and put any failure state in the response body instead, for example as a value your Response mapping can pick up.
This applies to every Webhook step, including ones set up before this change. An endpoint address that now matches the blocked-address rule above will start failing the same way.
Unlike a failed request, a response that arrives but doesn’t map cleanly, such as invalid JSON, an unresolved Path, or a body over 64 KB, does not drop the traveler. See the note under Response mapping above.
Test the Webhook
Anchor link toClick Test webhook to verify that your webhook configuration is correct and the request is sent successfully.
If a header still shows the stored mask, Pushwoosh fills in the real, saved value for the test request. The value never appears in your browser.
This substitution only works for a header already saved on this exact step. A step you haven’t saved yet, or one you just copied, has no saved value behind the mask, so Pushwoosh sends the test request without that header.
Save your configuration
Anchor link toClick Apply to save your webhook configuration.
Calls log
Anchor link toOpen the Calls log tab in the point’s drawer to see what Pushwoosh actually sent for this step: time, user, result, and duration, going back 30 days.
Filter by result (Success, HTTP error, No response) or search by the exact User ID or HWID. Click a row to expand it and see the request (method, URL, and body) and, depending on the outcome, either the response (status and body) or the error text. Duration covers the whole step, including time spent on an automatic retry.