---
title: Webhooks delivery structure
description: >-
  The structure of each delivery: JSON payload, HTTP headers, and how to
  customize what you receive with include_fields.
source_url:
  html: 'https://shopify.dev/docs/apps/build/webhooks/delivery-structure'
  md: 'https://shopify.dev/docs/apps/build/webhooks/delivery-structure.md'
---

# Webhooks delivery structure

Each qualifying change sends a delivery to your `uri` as an HTTP POST with a JSON body and a set of headers. By default, the body is the full REST resource payload for the topic.

Add `include_fields` to receive only the specific fields your app needs.

![Modify payloads](https://shopify.dev/assets/assets/images/apps/webhooks/customize/modify_payloads-ByCGW8QH.png)

***

## Payload

Every delivery includes a JSON body containing the full REST resource for the subscribed topic. The shape and fields depend on the topic. See the [Webhooks reference](https://shopify.dev/docs/api/webhooks) for the payload structure of each topic.

## Example payload (products/update)

```json
{
  "id": 9554194432293,
  "title": "T-Shirt",
  "status": "active",
  "vendor": "My Store",
  "product_type": "Shirts",
  "updated_at": "2025-04-22T14:30:00-05:00",
  "variants": [
    {
      "id": 123456789,
      "title": "Default Title",
      "price": "29.99",
      "sku": "TSHIRT-001",
      "taxable": true,
      "updated_at": "2025-04-22T14:30:00-05:00"
    }
  ],
  "tags": "cotton, comfortable"
}
```

***

## Headers

Every delivery includes the following headers. Treat header names as case-insensitive in your code, as HTTP/2 often lowercases them.

| Header | Description |
| - | - |
| `X-Shopify-Topic` | The topic name (for example, `products/update`). |
| `X-Shopify-Hmac-Sha256` | Base64-encoded HMAC signature for verifying the delivery came from Shopify. HTTPS only. |
| `X-Shopify-Shop-Domain` | The `myshopify.com` domain of the store that triggered the event. |
| `X-Shopify-API-Version` | The API version used to serialize the payload. |
| `X-Shopify-Webhook-Id` | A unique composite key per delivery. Use to identify and deduplicate individual deliveries. |
| `X-Shopify-Triggered-At` | Timestamp of when Shopify triggered the delivery. |
| `X-Shopify-Event-Id` | A unique ID shared across all deliveries produced by the same merchant action. |
| `X-Shopify-Name` (optional) | Developer-supplied subscription name, set via the `name` field in your subscription. |

***

## `include_fields`

`include_fields` is an optional array of field paths on a webhook subscription. When set, the delivery payload includes only the specified fields instead of the full resource.

Without `include_fields`, every delivery includes the complete resource payload:

## Without include\_fields

##### shopify.app.toml

```toml
[webhooks]
api_version = "2026-04"

[[webhooks.subscriptions]]
topics = ["products/update"]
uri = "https://your-app.example.com/webhooks/products"
```

##### {} Response

```json
{
  "id": 9554194432293,
  "title": "T-Shirt",
  "status": "active",
  "vendor": "My Store",
  "product_type": "Shirts",
  "updated_at": "2025-04-22T14:30:00-05:00",
  "variants": [
    {
      "id": 123456789,
      "title": "Default Title",
      "price": "29.99",
      "sku": "TSHIRT-001",
      "taxable": true,
      "updated_at": "2025-04-22T14:30:00-05:00"
    }
  ],
  "tags": "cotton, comfortable"
}
```

Adding `include_fields` narrows the payload to only the specified fields. You denote nested fields using a period (for example, `variants.price`). You can also set `include_fields` using the `includeFields` input in the [`webhookSubscriptionCreate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/webhookSubscriptionCreate) mutation.

## With include\_fields

##### shopify.app.toml

```toml
[webhooks]
api_version = "2026-04"

[[webhooks.subscriptions]]
topics = ["products/update"]
uri = "https://your-app.example.com/webhooks/products"
include_fields = ["id", "variants.id", "variants.price", "updated_at"]
```

##### {} Response

```json
{
  "id": 9554194432293,
  "variants": [
    {
      "id": 123456789,
      "price": "29.99"
    }
  ],
  "updated_at": "2025-04-22T14:30:00-05:00"
}
```

### Debouncing

When `include_fields` reduces the payload to a small set of fields, multiple qualifying events might produce identical payloads. Shopify debounces deliveries with identical payloads that arrive within a short time window, dropping the later one. For example, a subscription to `orders/updated` with `include_fields = ["id", "line_items.title"]` would debounce consecutive price changes, since neither the order ID nor line item titles change between them.

To prevent debouncing, include a field that always has a unique value. For example, `updated_at` changes with every update, ensuring no two consecutive deliveries are identical.

### Combining with `filter`

When both `filter` and `include_fields` are set, all fields referenced in the `filter` expression must also appear in `include_fields`.

## shopify.app.toml

```toml
[webhooks]
api_version = "2026-04"


[[webhooks.subscriptions]]
topics = ["products/update"]
uri = "https://example.com/webhooks"
include_fields = ["id", "status", "product_type", "variants.taxable", "variants.price", "variants.title", "updated_at"]
filter = "id:* AND status:active AND (product_type:Music OR product_type:Movies) AND variants.taxable:true AND variants.price:>=100 AND variants.title:'The Miseducation of'"
```

See [Delivery filtering](https://shopify.dev/docs/apps/build/webhooks/delivery-filtering) for filter syntax and examples.

***

## Example

Suppose you want deliveries only when an active product in the Music or Movies category has a variant priced above $100. The following subscription combines `include_fields` to narrow the payload and `filter` to gate delivery:

## Active high-price music or movies product

##### shopify.app.toml

```toml
[webhooks]
api_version = "2026-04"

[[webhooks.subscriptions]]
topics = ["products/update"]
uri = "https://your-app.example.com/webhooks/products"
include_fields = ["id", "status", "product_type", "variants.id", "variants.price", "updated_at"]
filter = "status:active AND (product_type:Music OR product_type:Movies) AND variants.price:>=100"
```

##### {} Response

```json
{
  "id": 9554194432293,
  "status": "active",
  "product_type": "Music",
  "variants": [
    {
      "id": 123456789,
      "price": "129.99"
    }
  ],
  "updated_at": "2025-04-22T15:00:00-05:00"
}
```

***

## Next steps

* [Delivery filtering](https://shopify.dev/docs/apps/build/webhooks/delivery-filtering): Gate deliveries with `filter` expressions.
* [Verify deliveries](https://shopify.dev/docs/apps/build/webhooks/verify-deliveries): HMAC verification and deduplication.

***
