# Source: https://docs.stripe.com/event-destinations.md

# Integrate with events

Send events from Stripe to webhook endpoints and cloud services.

> [Thin events](https://docs.stripe.com/event-destinations.md#thin-events) for API v1 resources are available in private preview. You can use them to streamline integration upgrades without changing your webhook configuration. Previously, thin events only supported API v2 resources. [Learn more and request access](https://docs.google.com/forms/d/e/1FAIpQLSeEkqzB02afvlklMkqwA6wsBH90eW8gxmc-hBOvqe2N6TRujQ/viewform?usp=dialog).

Set up an event destination to receive events from Stripe across multiple destination types, including webhook endpoints, and [Amazon EventBridge](https://docs.stripe.com/event-destinations/eventbridge.md). You can receive events in either:

- Self-contained [snapshot events](https://docs.stripe.com/event-destinations.md#choosing-event-format) for a point-in-time view of your resources
- Lightweight [thin events](https://docs.stripe.com/event-destinations.md#thin-events) to guarantee you always act on the most up-to-date data, which help simplify your integration upgrade process

## Use cases

When building Stripe integrations, you might want your applications to receive events in real-time from your Stripe accounts, enabling your backend systems to respond and perform actions accordingly.

With an event destination, Stripe pushes real-time event data from your account, enabling you to run backend actions, such as:

- Sending users a notification when a customer confirms a payment
- Initiating an internal claims reconciliation process when a customer disputes a charge
- Granting access to your user when they make successful recurring subscription payments

## Supported destination types

Send events to an AWS account using [Amazon EventBridge](https://docs.stripe.com/event-destinations/eventbridge.md), or deliver them to an HTTPS endpoint through [webhook endpoints](https://docs.stripe.com/webhooks.md).

## Events overview

When an event occurs, Stripe generates a new `Event` object. A single API request could result in the creation of multiple events. For example, creating a new subscription for a customer might result in `customer.subscription.created` and `payment_intent.succeeded` events. For programmatic integrations, we recommend that you configure an event destination to receive these events as they happen. The way the event is structured and delivered to your destination depends on the format you choose to receive.

We provide two different formats of `Event` objects:

- [Thin events](https://docs.stripe.com/api/v2/events.md): When delivered to your event destination, a thin event arrives as a lightweight event notification that only includes the ID of the affected objects. You can make a subsequent API call to fetch the complete `Event` object or the related resources’s latest state. These are generated by API v2 endpoints . See a [full list of thin events](https://docs.stripe.com/api/v2/events/event-types.md).
- [Snapshot events](https://docs.stripe.com/api/events.md): When delivered to your destination, a snapshot event arrives as the complete `Event` object with an eventually-consistent snapshot of the resource that has changed. Because this data can be stale by the time you process it, we recommend fetching the latest version of the resource from the API. Unlike thin event notifications, the delivered snapshot events are versioned, which requires you to manage versions both on your Stripe event destination and your client. These events are only generated by API v1 endpoints. They include a `previous_attributes` property that indicates the change, if applicable. See a [full list of snapshot events](https://docs.stripe.com/api/events/types.md).

### Choose a format 

Use thin events when:

- Data integrity is critical, and your application must act on the most up-to-date information.
- You want to simplify versioning by managing upgrades only on the client-side.
- You’re building a modern, type-safe application and want to take advantage of SDK typing benefits.

Use snapshot events when:

- You need to audit the specific fields that have changed without making a subsequent API call.
- Your integration requires a point-in-time view of the resource definition and can tolerate working with eventually-consistent data.

This table outlines high-level differences across thin events and snapshot events.

| Characteristics                             | Snapshot events                                                                                                                                  | Thin events                                                                                                                                                                                                                                                                                                                                                 |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Created by                                  | API v1 resource state changes                                                                                                                    | API v2 resource state changes                                                                                                                                                                                                                                                                                                                               |
| Delivered payload                           | **Large**: Includes a snapshot of the API object related to the event                                                                            | **Small**: Includes an ID of the API object related to the event in a lightweight event notification                                                                                                                                                                                                                                                        |
| Accessing additional data to process event. | Fetch the latest object definition from the API. The object definition in the event payload might be outdated by the time you process the event. | Fetch the latest object from the API or retrieve the complete [event](https://docs.stripe.com/api/v2/events.md) from `v2/events`. The complete event payload can include extra details about the event. For example, the payload for a `v1.billing.meter.error_report_triggered` event includes information about the types and frequency of errors raised. |
| SDK typing                                  | Untyped                                                                                                                                          | Typed                                                                                                                                                                                                                                                                                                                                                       |
| Versioning                                  | Versioned by API version                                                                                                                         | Unversioned, allowing you to upgrade your integration without changing your webhook endpoint configuration                                                                                                                                                                                                                                                  |
| API to view events                          | [Events v1 API](https://docs.stripe.com/api/events.md)                                                                                           | [Events v2 API](https://docs.stripe.com/api/v2/events.md)                                                                                                                                                                                                                                                                                                   |

### Example thin event notification payload 

The following is an example of an `v1.billing.meter.error_report_triggered` event. The `data` hash below won’t be accessible in the event notification sent to the destination. The `related_object` field includes the `id` of the object, but doesn’t include the object record itself.

```json
{
  "id": "evt_test_65R9Ijk8dKEYZcXeRWn16R9A7j1FSQ3w3TGDPLLGSM4CW0",
  "object": "v2.core.event",
  "type": "v1.billing.meter.error_report_triggered",
  "livemode": false,
  "created": "2024-09-17T06:20:52.246Z",
  "related_object": {
    "id": "mtr_test_61R9IeP0SgKbYROOx41PEAQhH0qO23oW",
    "type": "billing.meter",
    "url": "/v1/billing/meters/mtr_test_61R9IeP0SgKbYROOx41PEAQhH0qO23oW"
  }
  "data": {
    "developer_message_summary": "There is 1 invalid event",
    "reason": {
      "error_count": 1,
      "error_types": [
        {
          "code": "meter_event_no_customer_defined",
          "error_count": 1,
          "sample_errors": [
            {
              "error_message": "Customer mapping key stripe_customer_id not found in payload.",
              "request": {
                "id": "",
                "idempotency_key": "37c741d8-1f7e-4adc-af16-afdca1d73b37"
              }
            }
          ]
        }
      ]
    },
    "validation_end": "2024-08-28T20:54:10.000Z",
    "validation_start": "2024-08-28T20:54:00.000Z"
  }
}
```

### Example snapshot event payload 

View the following example of an `setup_intent.created` snapshot event, which includes the object definition as it was when the event was raised:

```json
{
  "id": "evt_1NG8Du2eZvKYlo2CUI79vXWy",
  "object": "event",
  "api_version": "2019-02-19",
  "created": 1686089970,
  "data": {
    "object": {
      "id": "seti_1NG8Du2eZvKYlo2C9XMqbR0x",
      "object": "setup_intent",
      "application": null,
      "automatic_payment_methods": null,
      "cancellation_reason": null,
      "client_secret": "seti_1NG8Du2eZvKYlo2C9XMqbR0x_secret_O2CdhLwGFh2Aej7bCY7qp8jlIuyR8DJ",
      "created": 1686089970,
      "customer": null,
      "description": null,
      "flow_directions": null,
      "last_setup_error": null,
      "latest_attempt": null,
      "livemode": false,
      "mandate": null,
      "metadata": {},
      "next_action": null,
      "on_behalf_of": null,
      "payment_method": "pm_1NG8Du2eZvKYlo2CYzzldNr7",
      "payment_method_options": {
        "acss_debit": {
          "currency": "cad",
          "mandate_options": {
            "interval_description": "First day of every month",
            "payment_schedule": "interval",
            "transaction_type": "personal"
          },
          "verification_method": "automatic"
        }
      },
      "payment_method_types": [
        "acss_debit"
      ],
      "single_use_mandate": null,
      "status": "requires_confirmation",
      "usage": "off_session"
    }
  },
  "livemode": false,
  "pending_webhooks": 0,
  "request": {
    "id": null,
    "idempotency_key": null
  },
  "type": "setup_intent.created"
}
```

## Using thin events 

Integrate with thin events by using the event notification sent to your destination to retrieve more details from the API.

### Processing the event notification 

The initial notification contains minimal data. Choose one of three approaches when processing the event notification, depending on what information your integration requires:

1. **Retrieve the complete event**: Use the `fetchEvent()` method to retrieve the complete `Event` object when you need more information than the related object’s latest state provides. The complete event object can include two types of additional data:
   - Contextual information about the event itself, available in the `data` hash. For example, a `v1.billing.meter.error_report_triggered` event includes details about the types and summary of validation errors in this field.
   - The previous values of any attributes that changed on the resource, available in the `changes` hash.

The following table details the additional data available in the complete [event](https://docs.stripe.com/api/v2/events.md) object compared to the initial notification:

| Property name       | Event notification | Event |
| ------------------- | ------------------ | ----- |
| Event type          | ✅                  | ✅     |
| Related resource ID | ✅                  | ✅     |
| Event ID            | ✅                  | ✅     |
| Created timestamp   | ✅                  | ✅     |
| Reason              | ✅                  | ✅     |
| Changes             | ❌                  | ✅     |
| Data                | ❌                  | ✅     |

1. **Retrieve the latest state of the related object**: Use the `fetchRelatedObject()` method to retrieve the latest version of the object associated with the event. For example, if you receive a `v1.billing.meter.error_report_triggered event`, `fetchRelatedObject()` retrieves the meter object that triggered an error report.
1. **Process the notification immediately**: If the event type and resource ID in the notification are sufficient for your use case, you can process it without making an additional API call.

The following example demonstrates how to retrieve the related object definition and additional event payload fields associated when processing a thin event notification:

#### Java

```java
com.stripe.model.EventNotification eventNotification = client.parseEventNotification(payload, signatureHeader, endpointSecret);
com.stripe.model.v2.Event event = client.v2().core().events().retrieve(eventNotification.getId());
if (event instanceof V1BillingMeterErrorReportTriggeredEvent) {
  V1BillingMeterErrorReportTriggeredEvent postedEvent = (V1BillingMeterErrorReportTriggeredEvent) event;
  // On each type of event, the Stripe library provides a "fetchRelatedObject" method
  // that performs a network request to Stripe to fetch the latest version
  // of the object directly associated with the event, in this case, an
  // "Meter" object.
  Meter op = postedEvent.fetchRelatedObject();
}
```

#### Node.js

```js
var eventNotification = client.parseEventNotification(payload, signature_header, endpoint_secret);
const event = await eventNotification.fetchEvent();
if (event.type === "v1.billing.meter.error_report_triggered") {
    // On each type of event, the Stripe library provides a "fetchRelatedObject" method
    // that performs a network request to Stripe to fetch the latest version
    // of the object directly associated with the event, in this case, an
    // "Meter" object.
    var meter = await eventNotification.fetchRelatedObject();
}
```

#### Python

```python
event_notification = client.parse_event_notification(payload, signature_header, endpoint_secret)
event = event_notification.fetch_event()
if isinstance(event, V1BillingMeterErrorReportTriggeredEvent):
    # The Stripe library also provides a "fetch_related_object" method
    # on the notification object that performs a network request to Stripe
    # to fetch the latest version of the related object, in this case, a
    # "Meter" object.
    meter = event_notification.fetch_related_object()
```

#### .NET

```csharp
var eventNotification = client.ParseEventNotification(payload, signatureHeader, endpointSecret);
var event = await eventNotification.FetchEventAsync();
if (event is V1BillingMeterErrorReportTriggeredEvent fullEvent)
{
    // On each type of event, the Stripe library provides a "FetchRelatedObjectAsync" method
    // that performs a network request to Stripe to fetch the latest version
    // of the object directly associated with the event, in this case, an
    // "Meter" object.
    var meter = await eventNotification.FetchRelatedObjectAsync();
}
```

#### Ruby

```ruby
event_notification = client.parse_event_notification(payload, signature_header, endpoint_secret)
event = event_notification.fetch_event
if (event.instance_of? Stripe::V1BillingMeterErrorReportTriggeredEvent)
    # On each type of event, the Stripe library provides a "fetch_related_object" method
    # that performs a network request to Stripe to fetch the latest version
    # of the object directly associated with the event, in this case, an
    # "Meter" object.
    meter = event_notification.fetch_related_object
end
```

#### PHP

```php
$event_notification = $client->parseEventNotification($payload, $signature_header, $endpoint_secret);
$event = $event_notification->fetchEvent();
if ($event instanceof \Stripe\Events\V1BillingMeterErrorReportTriggeredEvent) {
    # On each type of event, the Stripe library provides a "fetchRelatedObject" method
    # that performs a network request to Stripe to fetch the latest version
    # of the object directly associated with the event, in this case, an
    # "Meter" object.
    $meter = $event_notification->fetchRelatedObject();
}
```

#### Go

```go
eventNotification, err := client.ParseEventNotification(payload, signatureHeader, endpointSecret)
if err != nil {
  return fmt.Errorf("parsing event notification: %w", err)
}

event, err := eventNotification.FetchEvent()
if err != nil {
  return fmt.Errorf("fetching event: %w", err)
}

switch event.(type) {
case *stripe.V1BillingMeterErrorReportTriggeredEvent:
  // On each type of event, the Stripe library provides a "fetchRelatedObject" method
  // that performs a network request to Stripe to fetch the latest version
  // of the object directly associated with the event, in this case, an
  // "Meter" object.
  meter, err := eventNotification.FetchRelatedObject()
  if err != nil {
    return fmt.Errorf("fetching related object: %w", err)
  }
}
```

### SDK typing

Thin events and their notifications are fully typed in the SDKs.

- **Event notification**: The initial, lightweight payload delivered to your event destination is typed as `{EventType}EventNotification`.
- **Event**: After you retrieve the complete event from the API using `fetchEvent()`, the resulting object is typed as `{EventType}Event`.

## Event permissions

To view an event in the Dashboard, assign the [Admin or Developer role](https://docs.stripe.com/get-started/account/teams/roles.md) to your user account. To retrieve an event using the API, use either a [secret API key](https://docs.stripe.com/keys.md#create-api-secret-key), which allows you to view all event types by default, or a [restricted API key](https://docs.stripe.com/keys.md#create-restricted-api-secret-key) with `Read` access enabled for the specific event type’s resource. For example, you can grant `Read` access to `payment_intent` resources on your restricted API key to programmatically retrieve `payment_intent.succeeded events`.

## Event retention

In the **Events** tab in Workbench, you can access events within the last 13 months:

- For events less than 15 days old, you can view the full event payload, see the delivery attempts, and manually resend these events.
- For events 16-30 days old, you can access the full event payload, but you can’t resend them or view delivery attempts.
- For events older than 30 days, you can only see a summary view, which includes truncated fields of the original event data. Resending and viewing delivery attempts aren’t available for these events.

Use the [Retrieve event](https://docs.stripe.com/api/v2/events/retrieve.md) and [List events](https://docs.stripe.com/api/v2/events/list.md) APIs to access events with their full payload from the past 30 days.

## Event destination limits

You can register a maximum of 16 event destinations in each livemode or sandbox account. When registering a snapshot event destination with a version different from your merchant’s default version, you can register up to three uniquely versioned snapshot event destinations.

## Manage an event destination

To create, delete, and update an event destination in the Dashboard, open the [Webhooks](https://dashboard.stripe.com/webhooks) tab in Workbench or use the [event destinations API](https://docs.stripe.com/api/v2/event-destinations/.md).

## Disable an event destination

You can disable an event destination. After you disable it, Stripe stops sending any events to that destination. After you re-enable a destination, Stripe resumes sending events to it.