# The response envelope

Every read returns the same envelope. This lets any client, including an AI agent, reason about what the data is and how fresh it is without out-of-band knowledge.

```json
{
  "data": [ ... ],
  "tier": "graph",
  "as_of": "2026-07-07T18:00:00Z",
  "provenance": { "engine": "hybrid", "cached": false },
  "count": 24
}
```

## Fields

| Field | What it is |
|---|---|
| `data` | Your result. An object for a single resource, an array for a list. Read this. |
| `tier` | `graph` (stored, cacheable) or `live` (fetched per request). See [Tiers and freshness](#/tiers). |
| `as_of` | When the data was observed, in UTC. For live data this tells you how stale a number is. |
| `provenance` | Where the data came from and how it was produced (engine, source, cached flag). |
| `count` and page fields | On lists, the number returned plus pagination fields. See [Pagination](#/pagination). |

## Money

All amounts are integer **minor units** with a `currency`. `39900` in `INR` means `399.00`. Never assume two decimal places: divide by the currency exponent. This avoids floating point rounding.

## ETag and caching

Graph-tier responses carry a strong `ETag` and `Cache-Control`. Send `If-None-Match` with the ETag to get a `304 Not Modified` and skip the transfer when nothing changed.

```bash
curl -sS "https://dev.ziffi.xyz/v1/search?q=serum" -H 'If-None-Match: "abc123…"' -i | head -1
```

## Next steps

- [Tiers and freshness](#/tiers): when to trust `graph` vs `live`.
- [Errors](#/errors): the failure envelope.
