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

# Cache Metrics: Response Format

> Response structure for Gateway cache metrics API queries

## Response format

Every successful response has the same outer shape:

```json theme={"dark"}
{
  "data": {
    "dataPoints": [
      {
        "startTimestamp": "2026-04-29T12:00:00.000Z",
        "endTimestamp": "2026-04-29T13:00:00.000Z",
        "total": 1234,
        "<aggregationKey>": 0,
        "<groupByKey>": "value-or-null"
      }
    ]
  }
}
```

* **`total`**: implicit `COUNT(*)` for the row. Always present.
* **`<aggregationKey>`**: one key per requested aggregation. The key is `<type><Column>` in camelCase (e.g. `sumPotentialCostSavings`, `p99CacheLookupLatencyMs`, `sumCacheReadInputTokens`).
* **`<groupByKey>`**: one key per `groupBy` entry. The key is the lowerCamelCase form of the underlying column. Two special mappings:
  * `userEmail` and `virtualaccount` both map to `createdBySubjectSlug` in the response.
  * `team` maps to `team` (the value is a single unnested scalar, not an array).
    All other `groupBy` keys preserve their lowerCamelCase name.
* **`startTimestamp`**: present only for timeseries responses. Bucket start as an ISO 8601 timestamp string (e.g. `"2026-04-29T12:00:00.000Z"`). Distribution responses omit it.
* **`endTimestamp`**: present only for timeseries responses. Bucket end as an ISO 8601 timestamp string, equal to the next bucket's `startTimestamp` (e.g. `"2026-04-29T13:00:00.000Z"`). Distribution responses omit it.

<Note>
  Virtual-model rows surface under the `virtualModelName` key in the response (not `virtualModel`), because the response key is the lowerCamelCase of the underlying database column.
</Note>

### Distribution response example

```json theme={"dark"}
{
  "data": {
    "dataPoints": [
      {
        "cacheType": "semantic",
        "cacheNamespace": "prod-chat",
        "total": 4200,
        "sumPotentialCostSavings": 12.34,
        "sumCacheReadInputTokens": 480000,
        "p50CacheLookupLatencyMs": 8.2
      },
      {
        "cacheType": "semantic",
        "cacheNamespace": "prod-search",
        "total": 1850,
        "sumPotentialCostSavings": 4.81,
        "sumCacheReadInputTokens": 210000,
        "p50CacheLookupLatencyMs": 11.4
      }
    ]
  }
}
```

### Timeseries response example

```json theme={"dark"}
{
  "data": {
    "dataPoints": [
      {
        "startTimestamp": "2026-04-21T00:00:00.000Z",
        "endTimestamp": "2026-04-21T01:00:00.000Z",
        "cacheType": "semantic",
        "total": 180,
        "sumPotentialCostSavings": 0.52,
        "p99CacheLookupLatencyMs": 22.0
      },
      {
        "startTimestamp": "2026-04-21T01:00:00.000Z",
        "endTimestamp": "2026-04-21T02:00:00.000Z",
        "cacheType": "semantic",
        "total": 210,
        "sumPotentialCostSavings": 0.61,
        "p99CacheLookupLatencyMs": 24.5
      }
    ]
  }
}
```

<Info>
  If `groupBy` is empty or omitted, the response collapses to a single row (or one row per timeseries bucket) summarising every cache-eligible request inside the window. Note that the server always pins `WHERE "CacheLookupStatus" IS NOT NULL`, so non-cache rows are filtered out automatically.
</Info>

## Error responses

A malformed query returns `400 Bad Request`:

```json theme={"dark"}
{
  "statusCode": 400,
  "message": "Invalid query",
  "details": ["..."]
}
```

Common causes:

* Operator not allowed on this field, for example, `STRING_CONTAINS` on `cacheType` (it supports only `IN`/`NOT_IN`).
* Missing required `value` (or wrong shape, e.g. scalar where array is expected for `IN` / `BETWEEN`).
* Unknown field name for the datasource.
* Invalid `interval` format (compound expressions, unrecognised unit, non-positive integer).
* Missing required `interval` for a timeseries query.

Other status codes:

* `401 Unauthorized`: missing or invalid bearer token.
* `403 Forbidden`: caller does not have permission for the requested scope.
* `500 Internal Server Error`: unexpected server error while executing the query.
