---
title: "Revalidate"
description: Push content updates to the storefront when products, categories, or collections change in Enad.
---

## Overview

Revalidate notifies connected frontends when catalog content changes. Enad tracks which products, categories, and collections are out of date for each registered endpoint, then sends a JSON payload to the registered URL so cached pages can be refreshed, static paths rebuilt, or a CDN invalidated.

Typical use cases:

- On-demand ISR or static regeneration in Next.js, Nuxt, or similar frameworks
- Purging or warming CDN cache entries for product and category URLs
- Keeping headless storefronts in sync without polling Enad

## How it works

```mermaid
sequenceDiagram
    participant Enad as Enad (catalog events)
    participant Scheduler as Scheduler
    participant Endpoint as Registered revalidate URL

    Enad->>Enad: Content changes (product, category, collection)
    Enad->>Enad: Mark content as need_sync for all app endpoints
    Scheduler->>Enad: Poll endpoints due for sync (every interval)
    Scheduler->>Enad: Load dirty content IDs and build payloads
    Scheduler->>Endpoint: POST one JSON body per content item
    Endpoint-->>Scheduler: 2xx response
    Scheduler->>Enad: Mark item synced (need_sync = false)
```

1. **Registration**: One or more revalidate endpoints are configured for the app (URL, optional auth header, optional channel, sync interval).
2. **Change detection**: When a product, category, or collection is created or updated in Enad, it is marked as needing sync for every endpoint on that app. Channel-specific product content changes also mark the parent product.
3. **Scheduling**: A background scheduler runs every second. Endpoints whose `next_sync_at` has passed are picked up and their next run is rescheduled by `interval_minutes`.
4. **Delivery**: For each dirty item, Enad sends a separate `POST` request to the registered URL with a typed JSON body. Items are sent concurrently.
5. **Acknowledgement**: A successful response (`2xx`) clears `need_sync` for that item and records `last_sync_at`. Failed items stay dirty and are retried on the next sync cycle for that endpoint.

Content can also be marked for revalidation manually via the Management API, and sync status is available per endpoint.

## Register an endpoint

Register revalidate endpoints in Enad Admin under **System** → **Storefront revalidate**. See [Storefront revalidate in Admin](/storefront/revalidate/admin) for the full UI walkthrough.

Each endpoint needs:

- **URL**: HTTPS endpoint that accepts `POST` requests with a JSON body.
- **Authentication** (optional): Custom header name and value sent on every request.
- **Channel** (optional): When set, product payloads use channel-specific name, slug, and translations instead of the base product fields.
- **Interval**: How often Enad attempts to deliver pending updates for this endpoint (default: 15 minutes).

Each app can have multiple endpoints (for example, one per storefront or environment).

## HTTP request

Enad calls the registered endpoint with the following contract.

| Property | Value |
|----------|-------|
| Method | `POST` |
| Content-Type | `application/json` |
| Body | One content object per request (see [Payload](/storefront/revalidate/payload)) |
| Success | Any `2xx` status code |
| Failure | Any non-`2xx` status code. The item remains pending and will be retried |

### Timeouts

| Phase | Limit |
|-------|-------|
| Connect | 5 seconds |
| Total request | 30 seconds |

Redirects are not followed.

### Authentication

When authentication is enabled on an endpoint, Enad adds a single custom header to every request. The header name and value are configured on the integration (for example `Authorization: Bearer <token>` or `x-api-key: <secret>`).

The handler should validate this header before processing the payload.

### URL requirements

For security, Enad only delivers to public HTTPS URLs. The following are rejected:

- Non-HTTPS schemes (`http://`, etc.)
- Credentials in the URL (`https://user:pass@example.com/...`)
- `localhost` and hostnames ending in `.localhost`, `.local`, or `.internal`
- Private, loopback, link-local, and carrier-grade NAT IP addresses (including when resolved from a hostname)

Production requires a publicly reachable HTTPS URL. Local development requires a tunnel (for example ngrok or Cloudflare Tunnel).

