> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.messageblue.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.messageblue.ai/_mcp/server.

# Failed webhooks

Route `/failed-webhooks`

Find it Left rail → Failed webhooks

Who can open it Admins and team members

When a [webhook delivery](/settings#webhooks) cannot reach your server, MessageBlue keeps the payload rather than dropping it. This screen lists those deliveries and lets you replay them: *"Retry re-POSTs the stored webhook payload."*

Nothing is lost while your endpoint is down — an outage becomes a queue to work through rather than a hole in your data.

![Failed webhooks page showing search, type and date filters above an empty Deliveries table](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/message-blue.docs.buildwithfern.com/a39761af782a1017afc73d77cdd23ddd14546a0511579e6ae5041a6c3087cf83/docs/assets/frontend/failed-webhooks.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260916%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260916T212210Z&X-Amz-Expires=604800&X-Amz-Signature=0ee7de0b247df0eb92f5ab49f299ef7e4496a8f93df5b6e2563b19ac0f842815&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject)

An empty table is the state you want. It means every event MessageBlue tried to deliver was accepted by your server.

## Finding a delivery

The search box matches on **event ID, phone number, or message text**, and three more filters narrow it further:

| Filter                      | Values                                                     |
| --------------------------- | ---------------------------------------------------------- |
| **Type**                    | All types, `inbound_message`, `inbound_reaction`, `status` |
| **From date** / **To date** | Any range                                                  |

Press **Apply** to run the query. With no matches you get *"No failed or dead-lettered webhooks for these filters."* — worth re-reading before concluding nothing failed, since a stale date range is the usual cause.

## Reading the table

| Column         | What it tells you                                                             |
| -------------- | ----------------------------------------------------------------------------- |
| **Created**    | When the event happened                                                       |
| **Event ID**   | The identifier to correlate against your own logs                             |
| **From**       | The sender's number                                                           |
| **Text**       | A truncated preview of the message                                            |
| **Status**     | `failed`, `dead_lettered`, or `redelivered`                                   |
| **Why failed** | The error from the last attempt — usually a status code or a connection error |
| **Action**     | The retry control                                                             |

Statuses mean different things:

#### failed

An attempt failed. Automatic retries may still be pending.

#### dead\_lettered

*Exhausted automatic retries.* MessageBlue has stopped trying — only a manual retry will move it.

#### redelivered

A manual retry succeeded. Nothing more to do.

## Inspecting one delivery

Clicking a row expands it into the full record: the complete **message text**, the **webhook URL** it was sent to, **updated** and **delivered at** timestamps, the **attempt count**, the full **attempt history**, and the complete **request body** that was POSTed.

The attempt history is the useful part when debugging a persistent failure — it shows whether every attempt failed the same way (your endpoint is consistently rejecting it) or differently (an intermittent problem).

The **Full body** panel is exactly what your server would have received. Replaying it locally with `curl` is the fastest way to reproduce a handler bug without waiting for another live event.

## Retrying

The retry button re-POSTs the stored payload and confirms with *"Webhook redelivery enqueued. Status updates to redelivered on success."*

Only `failed` and `dead_lettered` rows can be retried — the button is disabled elsewhere and explains why: *"Only failed or dead\_lettered can be retried."*

Fix the cause before you retry in bulk. A retry against an endpoint that is still broken simply fails again, and your handler must be idempotent regardless — a redelivered event carries the same event ID as the original, so any handler that creates records without checking will duplicate them.