Webhooks are fire-and-forget. The sender fires an HTTP request and moves on. If your receiver is down, the webhook is lost -- or retried, maybe, if the sender is generous. Unlike APIs you call, webhooks call you -- and if nobody answers, you might not find out until a customer complains that their payment did not process or their deploy did not trigger.

This is the fundamental problem with webhook endpoints: they fail silently. Your application logs show nothing because the request never arrived. Your health checks pass because they do not test webhook routes. Everything looks green while critical integrations are quietly broken.

This guide covers how to monitor webhook endpoints for availability, response time, and correctness -- including how to handle signature validation, what status codes to expect, and how to combine webhook monitoring with heartbeat monitoring for end-to-end visibility. If you are new to monitoring in general, start with our uptime monitoring setup guide.

Why webhook endpoints need monitoring

Webhook endpoints are invisible failure points. They do not show up in your regular health checks. They are not part of the user-facing request flow. And when they break, the symptoms show up somewhere else entirely -- often hours later.

Consider what happens when specific webhook handlers go down:

  • Stripe webhook handler is down -- payments stop processing. Customers get charged but your system never fulfills orders, upgrades plans, or sends receipts.
  • GitHub webhook handler is down -- CI/CD stops triggering. Developers push code and nothing happens. Deploys stall silently.
  • Slack event handler is down -- your bot goes silent. Users message it and get no response. Support requests pile up.
  • Twilio webhook handler is down -- inbound SMS and voice calls go unanswered. Customer communications disappear.

The common thread: most webhook failures are silent. There is no error in your logs because the request never reached your application. The sender may retry a few times, but eventually gives up. By the time you notice, the damage is done.

Types of webhook endpoints to monitor

Any endpoint that receives inbound HTTP requests from a third-party service is a webhook endpoint worth monitoring. Here are the most common categories.

Payment webhooks

Stripe, PayPal, Square, Paddle, Lemon Squeezy -- every payment processor communicates asynchronously via webhooks. Subscription updates, successful charges, failed payments, refunds, and disputes all arrive as webhook events. If your handler is down, you lose visibility into your revenue.

CI/CD webhooks

GitHub, GitLab, and Bitbucket use webhooks to trigger builds, deployments, and automated workflows. A broken webhook receiver means pushes to main do not trigger deploys, pull requests do not get status checks, and your entire development pipeline stalls. See our guide on CI/CD uptime monitoring for more on keeping your pipeline reliable.

Communication webhooks

Slack, Discord, Twilio, and SendGrid send event data via webhooks -- incoming messages, delivery receipts, read notifications. If you are building a bot, an SMS gateway, or an email processing pipeline, these webhook endpoints are critical. Set up Slack alerts or Discord alerts so you know immediately when they go down.

CRM and marketing webhooks

HubSpot, Mailchimp, Segment, and similar tools send webhooks for form submissions, contact updates, and event tracking. These feed your sales pipeline and marketing automation. A down webhook handler means leads slip through the cracks.

Infrastructure webhooks

AWS SNS, Cloudflare, PagerDuty, and other infrastructure tools send operational webhooks -- scaling events, security alerts, incident notifications. Missing these can mean ignoring a critical infrastructure event.

How to monitor webhook receivers

Webhook endpoints present a unique monitoring challenge. Unlike a typical health check endpoint that responds to GET requests, webhook endpoints expect POST requests with specific payloads -- and often validate cryptographic signatures.

You cannot just send a GET request to /webhooks/stripe and check if it returns 200. Most webhook handlers will return 404 or 405 for GET requests, even when they are perfectly healthy.

The approach: create a monitor that sends POST requests with a minimal valid payload and checks for an expected response. If the endpoint validates signatures, you have two options (covered in the signature validation section below). For more on monitoring POST endpoints in general, see our API endpoint monitoring guide.

Setting up webhook monitors in CronAlert

Here is how to configure a monitor for a webhook endpoint in CronAlert.

Step 1: Create a new monitor and set the HTTP method to POST.

Step 2: Set the URL to your webhook endpoint -- for example, https://yourapp.com/webhooks/stripe.

Step 3: Add a Content-Type: application/json header.

Step 4: Configure a minimal JSON request body. This does not need to be a real webhook payload -- just enough for your endpoint to accept the request without crashing:

{
  "type": "health_check",
  "data": {}
}

Step 5: Set the expected status code. If your endpoint processes unknown event types gracefully (returning 200), expect 200. If it rejects unknown types, expect whatever status code it returns -- typically 400 or 422.

This is what CronAlert sends on each check:

curl -X POST https://yourapp.com/webhooks/stripe \
  -H "Content-Type: application/json" \
  -d '{"type": "health_check", "data": {}}'

If your webhook endpoint returns a response body, you can use keyword monitoring to verify it contains an expected string like "received" or "ok".

Handling signature validation

Many webhook providers sign their payloads with a secret key. Stripe, GitHub, Shopify, and others include a signature header (like Stripe-Signature or X-Hub-Signature-256) that your endpoint validates before processing. Unsigned requests get rejected with a 400 or 401.

This creates a problem for external monitoring: CronAlert does not have your webhook signing secret, so it cannot produce a valid signature. Two approaches solve this.

Option A: Add a health check route

Create a separate endpoint like /webhooks/stripe/health that bypasses signature validation. This route should:

  • Verify your application is running and can accept requests
  • Check database connectivity (since webhook processing usually writes to a database)
  • Return 200 with a simple response body

This is the more thorough approach because you can test actual dependencies, not just reachability. Monitor this endpoint with a standard GET check.

Option B: Monitor the main route, expect rejection

