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

# Caching

> Multi-tier caching strategies, ETag support, stale-while-revalidate, and YouTube video cache.

## Overview

The High IQ API uses a multi-tier caching system that automatically classifies endpoints and applies appropriate cache strategies. Caching is handled at both the CDN (Vercel Edge) and browser levels using standard HTTP cache headers, ETags, and stale-while-revalidate directives.

## Cache Tiers

Endpoints are automatically classified into one of eight endpoint types, each with its own caching strategy:

| Type             | TTL        | Browser `max-age`    | CDN `s-maxage` | Stale-While-Revalidate | ETag   |
| ---------------- | ---------- | -------------------- | -------------- | ---------------------- | ------ |
| **Static**       | 24 hours   | 24 hours             | 7 days         | 7 days                 | Strong |
| **Catalog**      | 5 minutes  | 5 minutes            | 5 minutes      | 15 minutes             | Strong |
| **Detail**       | 1 hour     | 1 hour               | 24 hours       | 3 days                 | Strong |
| **Search**       | 1 minute   | 1 minute             | 1 minute       | 5 minutes              | Weak   |
| **AI Generated** | 10 minutes | 10 minutes           | Private        | 30 minutes             | Weak   |
| **User Data**    | 1 minute   | 0 (no browser cache) | Private        | None                   | Weak   |
| **Analytics**    | 30 seconds | 0 (no browser cache) | Private        | None                   | Weak   |
| **Realtime**     | No cache   | No cache             | No cache       | None                   | None   |

### Endpoint Classification

The cache classifier uses URL pattern matching to determine the endpoint type. Only `GET` requests are cached. All other HTTP methods (`POST`, `PUT`, `DELETE`, etc.) bypass the cache entirely.

<Tabs>
  <Tab title="Static">
    Rarely-changing content:

    ```
    /                    → Static (24h TTL)
    ```
  </Tab>

  <Tab title="Catalog">
    Strain lists and filtered collections:

    ```
    /api/v1/strains              → Catalog (5min TTL)
    /api/v1/strains/popular      → Catalog (5min TTL)
    /api/v1/strains/by-terpene/* → Catalog (5min TTL)
    /api/v1/strains/by-type/*    → Catalog (5min TTL)
    /api/v1/strains/by-letter/*  → Catalog (5min TTL)
    ```
  </Tab>

  <Tab title="Detail">
    Individual strain pages with stable data:

    ```
    /api/v1/strains/slug/:slug          → Detail (1h TTL)
    /api/v1/strains/slug/:slug/complete  → Detail (1h TTL)
    /api/v1/strains/slug/:slug/youtube   → Detail (1h TTL)
    /api/v1/strains/:id                  → Detail (1h TTL)
    /api/v1/strains/:id/similar          → Detail (1h TTL)
    /api/v1/strains/:id/complete         → Detail (1h TTL)
    ```
  </Tab>

  <Tab title="Search">
    Query-dependent results:

    ```
    /api/v1/strains/search*       → Search (1min TTL)
    /api/v1/strains/autocomplete* → Search (1min TTL)
    ```
  </Tab>

  <Tab title="Realtime (No Cache)">
    Fresh data required for every request:

    ```
    /health                              → Realtime
    /docs                                → Realtime
    /api/v1/notifications/*              → Realtime
    /api/v1/chat/*                       → Realtime
    /api/v1/scanner/*                    → Realtime
    /api/v1/receipts/*                   → Realtime
    /api/v1/research/strain-pipeline/*   → Realtime
    ```
  </Tab>
</Tabs>

## Cache-Control Headers

The API builds `Cache-Control` headers dynamically based on the endpoint classification:

```
Cache-Control: public, max-age=300, s-maxage=300, stale-while-revalidate=900
```

### Header Components

| Directive                             | Meaning                                                       |
| ------------------------------------- | ------------------------------------------------------------- |
| `public`                              | Response can be stored by any cache (browser, CDN)            |
| `private`                             | Response is user-specific, only browser can cache             |
| `max-age=N`                           | Browser cache duration in seconds                             |
| `s-maxage=N`                          | CDN/shared cache duration in seconds                          |
| `stale-while-revalidate=N`            | Serve stale data for N seconds while refreshing in background |
| `no-store, no-cache, must-revalidate` | No caching at all (realtime endpoints)                        |

### Example Headers by Endpoint Type

