Troubleshoot webhook issues
Normally, an event happens, SendPulse sends a POST request to your webhook URL within a few seconds, your server returns a success code, and the request appears in the log with a green status. If one of these steps breaks, the log shows which one.
Let's talk about how to fix webhook issues, from a server that doesn't receive requests to a signature that doesn't match.
Your server doesn't receive requests
Either SendPulse didn't send the request, or your server didn't accept it. The request log shows which of the two happened.
To find the cause, go to Account settings > Webhooks and find the webhook. Its card must show the Active status. If it shows Inactive, click the three dots on the card and select Enable.
Click the three dots and select Edit, then click Test request. A green dot with the 200 code means your URL is reachable. If the test fails, see The test request fails.
Repeat the action that triggers the event.
Click the three dots and select Log, then click Refresh logs.
If there's no record, see An event happened, but there's no log entry.
If the record shows an error, see the section for its status: Timeout, 4xx, or 5xx.
If the record shows 200 but your server didn't process the data, the request reached the server. Look for the error in your handler and your server logs.
An event happened, but there's no log entry
SendPulse didn't send a request. This can happen for the following reasons:
- the event isn't selected in the webhook, or it's selected under another tool, such as Delivered under SMS instead of Email;
- the webhook is inactive;
- the action doesn't trigger this event, for example, disabling a subscriber in a mailing list isn’t an unsubscription, so SendPulse doesn't send the Subscriber unsubscribed event;
- it was a test request, and test requests don't appear in the log;
- it's a chatbot or pop-up event, which the Webhooks section doesn't send. See Chatbot and pop-up events aren't in the list.
To fix this click the three dots on the webhook card and select Edit. In the Events list, make sure the event is selected under the right tool. Make sure the Status toggle is on, and click Save.
Compare your action with the event description in Choose events to receive. Repeat the action, open the log, and click Refresh logs. The record appears within a few seconds.
If there's still no record, contact support and provide the webhook URL, the event, and the time of the action.
The log shows the Timeout status
SendPulse didn't receive a response from your server in time. The Response time column shows a dash.
To fix this, open the log and expand the record. The Request body section shows what SendPulse sent. Make sure your server is reachable from the internet over HTTPS and its certificate is valid.
If your server has a firewall, allow the IP addresses from the Webhook source IP addresses list in the webhook form.
If your handler takes a long time to process the data, return a success code first and process the data in the background.
Click Retry in the record row, then click Refresh logs.
The log shows a 4xx status
Your server received the request and rejected it. The common causes are the following:
- a wrong URL path (
404); - a handler that doesn't accept POST requests (
405); - required authorization (
401,403); - a framework that blocks POST requests without a CSRF token (
403); - a limit on the number of requests (
429).
To fix this, expand the record in the log. The Response body section shows your server's response.
For 404, check the path in the Webhook URL field.
For 405, make your handler accept POST requests.
For 401 or 403, add the authorization header your server expects in the Additional headers section, or exclude the webhook route from the authorization and CSRF checks.
For 429, allow more requests from the addresses in the Webhook source IP addresses list.
Click Retry in the record row, then click Refresh logs.
The log shows a 5xx status
Your server received the request but failed while processing it. SendPulse retries the request automatically after 1, 5, and 30 minutes. Each attempt is a dedicated record with its number in the Attempt column, and the request body and signature stay the same.
To fix this, expand the record in the log. The Response body section shows your server's error, and the Request body section shows what SendPulse sent.
Find the error in your server logs by the time in the Date and time column. The log shows time in your account's time zone.
Make sure your handler accepts the body of every selected event: the set of fields in data differs from event to event.
Once you fix the error, wait for the automated retry or click Retry in the record row, then click Refresh logs.
The test request fails
The result of a test request appears next to the Test request button: a dot, the status code, and the response time, for example, 405 · 87 ms.
The causes are the same as for regular requests, with one addition. The test request has the test event type, no scope field, and an empty data field, so a handler that expects event data can fail on it.
To fix this, save the webhook, click the three dots on its card, select Edit, and click Test request.
If the result isn't 200, see Timeout, 4xx, or 5xx.
If your server fails only on the test request, make the handler accept a body without scope and with an empty data field.
Click Test request again.
SendPulse doesn't accept the webhook URL
SendPulse supports only public HTTPS URLs, and each webhook in your account needs its own URL. The validation messages for the Webhook URL field are as follows:
| Message | Cause | What to do |
| Enter a valid HTTPS URL | The URL starts with http:// or isn't a valid address. |
Enter a URL that starts with https://. |
| Enter a valid public HTTPS URL | The URL points to localhost, an internal domain, or a private IP address, or the domain doesn't resolve to an IP address. |
Use an address that's reachable from the internet. If your server is still in development, use a tunnel or a service that gives you a public HTTPS URL. |
| A webhook with this URL already exists | Another webhook in your account uses this URL. | Click Filter, enter the URL in the Search field, and click Apply. Then, click the three dots on the found webhook, select Edit and add the events to it. |
Once you change the URL, click Save, then click Test request to check it.
SendPulse doesn't accept an additional header
Additional headers have limits, and some names are reserved because SendPulse sets them itself. The validation messages for the header are as follows:
| Message | Cause | What to do |
| This header is reserved and cannot be overridden | SendPulse sets this header itself, for example, Content-Type, X-Signature, or X-Event-Type. |
Use another header name. |
| Enter a valid header name using 1 to 128 allowed characters | The name is empty, longer than 128 characters, or contains characters that aren't allowed in HTTP header names, such as spaces. | Enter a name of 1 to 128 allowed characters. |
| Enter a header value using 1 to 1024 printable ASCII characters | The value is empty, longer than 1024 characters, or contains non-ASCII characters, such as non-Latin letters. | Enter a value of 1 to 1024 printable ASCII characters. |
If the Add header button is inactive, the webhook already has the maximum of 10 headers. Together, a webhook's headers can take up to 8 KB.
Once you change the headers, click Save, then click Test request and check on your server that the header was received.
The signature doesn't match the X-Signature header
Your server calculates the HMAC-SHA256 hash over a different body or with a different key. The common causes are the following:
- a regenerated key that wasn't updated on the server;
- a body that was parsed and re-serialized before verification;
- a comparison without the
sha256=prefix; - a key used as decoded bytes instead of a text string.
To fix this, click the three dots on the webhook card and select Edit. In the Secret key field, click the eye icon, then the copy icon, and compare the key with the one on your server. Once you regenerate the key, the previous key stops working immediately.
Calculate the hash over the raw request body, before you parse the JSON.
Compare the result with the whole header value, including sha256=, or remove the prefix before comparing.
Use the key exactly as shown in the field, as a text string.
Click Test request and check the signature of the test request.
The same event arrives more than once
This can happen for the following reasons:
- an automated retry: your server responded with an error or too late, so SendPulse sent the same request again;
- a manual retry from the request log;
- the Tag linked and Tag unlinked events occur in pairs: one request for the subscriber and one for the mailing list. This isn't a duplicate; the
entity_typefield in the request body tells the two requests apart.
To fix this, return a success code right away, before you process the data.
Before processing, check whether your server has already handled this event. SMS events contain the event_id field for this.
For tag events, check the entity_type field.
Events arrive out of order
SendPulse sends each event as a dedicated request, and requests can arrive out of order. For example, Email opened can arrive before Delivered.
To handle this, order the events by the occurred_at field in the request body, not by the time your server received them.
Your handler stopped processing events after the migration
SendPulse migrates the email service and SMTP webhooks from the former API and webhooks section to the Webhooks section automatically and disables the previous records.
Requests from a migrated webhook also contain the data in the previous format, in the "0" element. However, a migrated webhook sends one event per request instead of an array of events.
The request body is a JSON object that contains the "0" element and the user_id, scope, event_type, occurred_at, and data fields. A handler that processes the request body as an array might fail on these requests.
To fix this, go to Account settings > Webhooks, find the migrated webhook by its URL, click the three dots on its card, select Edit, and check the URL and events.
Update your handler to read one event from the request body instead of iterating over an array. To keep your current processing code, read the event from the "0" element. Take an action that triggers one of the selected events, then check the status of the new record in the request log.
Don't use a test request for this check because it doesn't contain the "0" element.
Old requests are missing from the log
SendPulse stores log records for 30 days, and the log of a deleted webhook isn't available. The page shows 20 records at a time.
To see earlier records from the last 30 days, click Show more. Records older than 30 days and the logs of deleted webhooks can't be restored, so if you need the history, store the requests on your side.
To pause a webhook and keep its log, click the three dots on its card and select Disable instead of Delete.
A team member doesn't see the Webhooks section
A team member sees the Webhooks section only if their user role has the Settings right in the Email and marketing campaigns group.
To fix this, ask the account owner to assign you a custom user role with this right. Refresh the page and go to Account settings > Webhooks.
Read more: Create a custom user role.
Chatbot and pop-up events aren't in the list
The Events list in the webhook form doesn't include chatbot and pop-up events. Webhooks for chatbots and pop-ups are set up in the settings of the specific chatbot or pop-up.
To receive these events, set up a webhook for chatbots and pop-ups.
Read more: How to send webhooks via chatbots, Set up notifications about new leads using webhooks.
If the issue persists, contact support and provide the webhook URL, the event, and the date and time of the request from the log.
To continue using webhooks, learn how to set up webhooks, verify the request signature, and view the request log and retry requests.
or