Monitor the actual webhook endpoint and set the expected status code to 401 or 400 -- whatever your endpoint returns for unsigned requests. This confirms three things: the endpoint is reachable, your application is running, and the webhook route is registered.

This is simpler because it requires no code changes. The tradeoff is that it does not test processing logic or downstream dependencies. If your database is down but your signature validation still runs, the monitor will show green.

For most teams, option A is worth the small investment. For a quick-and-dirty setup, option B works fine. For a deeper look at monitoring endpoints with non-200 expected responses, see our HTTP status codes guide.

Monitoring webhook delivery from the sender side

External monitoring tells you whether your endpoint is reachable. But you should also check what the sender sees.

Most major webhook providers offer delivery logs:

  • Stripe -- Developers > Webhooks > select endpoint > Recent deliveries
  • GitHub -- Settings > Webhooks > Recent deliveries
  • Shopify -- Settings > Notifications > Webhooks > check delivery status
  • Twilio -- Console > Monitor > Logs

Check these regularly. But understand their limitation: provider logs only show what they sent and what response they received. They do not tell you whether your processing logic succeeded. A 200 response from your endpoint means "I received the request" -- not "I processed it correctly."

That is why external monitoring and sender logs are complementary, not redundant. You need both.

Response time matters for webhooks

Most webhook senders have strict timeouts. If your endpoint does not respond in time, the sender marks the delivery as failed and queues a retry:

  • Stripe -- 20-second timeout
  • GitHub -- 10-second timeout
  • Slack -- 3-second timeout
  • Shopify -- 5-second timeout
  • Twilio -- 15-second timeout

If your endpoint is slow, the sender retries. Now you have duplicate events. If your processing is not idempotent, you get duplicate charges, duplicate notifications, or duplicate records. Slow webhook endpoints do not just cause missed events -- they cause duplicated events, which can be worse.

The fix: return 200 immediately and process the event asynchronously. Accept the webhook payload, enqueue it for background processing, and respond. Your endpoint should take milliseconds, not seconds.

// Bad: process synchronously
app.post("/webhooks/stripe", async (req, res) => {
  await verifySignature(req);
  await processEvent(req.body);  // slow database writes, API calls
  res.sendStatus(200);
});

// Good: acknowledge immediately, process async
app.post("/webhooks/stripe", async (req, res) => {
  await verifySignature(req);
  queue.enqueue(req.body);  // fast: just push to queue
  res.sendStatus(200);
});

CronAlert records response time on every check. If your webhook endpoint's response time starts climbing toward the sender's timeout threshold, you will see it in the monitor detail view before it becomes a problem.

Combining with heartbeat monitoring

Webhook monitoring confirms your receiver is up and accepting requests. But it does not tell you whether the downstream processing actually ran. Did the payment get recorded? Did the CI build actually start? Did the Slack message get processed?

Heartbeat monitoring fills this gap. After your background job processes the webhook event, it pings a heartbeat URL. If the ping stops arriving, you know the processing pipeline is broken -- even if the webhook endpoint itself is healthy.

The combination looks like this:

  1. Webhook monitor -- POST check to /webhooks/stripe/health every 1 minute. Confirms the receiver is up.
  2. Heartbeat monitor -- your webhook processing worker pings https://cronalert.com/api/v1/heartbeat/abc123 after processing each batch. Confirms the processing pipeline is running.

If the webhook monitor fails, your endpoint is down. If the heartbeat stops, your processing is stuck. Together, they give you end-to-end visibility from event receipt to event processing. You can also use CronAlert's API to programmatically manage both types of monitors.

Keeping it all visible

Webhook endpoints are infrastructure -- they run in the background, out of sight. That makes it critical to surface their status. Use multi-region monitoring for webhook endpoints that serve a global user base, and SSL certificate monitoring to catch expiring certificates before they take down your webhook receivers.

Create a free CronAlert account to start monitoring your webhook endpoints in under a minute. The free plan includes 25 monitors with 3-minute checks and email, Slack, Discord, and webhook alerts -- enough to cover every critical webhook receiver in your stack. Paid plans start at $5/month with 1-minute intervals for tighter monitoring.

FAQ

Can I monitor webhook endpoints that require authentication?

Yes. CronAlert supports custom headers on any monitor, so you can include Authorization headers, API keys, or any other authentication your webhook endpoint requires. For endpoints that validate webhook signatures (like Stripe or GitHub), consider creating a dedicated health check route that bypasses signature validation, or monitor the main route and expect a 401 or 400 as the healthy response -- confirming the endpoint is reachable and your application is running.

What status code should I expect from a webhook health check?

For a dedicated health check route (like /webhooks/stripe/health), expect 200. For monitoring the actual webhook endpoint without a valid signature, expect whatever your endpoint returns for unsigned requests -- typically 401 Unauthorized or 400 Bad Request. Both confirm the endpoint is reachable. Set the expected status code in CronAlert to match what your endpoint actually returns when healthy.

How do I monitor webhooks that validate signatures?

Two approaches. First, create a separate health check route (like /webhooks/stripe/health) that skips signature validation and tests database connectivity. This is more thorough. Second, monitor the main webhook route and set the expected status code to 401 or 400 -- confirming the endpoint exists and your application is running, without needing a valid signature. The first approach is recommended for production systems.

Should I monitor third-party webhook senders too?

You should monitor your own webhook receivers externally, and also check the sender's delivery logs regularly. Stripe, GitHub, and most major providers have webhook delivery dashboards showing delivery attempts and response codes. External monitoring confirms your receiver is up; provider logs confirm they are actually sending. For complete end-to-end visibility, combine webhook endpoint monitoring with heartbeat monitoring on your processing pipeline.