<Tabs>
  <Tab title="Catalog">
    ```
    Cache-Control: public, max-age=300, s-maxage=300, stale-while-revalidate=900
    Vary: Accept-Language
    ETag: "abc123"
    ```
  </Tab>

  <Tab title="Detail">
    ```
    Cache-Control: public, max-age=3600, s-maxage=86400, stale-while-revalidate=259200
    Vary: Accept-Language, Authorization
    ETag: "def456"
    ```
  </Tab>

  <Tab title="User Data">
    ```
    Cache-Control: private, max-age=0
    Vary: Authorization
    ETag: W/"ghi789"
    ```
  </Tab>

  <Tab title="Realtime">
    ```
    Cache-Control: no-store, no-cache, must-revalidate
    Pragma: no-cache
    ```
  </Tab>
</Tabs>

## ETag Support

The API supports both strong and weak ETags for conditional requests:

| ETag Type | Format       | Used For                                                                     |
| --------- | ------------ | ---------------------------------------------------------------------------- |
| Strong    | `"abc123"`   | Static, catalog, and detail endpoints where byte-level equality matters      |
| Weak      | `W/"abc123"` | Search, AI-generated, and user data where semantic equivalence is sufficient |

### Conditional Requests

Clients can send `If-None-Match` headers to check if their cached version is still valid:

```bash theme={null}
# First request - get the ETag
curl -i "https://api.thisiswhyimhigh.com/api/v1/strains/slug/blue-dream"
# ETag: "abc123"

# Subsequent request - use conditional request
curl -i "https://api.thisiswhyimhigh.com/api/v1/strains/slug/blue-dream" \
  -H 'If-None-Match: "abc123"'
# Returns 304 Not Modified if unchanged (no body, saves bandwidth)
```

## Conditional Response Optimization

The caching middleware inspects response content and adjusts headers dynamically:

| Condition                           | Cache Behavior                                 |
| ----------------------------------- | ---------------------------------------------- |
| Error responses                     | `Cache-Control: no-cache` (never cache errors) |
| Empty array results                 | Short cache: `max-age=60`                      |
| Large list results (100+ items)     | Extended cache: `max-age` doubled              |
| Response has timestamp/lastModified | `Last-Modified` header added                   |

An `X-Item-Count` header is added to list responses:

```
X-Item-Count: 47
```

## YouTube Video Cache

YouTube video data uses a specialized 30-day cache in Supabase to optimize YouTube API quota usage (10,000 units/day limit).

| Aspect            | Value                                              |
| ----------------- | -------------------------------------------------- |
| **Cache Table**   | `youtube_video_cache` in Supabase                  |
| **TTL**           | 30 days                                            |
| **Quota Savings** | \~10x more efficient than pipeline-based fetching  |
| **Fallback**      | Returns YouTube search URL when quota is exhausted |

```bash theme={null}
# Fetches from cache or YouTube API
curl "https://api.thisiswhyimhigh.com/api/v1/strains/slug/blue-dream/youtube"

# Check cache statistics
curl "https://api.thisiswhyimhigh.com/api/v1/strains/youtube/cache-stats"
```

## Cache Invalidation

Write operations (`POST`, `PUT`, `PATCH`, `DELETE`) automatically trigger cache invalidation for related content:

| Path Pattern                           | Invalidated Tags               |
| -------------------------------------- | ------------------------------ |
| `/strains/*`                           | `strains`, `catalog`, `search` |
| `/users/*`, `/orders/*`, `/sessions/*` | `user_data`                    |

Invalidation tags are sent via the `X-Cache-Invalidate` response header for CDN integration:

```
X-Cache-Invalidate: strains,catalog,search
```

## Cache Warming

The API includes proactive cache warming that triggers on approximately 0.1% of requests. It pre-populates cache entries for popular endpoints to reduce cold-cache latency for common queries.

## Cache Analytics

Cache performance is tracked internally with hit/miss/bypass counts per endpoint type. In development, analytics are periodically logged:

```
[CacheAnalytics] Performance: {
  hitRate: 0.73,
  missRate: 0.22,
  bypassRate: 0.05,
  totalRequests: 14520
}
```

The `X-Cache-Status` header indicates the cache outcome:

| Value    | Meaning                                     |
| -------- | ------------------------------------------- |
| `HIT`    | Response served from cache                  |
| `MISS`   | Cache miss, response generated fresh        |
| (absent) | Cache bypassed (non-GET, realtime endpoint) |

## Debug Headers (Development Only)

In development mode, additional debugging headers are included:

```
X-Endpoint-Type: catalog
X-Cache-Strategy: enabled
X-Cache-TTL: 300
X-Cache-MaxAge: 300
```

These headers are not sent in production.
