Skip to content
Create account or Sign in
The Stripe Docs logo
Search/Ask AI
Create accountSign in
  • Get started
  • Payments
  • Revenue
  • Risk
  • Data
  • Money management
  • Stablecoins
  • Embedded finance
  • Developer resources
More
APIs & SDKsHelp
Overview
Versioning
Changelog
Upgrade your integrationHow API versioning works
Essentials
SDKs
API
Events
    How events work
    Set up events
    Send events directly to your application
    Migrate to thin events
Testing
Stripe CLI
Tools
Stripe Dashboard
Stripe Projects
Provisioning
Workbench
Developers Dashboard
Stripe for Visual Studio Code
Terraform
Stripe Discord server
Features
Workflows
Batch jobs
Stripe health alertsFile uploads
AI tools
Agent pluginsModel Context ProtocolAgent skillsStripe Directory
Extend Stripe
Overview
Build Stripe apps
Use apps from Stripe
Build extensions
Custom objects
Security and privacy
Security
Activity logsStripebot web crawler
Privacy
Partners
Partner ecosystem
Partner certification
United States
English (United States)
  1. Home/
  2. Developer resources/
  3. Events

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:

  • Webhook endpoints
  • Amazon EventBridge
  • Azure Event Grid

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.subscription.created event and a payment_intent.succeeded 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:

  • Webhook endpoints
  • Amazon EventBridge
  • Azure Event Grid

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 Event object, 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 Event object payload.
  • You need to audit the specific fields that changed without making a subsequent API call. Thin events include changed fields in the changes hash on the complete event, while snapshot events carry previous_attributes directly in the payload.
  • 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.

CharacteristicsSnapshot eventsThin events
Created byAPI v1 and API v2 resource state changesAPI v1 and API v2 resource state changes. See the thin event catalog for the full list of supported types.
Delivered payloadLarge: Includes a snapshot of the API object related to the eventSmall: Includes an ID of the API object related to the event in a lightweight event notification
Accessing additional dataFetch 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.billing.meter.error_report_triggered event includes information about the types and frequency of errors raised.
SDK typingUntypedTyped
VersioningVersioned by API versionUnversioned, allowing you to upgrade your integration without changing your event destination configuration
API to view eventsEvents v1 APIEvents 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.core.account.updated. See the full list of thin events
  • the event ID (id), which you use to retrieve the complete Event object.
  • a timestamp (created), which records when the event occurred.
  • the ID of the related resource (related_object), alongside that resource’s type and API URL.

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.core.account.updated 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_object 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 data hash. For example, a v1.billing.meter.error_report_triggered event includes details about validation error types and summaries.
    • The previous values of any attributes that changed on the resource in the changes hash.
  • 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 nameEvent notificationEvent
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:

Java
Node.js
Python
.NET
Ruby
PHP
Go
No results
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:

Java
Node.js
Python
.NET
Ruby
PHP
Go
No results
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_attributes 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_intent.created 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.acacia 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_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:

  • 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_events list omits event types your integration needs, add those types and retrieve available historical events. Updating enabled_events 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.

  1. Update enabled_events in the Dashboard or with the event destinations API to include the missing event types.

  2. 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 type parameter to filter by event type.
    • Thin events: Use List events (v2) with the types array parameter to filter by event type, then retrieve the complete event.

    Process the returned Event objects in your integration. If you need the latest resource state, retrieve the related resource separately.

  3. 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.created (if there’s a charge)

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.paid 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-Signature header. 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.

Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Chat with Stripe developers on Discord.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc
On this page
Advertisement
Advertisement