How events work
Learn how Stripe generates events and how they're delivered to your integration.
When a state change occurs in your Stripe account, Stripe generates an event and can push it to one or more configured destinations. Your application receives the event, identifies the type, and takes the appropriate action.
This page describes how events are structured and delivered. For destination-specific setup instructions, see:
Event generation
Every state change in Stripe that your integration might need to respond to produces an Event object. A single action against a Stripe resource can result in multiple events. For example, creating a new subscription can produce both a customer. event and a payment_ event under certain conditions.
Events are delivered asynchronously to your configured event destinations. You can configure each destination to receive a specific set of event types. The format and delivery of each event depend on your destination configuration.
Event destinations
Stripe pushes events to your configured destinations, which can be webhook endpoints, Amazon EventBridge, or Azure Event Grid. Your application receives these events so it can 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
Each destination receives events in one of two formats: thin or snapshot. You choose the format when you create the destination.
Manage event destinations
To create, update, delete, or disable an event destination in the Dashboard, open the Webhooks tab in Workbench or use the event destinations API. After you disable an event destination, Stripe stops sending any events to that destination. After you re-enable a destination, Stripe resumes sending events to it.
For detailed, destination-specific setup instructions, see:
Event destination limits
You can register a maximum of 16 event destinations per livemode or sandbox account. When registering a snapshot event destination with a version different from your account’s default API version, you can register up to three uniquely versioned snapshot event destinations.
Event formats
Stripe delivers events in two formats:
- Thin events: Stripe sends a lightweight notification containing the event type and resource ID. Your code can then optionally fetch the complete event or the latest state of the related resource from the API.
- Snapshot events: Stripe sends a payload containing the complete
Eventobject, including a point-in-time snapshot of the related resource. Your code can optionally fetch the latest state of the related resource from the API.
Comparison
For new integrations, use thin events. Thin events are unversioned, fully typed in the Stripe SDKs, and let your integration fetch the latest resource state. The notification itself carries identifiers and event metadata, not the resource state, so your code retrieves the current resource from the API.
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:
- A third-party tool or integration requires receiving the complete
Eventobject payload. - You need to audit the specific fields that changed without making a subsequent API call. Thin events include changed fields in the
changeshash on the complete event, while snapshot events carryprevious_directly in the payload.attributes - Your integration requires a point-in-time view of the resource definition and can tolerate working with eventually-consistent data.
The following table outlines the key differences between the two formats.
| Characteristics | Snapshot events | Thin events |
|---|---|---|
| Created by | API v1 and API v2 resource state changes | API v1 and API v2 resource state changes. See the thin event catalog for the full list of supported types. |
| 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 | Fetch the latest object from the API. The object 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 from v2/events. The complete event payload can include extra details. For example, the payload for a v1. 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 event destination configuration |
| API to view events | Events v1 API | Events v2 API |
If you use Accounts v2, you might listen to both snapshot and thin events.
Thin events
A thin event sends a lightweight notification containing only identifying information:
- the event type (
type), which describes what happened. For example,v2.. See the full list of thin eventscore. account. updated - the event ID (
id), which you use to retrieve the completeEventobject. - a timestamp (
created), which records when the event occurred. - the ID of the related resource (
related_), alongside that resource’s type and API URL.object
To access the full resource state or additional event data, your code needs to make a subsequent API call using this information. For the complete set of properties, see the Event object.
Both API v1 and API v2 resources generate thin events. Because thin event notification payloads are unversioned, you can upgrade your Stripe SDK or your integration’s API version without changing your event destination configuration. Events and resources that you fetch from the API still follow standard API versioning behavior. Notifications are also fully typed in the SDKs, so your code gets compile-time type safety when it processes events. These properties make thin events the recommended format for new integrations.
Notification payload structure
The following example shows a v2. thin event notification. The id property contains the ID of the associated Event object. The reason hash describes what triggered the event, and the related_ hash identifies the associated resource.
{ "id": "evt_test_65UIRNU7G1XbhCfOim416TgmEI4ASQ3jHxXt8RFwXoeVwO", "object": "v2.core.event", "type": "v2.core.account.updated", "livemode": false, "created": "2026-03-09T13:00:28.435Z", "context": null, "reason": { "type": "request", "request": { "id": "req_v2y9y15XqG3Futmjg", "idempotency_key": "ik_TgmEI3jHxXt8RFw4jS7ve2QcAReDQWBjPAkAEUm" } }, "related_object": { "id": "acct_1T93Q4Pmpb34Vto6", "type": "v2.core.account", "url": "/v2/core/accounts/acct_1T93Q4Pmpb34Vto6" } }
Processing thin event notifications
The initial notification contains minimal data. Depending on your use case, you can get more information about the event or object or act on the notification immediately:
Retrieve the complete event: Use the SDK or API to retrieve the event object. The complete object includes two types of additional data:
- Contextual information about the event in the
datahash. For example, av1.event includes details about validation error types and summaries.billing. meter. error_ report_ triggered - The previous values of any attributes that changed on the resource in the
changeshash.
- Contextual information about the event in the
Retrieve the latest state of the related object: Use the related_object.url to get the latest version of the resource associated with the event through the SDK or API.
Process the notification immediately: If the event type and resource ID in the notification provide enough information for your use case, you can process it without making an additional API call.
The following table shows which properties are available in the event notification versus the complete event object:
| Property name | Event notification | Event |
|---|---|---|
| Event type | ||
| Related resource ID | ||
| Event ID | ||
| Created timestamp | ||
| Reason | ||
| Changes | ||
| Data |
The following example shows how to retrieve the latest state of the related object directly from the event notification, without making an additional API call to fetch the event:
com.stripe.model.v2.core.EventNotification eventNotification = client.parseEventNotification(payload, signatureHeader, endpointSecret); if (eventNotification instanceof V1BillingMeterErrorReportTriggeredEventNotification) { V1BillingMeterErrorReportTriggeredEventNotification notif = (V1BillingMeterErrorReportTriggeredEventNotification) eventNotification; // fetchRelatedObject() makes one network request to fetch the latest version // of the object associated with this event (a Meter, in this case). // No API call to retrieve the full Event is needed. Meter meter = notif.fetchRelatedObject(); }
The following example shows how to fetch the complete Event object when your integration requires additional data, such as the data hash with contextual information or the changes hash with previous attribute values:
com.stripe.model.v2.core.EventNotification eventNotification = client.parseEventNotification(payload, signatureHeader, endpointSecret); if (eventNotification instanceof V1BillingMeterErrorReportTriggeredEventNotification) { V1BillingMeterErrorReportTriggeredEventNotification notif = (V1BillingMeterErrorReportTriggeredEventNotification) eventNotification; // Use fetchEvent() when you need additional data in the Event object, // such as the "data" hash with contextual info or the "changes" hash // with previous attribute values. com.stripe.model.v2.core.Event event = notif.fetchEvent(); if (event instanceof V1BillingMeterErrorReportTriggeredEvent) { V1BillingMeterErrorReportTriggeredEvent typedEvent = (V1BillingMeterErrorReportTriggeredEvent) event; String summary = typedEvent.getData().getDeveloperMessageSummary(); } }
SDK typing
Thin events and their notifications are fully typed in the Stripe SDKs:
- Event notification: The initial lightweight payload is typed as
{EventType}EventNotification. - Event: After you retrieve the complete event using
fetchEvent(), the object is typed as{EventType}Event.
Snapshot events
A snapshot event delivers a payload containing the complete Event object, including an eventually-consistent snapshot of the updated resource at the time the event was generated. Because this snapshot can be stale by the time your application processes it, fetch the latest version of the resource from the API before acting on the data.
Snapshot events are versioned by API version. The API version of a snapshot destination is fixed when the destination is created, and the payload structure is tied to that version. This requires you to manage version compatibility between your destination configuration and your integration code. For details on upgrading, see Upgrade a snapshot event destination or the API versioning guide.
Snapshot events are generated by both API v1 and API v2 resources. They include a previous_ property that indicates which fields changed, when applicable. See the full list of snapshot events.
Use snapshot events when thin events aren’t the right fit for your use case. Read more about choosing a format.
Payload structure
The following example shows a setup_ snapshot event, which includes the complete object definition as it was when the event was generated:
{ "id": "evt_1NG8Du2eZvKYlo2CUI79vXWy", "object": "event", "api_version": "2019-02-19", "created": 1686089970,
Snapshot event versioning
Snapshot event destinations have an API version set explicitly, or they use the default API version of the Stripe account. If you use a statically typed language SDK (.NET, Java, or Go) to process events, the API version configured on the destination must match the version used to generate the SDK. Mismatched versions cause deserialization failures.
Every API version before 2024-09-30.acacia has breaking changes. Starting with the 2024-09-30. release, Stripe follows a new API release process where monthly API versions within the same release contain no breaking changes. You can upgrade your event destination to any version within the same release without modifying your integration code. Twice a year, Stripe issues a new named release that begins with a breaking-change version.
Thin events are not subject to these constraints. Because thin event notification payloads are stable, you can upgrade your SDK or API version without updating your event destination configuration.
Upgrade an event destination to a new API version
Use the API upgrade guide to update your event destinations and webhook endpoints.
Event permissions
To view an event in the Dashboard, assign the Administrator or Developer role to your user account. To retrieve an event using the API, use either a secret API key, which allows you to view all event types by default, or a restricted API key with Read access enabled for the specific event type’s resource. For example, you can grant Read access to payment_ resources on your restricted API key to programmatically retrieve payment_.
Event retention
In the Events tab in Workbench, you can access events within the last 13 months:
- Events less than 15 days old: you can view the full event payload, see delivery attempts, and manually resend these events.
- Events 16 to 30 days old: you can access the full event payload, but you can’t resend them or view delivery attempts.
- Events older than 30 days: you can only see a summary view with truncated fields. Resending and viewing delivery attempts aren’t available.
Use the Retrieve event and List events APIs to access events with their full payload from the past 30 days.
Recover from missing event types
If your destination’s enabled_ list omits event types your integration needs, add those types and retrieve available historical events. Updating enabled_ affects future delivery only. Stripe doesn’t automatically deliver earlier events.
Before retrieving events, check the event permissions and query the account context that produced them. For connected accounts, use the Stripe-Account header. For organization accounts or other account relationships, use the Stripe-Context header. If your destination receives events from multiple accounts, query each affected account context separately.
Update
enabled_in the Dashboard or with the event destinations API to include the missing event types.events Retrieve and process historical events. Events that weren’t delivered to your destination might still be available through the Events API for 30 days. Use the API that matches your event format:
- Snapshot events: Use List events (v1) with the
typeparameter to filter by event type. - Thin events: Use List events (v2) with the
typesarray parameter to filter by event type, then retrieve the complete event.
Process the returned
Eventobjects in your integration. If you need the latest resource state, retrieve the related resource separately.- Snapshot events: Use List events (v1) with the
Inspect older events in Events in Workbench. Events older than 30 days have summaries with truncated fields, and you can’t retrieve their full payloads or resend them. Summaries are available for up to 13 months. See Event retention for details.
Amazon EventBridge recovery constraints
For Amazon EventBridge destinations, you can’t manually resend events through Stripe. Follow the recovery steps in this section to retrieve available events from the past 30 days and process them directly in your application.
An EventBridge archive can’t recover events that Stripe never delivered to your event bus. For guidance on archiving events that the bus receives, see EventBridge delivery behaviors.
Event delivery behaviors
This section describes how Stripe delivers events to your configured destinations.
Automatic retries
Stripe attempts to deliver events to your destination for up to three days with an exponential back off in live mode. View when the next retry will occur, if applicable, in your event destination’s Event deliveries tab. We retry event deliveries created in a sandbox three times over the course of a few hours. If your destination has been disabled or deleted when we attempt a retry, we prevent future retries of that event. However, if you disable and then re-enable the event destination before we’re able to retry, you still see future retry attempts.
Manual retries
You can manually retry events in the Stripe Dashboard by clicking Resend when looking at a specific event. This works for up to 15 days after the event creation.
Event ordering
Stripe doesn’t guarantee the delivery of events in the order that they’re generated. For example, creating a subscription might generate the following events:
customer.subscription. created invoice.created invoice.paid charge.(if there’s a charge)created
Make sure that your event destination isn’t dependent on receiving events in a specific order. Snapshot events record created in seconds, so distinct events can share a timestamp. Don’t use created to determine event order or whether you’ve already processed an event. Track event IDs to identify duplicate deliveries instead. You can also use the API to retrieve any missing objects. For example, you can retrieve the invoice, charge, and subscription objects with the information from invoice. if you receive this event first.
API versioning
The API version in your account settings when the event occurs dictates the API version, and therefore the structure of an Event sent to your destination. For example, if your account is set to an older API version, such as 2015-02-16, and you change the API version for a specific request with versioning, the Event object generated and sent to your destination is still based on the 2015-02-16 API version. You can’t change Event objects after creation. For example, if you update a charge, the original charge event remains unchanged. As a result, subsequent updates to your account’s API version don’t retroactively alter existing Event objects. Retrieving an older Event by calling /v1/events using a newer API version also has no impact on the structure of the received event. You can set test event destinations to either your default API version or the latest API version. The Event sent to the destination is structured for the event destination’s specified version.
Verify webhook authenticity
Always verify that webhook events originate from Stripe before acting on them. Use both of these protections:
- Signature verification: Stripe signs every webhook event by including a signature in the
Stripe-Signatureheader. Verify this signature using the official libraries to confirm the event wasn’t sent or modified by a third party. - IP allowlisting: Stripe sends webhook events from a set list of IP addresses. Configure your server or firewall to only accept webhook requests from these addresses.
For complete setup instructions, see Set up events.