> ## Documentation Index
> Fetch the complete documentation index at: https://guides.affiliate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Product watch notification history and webhooks

> Retrieve the notification history for your product watches and understand the webhook payload formats for price changes, unavailability, and expiration.

The Product Watch API provides two endpoints for retrieving notification history, plus details on the webhook payloads your server receives when rules trigger. Use the history endpoints to audit past notifications or replay missed events.

## History endpoints

### Get history for a specific watch

Retrieve all notifications sent for a single watch by its ID.

```
GET /v1/products/watches/{watch_id}/histories
```

<ParamField path="watch_id" type="string" required>
  The unique identifier of the watch.
</ParamField>

<ParamField header="Authorization" type="string" required>
  Bearer token for authentication. Format: `Bearer {your_api_key}`.
</ParamField>

```bash theme={null}
curl --request GET \
  --url 'https://api.affiliate.com/v1/products/watches/9e838778-c642-4461-b8d8-bcab87889a91/histories' \
  --header 'Authorization: Bearer {your_api_key}'
```

**Response**

```json theme={null}
{
  "watch_id": "9e838778-c642-4461-b8d8-bcab87889a91",
  "name": "Nike Shoe Price Drop Watch",
  "target_id": "8099982740095203709",
  "histories": [
    {
      "watch_id": "9e838778-c642-4461-b8d8-bcab87889a91",
      "id": "a123b456-c789-4d0e-f123-456789abwxyz",
      "changes": [
        {
          "field": "final_price",
          "old_value": 199,
          "new_value": 149
        }
      ],
      "notified_at": "2025-02-19T15:30:45Z"
    }
  ],
  "meta": {
    "total_events": 1,
    "page_size": 15,
    "page": 1,
    "trace_id": "0195ce1a-6899-70ab-b213-738733bb8b08"
  }
}
```

### Get history filtered by metadata

Retrieve notifications across watches that share a metadata key-value pair. At least one `metadata` parameter is required for this endpoint.

```
GET /v1/products/watches/histories?metadata[{key}]={value}
```

<ParamField query="metadata[{key}]" type="string" required>
  Filter by metadata key-value pair. At least one metadata parameter is required. You can combine multiple pairs in a single request.

  Examples:

  * `?metadata[campaign]=summer_sale`
  * `?metadata[campaign]=summer_sale&metadata[priority]=high`
</ParamField>

<ParamField header="Authorization" type="string" required>
  Bearer token for authentication. Format: `Bearer {your_api_key}`.
</ParamField>

```bash theme={null}
curl --request GET \
  --url 'https://api.affiliate.com/v1/products/watches/histories?metadata[campaign]=summer_sale' \
  --header 'Authorization: Bearer {your_api_key}'
```

**Response**

```json theme={null}
{
  "meta": {
    "total": 1,
    "from": 1,
    "to": 1,
    "current_page": 1,
    "last_page": 1,
    "per_page": 20,
    "trace_id": "f12a3d45-6b78-90c1-2d3e-4f5678901234"
  },
  "data": [
    {
      "watch_id": "a123b456-c789-4d0e-f123-456789abcdef",
      "id": "a123b456-c789-4d0e-f123-456789abwxyz",
      "changes": [
        {
          "field": "final_price",
          "old_value": 199.00,
          "new_value": 149.00
        }
      ],
      "notified_at": "2025-02-19T15:30:45Z"
    }
  ]
}
```

## Webhook notification formats

When a rule triggers, the API sends an HTTP POST request to the webhook URL you configured. Your endpoint should respond with a `2xx` status code.

### Standard product change notification

Sent when a watch rule is triggered by a product field change such as a price drop or sale status update.

```json theme={null}
{
  "watch_history_id": "a0c88d4d-8c49-4257-be33-e7fe8e3b019c",
  "watch_event_type": "product_watch_alert",
  "timestamp": "2026-01-08T00:30:45+00:00",
  "watch_id": "a0c88cfc-7f54-4384-8bde-3f588d703a57",
  "watch_name": "Price Drop Alert Watch",
  "metadata": {
    "key1": "test-campaign"
  },
  "details": [
    {
      "id": "9200-us-B08HC1N3K1",
      "name": "DIFF Reading glasses for Women, Lightweight Oversized Readers",
      "network": {
        "id": 9200,
        "name": "Example Network"
      },
      "merchant": {
        "id": 921239,
        "name": "DIFF Eyewear"
      },
      "changes": [
        {
          "field": "final_price",
          "old_value": "999",
          "new_value": 31.99
        }
      ]
    }
  ]
}
```

