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

# Rates

> The rate table: every FX rate the keeper oracle has posted, per currency code, for rate history and freshness checks.

`rate` records every `RatePosted` event from the `KeeperFxOracle`: one row per code per post. The latest row per code is also copied onto `currency.lastRate`, so query this table when you need history rather than the current value.

## Fields

| Field         | Type   | Unit                | Meaning                                                                       |
| ------------- | ------ | ------------------- | ----------------------------------------------------------------------------- |
| `id`          | text   |                     | `txHash-logIndex`. Primary key.                                               |
| `code`        | hex    | bytes32             | Currency code, hex encoded.                                                   |
| `rate`        | bigint | units per USD, 1e18 | The posted rate.                                                              |
| `publishTime` | bigint | unix seconds        | The timestamp the keeper attached to the rate (the oracle's freshness clock). |
| `timestamp`   | bigint | unix seconds        | Block timestamp of the post.                                                  |
| `blockNumber` | bigint |                     |                                                                               |

Index: `(code, publishTime)`. Filter on `code` and order by `publishTime`.

`code` is the hex form, so encode the ASCII code first (see [currency codes](/api/graphql#currency-codes)). INR is `0x494e520000000000000000000000000000000000000000000000000000000000`. USD is never posted; its rate is fixed at `1e18`.

## Examples

Rate history for one currency, newest first:

```graphql theme={"system"}
query Rates($code: String!) {
  rates(where: { code: $code }, orderBy: "publishTime", orderDirection: "desc", limit: 100) {
    items { rate publishTime timestamp blockNumber }
  }
}
```

Through the currency relation, which lets you filter by the readable symbol:

```graphql theme={"system"}
{
  currencys(where: { symbol: "JPY" }) {
    items {
      symbol lastRate lastRateAt
      rates(orderBy: "publishTime", orderDirection: "desc", limit: 24) { items { rate publishTime } }
    }
  }
}
```

Rates in a time window for a chart, oldest first:

```graphql theme={"system"}
query Series($code: String!, $from: BigInt!) {
  rates(where: { code: $code, publishTime_gte: $from }, orderBy: "publishTime", orderDirection: "asc", limit: 1000) {
    items { rate publishTime }
  }
}
```

The most recent post across every code (to see when the keeper last ran):

```graphql theme={"system"}
{ rates(orderBy: "timestamp", orderDirection: "desc", limit: 60) { items { code rate publishTime currencyInfo { symbol } } } }
```

Posts in a single transaction (the keeper batches up to 25 codes per `post`):

```graphql theme={"system"}
{ rates(where: { blockNumber: "65900000" }) { items { code rate currencyInfo { symbol } } } }
```

With `curl`:

```bash theme={"system"}
curl -s https://api.windrose.market/graphql \
  -H 'content-type: application/json' \
  -d '{"query":"query($c:String!){ rates(where:{code:$c}, orderBy:\"publishTime\", orderDirection:\"desc\", limit:5){ items { rate publishTime timestamp } } }","variables":{"c":"0x494e520000000000000000000000000000000000000000000000000000000000"}}'
```

## Reading rates

* `rate / 1e18` is the number of currency units per US dollar. A JPY value of `149800000000000000000` is 149.8 JPY per USD.
* Freshness is judged against `publishTime`, not the block time. The keeper oracle treats a rate as fresh for two hours and usable at the higher stale fee for five days; after that mint, redeem and `vault.status()` revert until a new post arrives. The [oracles page](/protocol/contracts/oracles) has the windows and the rules.
* The keeper re-posts an unchanged rate hourly as a heartbeat, so consecutive rows with the same `rate` are expected.
* A single post cannot move a rate by more than the oracle's `maxMoveBps` (15% on the current deployments); a larger move takes several posts.
* `currency.lastRate` is only updated for codes the registry lists. A code that appears here but not in `currencys` was posted by the keeper without being registered.
