--- title: Integrate with events subtitle: Send events from Stripe to webhook endpoints and cloud services. route: /event-destinations --- # Integrate with events Send events from Stripe to webhook endpoints and cloud services. 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). Additionally, you can use thin events created by [API v2](https://docs.stripe.com/api-v2-overview.md) endpoints. The SDKs for API v2 includes helpers that allow your application to fetch the latest object state from Stripe. ## 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 Stripe generates event data to keep you informed about the activity in your account. When an event occurs, Stripe generates a new `Event` object. After your destination receives the `Event`, your app can run backend actions (for example, calling your shipping provider’s APIs to schedule a shipment after you receive a `payment_intent.succeeded` event). We provide two different types of `Event` objects: * [Thin events](https://docs.stripe.com/api/v2/events.md): These events only include the ID of the affected objects. These are generated by API v2 endpoints. API v1 endpoints also generate thin events. 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): These events provide an eventually-consistent snapshot of the object that has changed and are only generated by API v1 endpoints. They might include a `previous_attributes` property that indicates the change when applicable. See a [full list of snapshot events](https://docs.stripe.com/api/events/types.md). 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 | | Payload | **Large**: Includes a snapshot of the API object related to the event | **Small**: Only includes an ID of the API object related to the event | | Access 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 full [event](https://docs.stripe.com/api/v2/events.md) from `v2/events`. The full event payload may 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 | A single API request might 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. Select the events you want to subscribe to for each event destination. ## Thin events Thin events are lightweight events you can access through the [API v2](https://docs.stripe.com/api-v2-overview.md) namespace. Thin events have a more granular permissions model and their payloads contain no API-versioned data, only the IDs of the objects related to the event. This helps update integrations that receive events and are built with a well-typed Stripe SDK. Thin Events: - Include a `data` property that can include additional information about the event. - Are fully typed in the SDKs for API v2. You can retrieve [Event](https://docs.stripe.com/api/v2/events.md) objects for each notification from the `/v2/core/events` endpoint. These API objects include the `data` property that can provide additional details about the thin event. ### Prevent application errors If your application needs a corresponding API object related to an event (for example, the [Meter](https://docs.stripe.com/api/billing/meter/retrieve.md)), you must call the Stripe API for the object’s latest state. Although this method requires an additional network call to Stripe, it helps prevent application errors caused by outdated object data (for example, race conditions). The SDKs for API v2 contain helper methods that allow you to retrieve records associated with an event. ### Example thin event payload The following is an example of an `v1.billing.meter.error_report_triggered` event. 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" } } ``` ### 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" } ``` ## Retrieve additional information associated with a thin event There are two types of information you can retreive related to a thin event: - **Related object resource definition**: Each thin event details a specific occurrence related to a Stripe 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 current version of the meter object that triggered an error report. - **Additional event payload fields**: Thin events might contain additional contextual data that’s only retrievable with the API. Use the `retrieve()` call with the thin event ID to retrieve these additional payload fields. For example, fetching a `v1.billing.meter.error_report_triggered` event with the API return an additional `data` hash. This hash includes contextual fields about the errors triggered, such as the time the validation error occurred, a list of sample error messages, and the number of validation errors. The following example demonstrates how to retrieve the related object definition and additional event payload fields associated with a thin event: ```java com.stripe.model.ThinEvent thinEvent = client.parseThinEvent(payload, signatureHeader, endpointSecret); com.stripe.model.v2.Event event = client.v2().core().events().retrieve(thinEvent.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 var thinEvent = client.parseThinEvent(payload, signature_header, endpoint_secret); const event = await client.v2.core.events.retrieve(thinEvent.id); 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 event.fetchRelatedObject(); } ``` ```python thin_event = client.parse_thin_event(payload, signature_header, endpoint_secret) event = client.v2.core.events.retrieve(thin_event.id) if isinstance(event, 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.fetch_related_object() ``` ```dotnet var thinEvent = client.ParseThinEvent(payload, signatureHeader, endpointSecret); var event = await client.V2.Core.Events.GetAsync(thinEvent.Id); 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 fullEvent.FetchRelatedObjectAsync(); } ``` ```ruby thin_event = client.parse_thin_event(payload, signature_header, endpoint_secret) event = client.v2.core.events.retrieve(thin_event.id) 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.fetch_related_object end ``` ```php $thin_event = $client->parseThinEvent($payload, $signature_header, $endpoint_secret); $event = $client->v2->core->events->retrieve($thin_event->id); 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->fetchRelatedObject(); } ``` ```go err = webhook.ValidatePayload(payload, signatureHeader, endpointSecret) if err != nil { fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) return } var thinEvent map[string]interface{} if err := json.Unmarshal(payload, &thinEvent); err != nil { fmt.Fprintf(os.Stderr, "Failed to parse thin event body json: %v\n", err.Error()) return } eventID := thinEvent["id"].(string) var event map[string]interface{} resp, err := client.RawRequest(http.MethodGet, "/v2/core/events/"+eventID, "", nil) if err != nil { fmt.Fprintf(os.Stderr, "Failed to get pull event: %v\n", err.Error()) return } if err := json.Unmarshal(resp.RawJSON, &event); err != nil { fmt.Fprintf(os.Stderr, "Failed to parse pull event body json: %v\n", err.Error()) return } switch t := event["type"].(string); t { case "v1.billing.meter.error_report_triggered": // Based on the docs, we know that the related object for this event is the // BillingMeter object. Use the corresponding API to fetch the related object. relatedObject := event["related_object"].(map[string]interface{}) meter, err := billingMeters.Get(relatedObject["id"].(string), nil) if err != nil { fmt.Fprintf(os.Stderr, "Failed to get related meter object: %v\n", err.Error()) return } meterID := meter.ID fmt.Printf("Success! %s\n", meterID) // Access the contextual event data for the v1.billing.meter.error_report_triggered // event. eventData := event["data"] default: fmt.Fprintf(os.Stderr, "Unhandled event type: %s\n", t) } ``` ## 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-enabled a destination, Stripe resumes sending events to the destination.