# Event delivery retries and event duplication

It can be difficult to achieve perfect stability to receive Event Streams continuously. When network infrastructure, third-party, or Twilio internal issues occur, Event Streams retries delivering an event for up to four hours.

Event Streams notifies you about event delivery issues. You'll get [error logs in the Twilio Console](https://console.twilio.com/us1/monitor/logs/debugger/errors) by default. You'll receive a notification after the first error and then more notifications grouped at certain points: every 20 minutes, after every 10, 100, 1000 errors, and so on. You can also create custom [Alarms](https://console.twilio.com/us1/monitor/alarms/manage) for specific errors to trigger console indicators, email notifications, or webhooks.

## At-least-once delivery

Event Streams guarantees at-least-once delivery of events. When an event delivery fails, Twilio retries delivering the event. Multiple event delivery retries could result in receiving duplicated events. If you want to discard duplicated events, then you must [deduplicate](#deduplicate-events) the events you receive.

## Event delivery retries

When an event delivery fails, Twilio retries delivering the event several times. Twilio performs the retry with an exponential backoff with jitter, meaning that the interval between retries increases and includes some randomness. Because of this randomness, there's no fixed number of attempts. Twilio continues retrying delivery until it succeeds or four hours have passed, after which it stops retrying.

Events Streams might deliver events out of order. You can use each event's timestamp to sort events.

### Error behavior for each sink

The following tables list potential errors and the resulting Event Streams behavior.

#### Kinesis sink

| Issue                                    | Error code | Event Streams behavior |
| ---------------------------------------- | ---------- | ---------------------- |
| Error writing to Kinesis                 | 93101      | retry delivery         |
| assume role error                        | 93102      | retry delivery         |
| get shard count error                    | 93103      | retry delivery         |
| get Kinesis Stream Name And Region error | 93104      | discard event          |

#### Webhook sink

| Issue                                             | Error code | Event Streams behavior |
| ------------------------------------------------- | ---------- | ---------------------- |
| customer returning 429 HTTP error                 | 93101      | retry delivery         |
| customer returning other 400 HTTP error (not 429) | 93101      | discard event          |
| customer returning any 500 HTTP error             | 93101      | retry delivery         |

#### Segment sink

The Segment sink doesn't send notifications when delivery errors occur.

## Events flow control in webhook sinks

If events overwhelm your service, use the response HTTP status codes to control the flow of events:

* Use the `429` status code if you wish the flow of events to slow down, but the events to retry. For example, if events overwhelm your service or your service performs load shedding, but you don't want to lose the event data, use the `429` status code.
* Use the `400` status code if you wish to discard the event with no further retries. For example, if the event is no longer relevant to you after a certain period of time, use the `400` status code.

## Dealing with duplicate events

Twilio might send the same event multiple times for several reasons, including but not limited to the following:

* Event delivery retries due to [errors](#error-behavior-for-each-sink)
* Incident remediation
* Internal temporary errors

### Deduplicate events

Duplicated events are events that have the same `id`. The `id` is a SID like `EZ00000000000000000000000000000000`. If you require exactly-once delivery, then you need to implement deduplication in the service that receives the events.

Use the following general steps to deduplicate received events:

* Check if you previously received another event with the same event `id`.
* If you already received an event with the same `id`, discard the incoming event.
* Otherwise, store the event `id`.

> \[!NOTE]
>
> If you use a [webhook sink](/docs/events/webhook-quickstart), then you should return a `200` success status code when you discard a duplicate event.
> Otherwise, Event Streams attempts to retry delivery.
