# Private cache (/docs/concepts/private-cache)



Every workspace has its own encrypted cache. Nothing is shared between workspaces: keys include the
workspace id, and every value is sealed with AES-256-GCM under a key only that workspace can unwrap.

## Two kinds of record [#two-kinds-of-record]

| Kind         | Used by                                                | Answers                                                    |
| ------------ | ------------------------------------------------------ | ---------------------------------------------------------- |
| **Entity**   | `/v1/run`, `/v1/run/auto`, single-stage waterfall runs | Any vendor, field by field, for the same person or company |
| **Response** | `/v1/call` on GridRouter's managed vendor accounts     | The same endpoint with the same normalized input           |

Calls on your own vendor keys never use the response cache, so at launch repeats are answered by the
entity cache through `/v1/run` and waterfalls.

An entity is found by any identity it carries, strongest first: LinkedIn URL, email, name at domain,
domain, company name. An enrichment by email is found again by LinkedIn URL. Inputs are normalized
first: emails are lowercased with `+tags` removed, domains reduce to the registrable domain, company
legal suffixes are dropped.

When every wanted field is fresh, the answer is a free `hit`. When some are, it is a `partial`: the
route runs and the cached fields fill what the vendors leave empty. A single-stage waterfall skips
the vendors whose fields are already fresh.

## Freshness [#freshness]

| Field class      | Default TTL | Field class      | Default TTL |
| ---------------- | ----------- | ---------------- | ----------- |
| `work_email`     | 90 days     | `technographics` | 14 days     |
| `personal_email` | 90 days     | `signals`        | 1 day       |
| `phone`          | 180 days    | `verification`   | 30 days     |
| `title`          | 30 days     | `social`         | 30 days     |
| `firmographics`  | 30 days     | `other`          | 30 days     |

A value is kept for the shortest of: its class TTL (overridable per workspace), the vendor's data
terms (vendors that forbid storage are never cached), your plan's maximum (30 days on Free) and the
request's `ttl_s`.

## Per request [#per-request]

Set `data.cache` in the [execution options](/docs/concepts/execution-options), or use
`Cache-Control`:

| `mode`             | Header           | Meaning                                                                     |
| ------------------ | ---------------- | --------------------------------------------------------------------------- |
| `prefer` (default) |                  | Serve fresh fields, fetch the rest                                          |
| `refresh`          | `no-cache`       | Always fetch, then write                                                    |
| `only`             | `only-if-cached` | Never call a vendor; a miss is `404 not_found` with `details.cache: "miss"` |
| `bypass`           | `no-store`       | No read, no write                                                           |

`max_age_s` (`Cache-Control: max-age=N`) is the oldest value this request accepts,
`stale_while_revalidate_s` serves a stale value while refreshing it in the background, and
`write: false` reads without writing.

## Response headers [#response-headers]

| Header               | Value                                                                                            |
| -------------------- | ------------------------------------------------------------------------------------------------ |
| `X-Grid-Cache`       | `hit`, `partial`, `stale` or `miss` when the cache was consulted; `bypass` on an explicit bypass |
| `X-Grid-Cache-Age`   | Seconds since the value was fetched                                                              |
| `X-Grid-Fetched-At`  | When it was fetched (ISO, UTC)                                                                   |
| `X-Grid-Saved-Micro` | Vendor spend the answer avoided, in micro-USD (list price for your own keys)                     |

The call body carries the same facts in `cache`, with `fields_cached` and `fields_fetched`.

## Manage it [#manage-it]

`/cache` shows savings, a 30-day hit chart and an explorer with masked labels (never values).

* [`DELETE /v1/cache`](/docs/api/cache/cache_purge) purges by key, tag or capability; `all=true`
  destroys the workspace's cache key, so every value becomes unreadable at once.
* [`POST /v1/cache/forget`](/docs/api/cache/cache_forget) deletes every record about a person or
  company under any identity, for data subject requests.
* [`POST /v1/cache/feedback`](/docs/api/cache/cache_feedback) drops fields (after a bounce, say) so
  the next request fetches them again.

Free keeps up to 50,000 records. At the limit, new records are not written and existing ones still
update.

