Skip to main content

App Events API reference

The App Events API lets developers send events that happen in their app to Shopify. All events are shown in the Dev Dashboard logs section. Events configured as part of Shopify App Pricing are also processed for billing.

All App Events API requests require a valid bearer token.

API keys created in the Dev Dashboard provide a client ID and secret that can be used to generate a JWT token. Permissions to write to App Events are automatically included — no additional scope configuration is required.

The response will contain:

  • access_token: A JWT access token that can be used to interact with the App Events API.
  • scope: The list of access scopes that were granted to your API key.
  • expires_in: The number of seconds until the access token expires.

Include your token as a Authorization: Bearer {token} header on all API requests. Access tokens expire after 60 minutes. You can use a JWT decoder tool like jwt.io to investigate more details related to how Shopify issues this token. Request a new token before the current one expires.


Anchor to Endpoints and requestsEndpoints and requests

The App Events API lets you send events happening in your app to Shopify. All events are visible in the Dev Dashboard. Events sent to this API as part of Shopify App Pricing are processed for billing to merchants. Each request sends one event at a time — batch requests aren't supported.

All App Events API endpoints follow this pattern: https://api.shopify.com/app/{version}/events.

The App Events API is versioned. To keep your app stable, make sure you specify a supported version in the URL. Learn more about API versioning.

The App Events API provides the following endpoint:

  • Create an event: Send billing events for usage-based pricing meters or custom events for monitoring in the Dev Dashboard.

Learn more about App Events and building a billing event.


Anchor to Shopify Analytics eligibilityShopify Analytics eligibility

Developer preview

App Events in Analytics is in developer preview. The preview is available to approved apps and supports declared standard events. Sign up for early access.

Events sent to the App Events API appear in the Dev Dashboard. Depending on your app configuration, Shopify can also process an event for usage-based billing or make it available in Shopify Analytics.

An event is eligible for Shopify Analytics only when all of the following are true:

  • The app has access to App Events in Analytics.
  • The app has an accepted analytics_app_events declaration.
  • The emitted event_handle matches a declared standard event.
  • The event attributes match the standard registry definition and the App Events API request constraints.
  • The event passes analytics validation and processing.

For standard events, emit the full standard registry handle, including the shopify. prefix, as the event_handle. Use the same handle that you declare in shopify.extension.toml.

shopify.extension.toml declaration (name)API event_handle
shopify.marketing.email_sentshopify.marketing.email_sent
shopify.marketing.sms_sentshopify.marketing.sms_sent
shopify.loyalty.points_earnedshopify.loyalty.points_earned

Standard registry membership alone doesn't make an event queryable in Shopify Analytics. Your app must declare the event in shopify.extension.toml.

The following example shows the request body for a standard analytics event:

{
"shop_id": "gid://shopify/Shop/23423423",
"event_handle": "shopify.marketing.email_sent",
"timestamp": "2026-01-27T14:30:00Z",
"idempotency_key": "email_sent_23423423_55667788",
"attributes": {
"campaign_id": 100472895,
"message_type": "campaign"
}
}

Learn how to use App Events in Analytics.


All events use a single request schema. Every event is logged and visible in the Dev Dashboard. If the event_handle matches a handle configured in a pricing plan as part of Shopify App Pricing, the event is also processed as a usage charge.

Caution

Don't include any data that, alone or in combination with other data, could identify an individual. This includes any merchant or buyer information, such as name, email address, phone number, and other identifiable data points. Use anonymized identifiers and aggregated metrics instead.


shop_id•stringRequired

The ID of the merchant's shop that the event is associated with. For example, gid://shopify/Shop/23423423 or 23423423. Both a Shopify GID and a numeric shop ID (as a string) are accepted.


event_handle•stringRequired

The name of the event. If this matches a meter handle in your pricing configuration, the event is processed as a billing event. Otherwise, it's tracked as a custom event for monitoring. The prefix shopify. is reserved and can't be used.

If the event matches an accepted Analytics App Events declaration, then Shopify can also make the event available in Shopify Analytics. Standard events used in Shopify Analytics are an exception to the reserved shopify. prefix: emit the full standard registry handle, such as shopify.marketing.email_sent, as the event_handle. Use the same handle that you declare in shopify.extension.toml.


timestamp•stringRequired

The ISO 8601 timestamp of when the event occurred (for example, 2026-01-27T14:30:00Z). The timestamp can't be more than 5 minutes in the future. Billing events outside the current cycle currently reject with RESULT_STATUS_FAILURE and a result_details message with details about the allowable window.


idempotency_key•stringRequired

An app-generated unique key to prevent duplicate events. Maximum 64 characters. The API enforces a 24-hour idempotency window — requests with a previously seen key within that window return the original response. For billing events, idempotency is enforced permanently.


attributes•objectRequired

A JSON object containing the event data. For billing events, the value field is required and specifies the quantity to apply to the meter. For details, see Understand the request fields. The attributes object has the following restrictions:

  • Maximum 15 keys in the attributes object
  • Keys are limited to 64 characters and can only contain alphanumeric ASCII characters, underscores (_), periods (.), and hyphens (-)
  • String values are limited to 128 characters (UTF-8)
  • Only scalar values are allowed (strings, numbers, booleans). Arrays and nested objects aren't supported.


All successful requests return a 202 Accepted response with the following JSON body:


success•boolean

Whether the event was received successfully.


error•string

Present when success is false. A short explanation of what went wrong.



Anchor to Example: Report a billing eventExample: Report a billing event

This example shows the full flow of authenticating and sending a billing event.


Anchor to Status and error codesStatus and error codes

All API queries return HTTP status codes that can tell you more about the response.


202 Accepted

The event was received successfully. A 202 response means Shopify received the request — it doesn't confirm that billing validation passed. Billing errors are processed asynchronously and are only visible in the Dev Dashboard under Logs with the App Billing Event type filter. There are no synchronous billing error responses and no webhooks for billing validation failures. Replayed requests (same idempotency_key within the idempotency window) return the original response with an Idempotent-Replay: true header.

A 202 response also doesn't confirm that the event was accepted for Shopify Analytics. Analytics processing occurs asynchronously. An accepted request becomes queryable only if it matches an accepted Analytics App Events declaration and passes analytics validation. If an event appears in the Dev Dashboard but isn't available in Shopify Analytics, then check the app's analytics_app_events declaration and the standard event registry definition.


400 Bad Request

The request parameters are invalid. The response includes { "success": false, "error": "Invalid request" }.


401 Unauthorized

The bearer token is missing or invalid.


403 Forbidden

The app isn't installed on the shop specified by shop_id, or the shop_id value is invalid.


409 Conflict

A request with the same idempotency_key is still being processed. Retry after a short delay.


429 Too Many Requests

Rate limit exceeded. The App Events API has a rate limit of 500 requests per second per app. Wait before retrying.


5xx Errors

An internal error occurred in Shopify. Check out the Shopify status page for more information.



By using the App Events API, you agree to the App Events API Terms of Service. Don't submit personal information such as names, email addresses, or any data that identifies a natural person.

Events used for analytics must not include personal data or data that can identify a natural person. Don't send names, email addresses, phone numbers, customer IDs, addresses, or other directly identifiable values in event attributes. Use non-identifying campaign, workflow, app, or aggregate identifiers instead.


Was this page helpful?