### Product unavailable notification

Sent when a watched product is removed from the Affiliate.com database. The watch is automatically deleted after this notification. The `field` value `"__product__"` indicates a watch-level event rather than a product field change.

```json theme={null}
{
  "watch_history_id": "a0c8850f-a945-461e-8cb4-8b022bb6858f",
  "watch_event_type": "product_watch_alert",
  "timestamp": "2026-01-08T00:07:43+00:00",
  "watch_id": "a0c884a5-48e1-48cc-9eb1-ea767df2eb79",
  "watch_name": "Price Drop Alert Watch",
  "metadata": {
    "key1": "test-campaign"
  },
  "details": [
    {
      "id": "9200-us-B0CGKLGRPT",
      "name": "Unknown",
      "network": {
        "id": null,
        "name": "Unknown"
      },
      "merchant": {
        "id": null,
        "name": "Unknown"
      },
      "changes": [
        {
          "field": "__product__",
          "old_value": "available",
          "new_value": "unavailable"
        }
      ]
    }
  ]
}
```

### Watch expiration notification

Sent when a watch reaches its `expire_timestamp`. The `field` value `"__watch__"` indicates a watch status change. After receiving this notification, create a new watch or use the PUT endpoint to update `expire_timestamp` if you want to continue monitoring.

```json theme={null}
{
  "watch_history_id": "a0bea68c-f6ae-4b0a-a980-e6a7cab53c93",
  "watch_event_type": "product_watch_alert",
  "timestamp": "2026-01-03T02:23:06.000000Z",
  "watch_id": "a0bdafe6-1ce0-48a0-9085-b2efc2178a98",
  "watch_name": "Nike Shoe Price Drop Watch",
  "target_id": "39800028808",
  "changes": [
    {
      "field": "__watch__",
      "new_value": "expired",
      "old_value": "active"
    }
  ],
  "metadata": {
    "key1": "value1",
    "campaign": "summer_sale"
  }
}
```

## Metadata in webhooks

Every webhook notification includes the `metadata` object from the watch. This lets you route and process notifications programmatically using the tags you applied at watch creation — for example, dispatch notifications by `campaign`, `priority`, or any other dimension you track.

<Note>
  After you receive an expiration notification, the watch stops checking. To continue monitoring, call the PUT endpoint with `status: "active"` and a new `expire_timestamp`, or create a new watch.
</Note>

## Response fields

### Single-watch history response

<ResponseField name="watch_id" type="string">
  The ID of the watch these histories belong to.
</ResponseField>

<ResponseField name="name" type="string">
  The name of the watch.
</ResponseField>

<ResponseField name="target_id" type="string">
  The product identifier being watched.
</ResponseField>

<ResponseField name="histories" type="object[]">
  Array of notification history records.

  <Expandable title="History record">
    <ResponseField name="id" type="string">
      Unique identifier for this history record.
    </ResponseField>

    <ResponseField name="watch_id" type="string">
      The watch this record belongs to.
    </ResponseField>

    <ResponseField name="changes" type="object[]">
      The field changes that triggered the notification. Each object has `field`, `old_value`, and `new_value`.
    </ResponseField>

    <ResponseField name="notified_at" type="string">
      ISO 8601 datetime when the notification was sent.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="meta.total_events" type="integer">
  Total number of notification events for this watch.
</ResponseField>

<ResponseField name="meta.page_size" type="integer">
  Number of history records per page.
</ResponseField>

<ResponseField name="meta.page" type="integer">
  Current page number.
</ResponseField>

<ResponseField name="meta.trace_id" type="string">
  Unique identifier for this request.
</ResponseField>

### Metadata-filtered history response

The metadata-filtered history endpoint returns a paginated list where each `data` item is a history record. The `meta` object includes `total`, `from`, `to`, `current_page`, `last_page`, `per_page`, and `trace_id` fields following the standard paginated envelope.
