> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Delivery & Best Practices

## Event delivery behavior

### Test payload

When you register a webhook, Dynamic sends a test payload to the webhook's configured URL to verify that the endpoint exists and can receive payloads. The test payload is a `ping` event.

### Automatic retries

Webhook messages have built-in retry logic. Any response outside the `2XX` range, or no response within the [endpoint response time](#endpoint-response-time), is treated as a failed delivery and triggers a retry.

Events are delivered at least once. In **live** environments, Dynamic makes the initial delivery plus up to **5 automatic retries** spaced over 1 day; design your endpoint to be [idempotent](#idempotency) using the `eventId` attribute.

The retry schedule in live environments:

| Attempt | Time since previous attempt | Time since initial attempt |
| - | - | - |
| Retry 1 | 15 seconds | 15 seconds |
| Retry 2 | 45 seconds | 1 minute |
| Retry 3 | 9 minutes | 10 minutes |
| Retry 4 | 50 minutes | 1 hour |
| Retry 5 | 23 hours | 1 day |

After Retry 5 fails, the message is marked failed and **no further automatic delivery is attempted**. The message itself is still stored: see [Manual redelivery](#manual-redelivery) below for how to re-trigger it.

#### Sandbox environments

Sandbox webhooks use the same retry rule (any non-`2XX` response retries) but stop earlier: after **2 automatic retries** (3 attempts in total, the last about 1 minute after the initial). This avoids tying up retry slots for misconfigured endpoints during development. The auto-disable threshold ([Webhook messages](#webhook-messages)) is calibrated to the same 3-attempt sandbox window.

### Manual redelivery

When a message has stopped retrying (either because all 5 automatic retries failed, or because you want to replay a successfully-delivered event against an updated handler), you can re-trigger delivery manually. A manual redelivery re-queues the same payload and runs the full delivery flow again: initial attempt plus up to 5 automatic retries.

Two ways to do this:

* **From the Dynamic Console.** Open the webhook in the Dynamic Console, expand the message in the **Messages** list, and click **Redeliver**. The button is disabled when the parent webhook is disabled, so re-enable the webhook first.
* **From the REST API.** `POST /environments/{environmentId}/webhooks/{webhookId}/messages/{messageId}/redeliver`. See the [Redeliver a webhook message](https://www.dynamic.xyz/docs/api-reference/webhooks/redeliver-a-webhook-message.md) endpoint reference. Redelivered messages appear in the message list with a `redelivery` badge so you can distinguish them from automatic retries.

You can redeliver any message that's still within the [message retention window](#webhook-messages) (90 days in live, 30 days in sandbox). After that, the message record is gone and cannot be redelivered.

### Event ordering

Dynamic makes no guarantee of message ordering. Events can be sent in an order not congruent with the order in which they happened.

## Best Practices for implementing webhooks

### Idempotency

Configured endpoints may receive the same event multiple times. This can happen for a number of reasons, including network timeouts, duplicate events, or as a result of retry logic. As such, it is important to design your endpoint to be idempotent so that it can safely handle duplicate events. Using the `eventId` attribute in the event object is a good way to handle this.

### Events

Only select the events you are interested in. If you are only interested in `user` events, only select those event types. This will reduce the number of messages you receive and the number of messages you need to handle.

### Verify messages

Make sure to validate the `x-dynamic-signature-256` header to ensure the message is coming from Dynamic. This is a hash signature value, generated from your secret token.

### Security

Make sure your endpoint is using HTTPS. Dynamic will not send messages to endpoints that use HTTP.

## Limits

### Webhooks

10 per environment

### Webhook messages

After repeated failed delivery of messages within a 30 day period to a configured endpoint that responds with a non `2XX` HTTP status code the webhook will be automatically disabled. For live environments this is 6 failed attempts per message up to a maximum of 1500 failed messages, and for sandbox environments this is 3 failed attempts per message up to a maximum of 250 failed messages. Note that if any of the message retries are successful it is not counted against the failure limit. The webhook will remain disabled until it is re-enabled manually.

Messages in live environments will be available for 90 days and 30 days for sandbox environments.

### Endpoint response time

Configured payload urls must respond promptly, if the endpoint does not respond within 15 seconds, the message timeout and will be retried.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.