# Cache and revalidation

> Edge caching of the Storefront API and the storefront.updated webhook for on-demand revalidation.

Source: https://shopfa.st/docs/headless/revalidation

Cache catalog pages as long as you like and refresh them the moment something changes: ShopFast tells you what
changed.

## The storefront.updated webhook

Whenever buyers would see something new (a product edited, a sale that moved stock, a review, a collection or a page,
the store's settings), ShopFast sends `storefront.updated` with the same tags it uses for its own edge cache:

```json
{
  "id": "msg_…",
  "type": "storefront.updated",
  "createdAt": "2026-10-28T12:00:00.000Z",
  "storeId": "st_…",
  "data": {
    "scope": "items",
    "store": { "id": "st_…", "handle": "your-store" },
    "tags": ["p:prd_8x…", "c:st_…:staff-picks"],
    "productIds": ["prd_8x…"],
    "products": [{ "id": "prd_8x…", "handle": "nimbus-vpn" }],
    "collectionHandles": ["staff-picks"],
    "pageHandles": []
  }
}
```

`scope: "store"` means something store-wide changed (settings, the theme, many products): refresh everything. Changes
close together arrive as one event. `products` carries each product's handle (`null` once it was deleted), so a site
with pages by handle can refresh `/products/nimbus-vpn` without a lookup.

Add an endpoint in **Settings → Developers → Webhooks** with the event `storefront.updated`. It is signed with
[Standard Webhooks](https://shopfa.st/docs/guides/webhooks), like every other event.

## Next.js

```ts
// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { handleRevalidationWebhook } from '@shopfast-sdk/client/next';

export async function POST(request: Request) {
  return handleRevalidationWebhook(request, { secret: process.env.SHOPFAST_WEBHOOK_SECRET!, revalidateTag });
}
```

The SDK's Next.js mode tags every fetch with your shop, so one event refreshes exactly the pages that read it.

## Your own cache or CDN

Storefront API answers carry `Cache-Tag` with the same tags. If your CDN purges by tag, purge the event's `tags`. If
not, use `ETag` and `If-None-Match` to revalidate for free: an unchanged answer is a `304` with no body.

## Live data stays live

Never cache `GET /products/{handle}/availability`, carts, accounts or orders: ShopFast answers them `private, no-store`.
For a buy button, render the product from cache and fetch availability in the browser.
