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

# How Earn Works

> How the Earn Data API aggregates and normalizes vault data: the NormalizedVault schema, transactional capabilities, and data freshness.

This page explains how the Earn Data API aggregates vault data across protocols, normalizes it into a consistent schema, and keeps it fresh.

***

## Architecture Overview

The Earn Data API is a **data aggregation layer** that sits between protocol data and your application. It handles:

1. **Ingestion.** Fetching vault data from multiple data sources across supported protocols.
2. **Normalization.** Transforming protocol-specific formats into a unified `NormalizedVault` schema.
3. **Capability Resolution.** Determining which vaults support deposits and withdrawals via Composer.
4. **Serving.** Exposing the normalized data through a REST API with filtering, sorting, and pagination.

***

## Data Freshness

The Earn Data API runs a background sync pipeline that keeps vault data current:

| Data                                                  | Refresh Frequency |
| ----------------------------------------------------- | ----------------- |
| Vault metadata, APY, and TVL                          | Every 15 minutes  |
| Transactional capabilities (deposit/withdraw support) | Every 2 minutes   |

This means APY and TVL data is at most 15 minutes stale, and transactional capability data is at most 2 minutes stale.

***

## The NormalizedVault Schema

Every vault in the Earn API follows the same schema, regardless of which protocol or data provider it comes from. This is the core data structure:

```json theme={"system"}
{
  "address": "0x7BfA7C4f149E7415b73bdeDfe609237e29CBF34A",
  "network": "base",
  "chainId": 8453,
  "slug": "morpho-base-usdc-0x7bfa",
  "name": "Morpho USDC Vault",
  "description": "Optimized USDC lending vault on Morpho",  // optional, may be absent
  "protocol": {
    "name": "Morpho",
    "logoUri": "https://example.com/morpho-logo.png",
    "url": "https://morpho.org"
  },
  "underlyingTokens": [
    {
      "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "symbol": "USDC",
      "decimals": 6,
      "weight": 1.0
    }
  ],
  "lpTokens": [],                  // typically empty; use vault `address` as toToken for Composer
  "rewardTokens": [],             // optional, may be absent
  "tags": ["stablecoin", "lending"],
  "analytics": {
    "apy": {
      "base": 0.0534,             // nullable, can be null
      "reward": null,             // nullable, can be null
      "total": 0.0534
    },
    "apy1d": 0.0521,              // nullable, can be null
    "apy7d": 0.0538,              // nullable, can be null
    "apy30d": 0.0545,
    "tvl": {
      "usd": "12500000.00",
      "native": "12500000000000"  // optional, may be absent
    },
    "updatedAt": "2026-03-31T14:30:00.000Z"
  },
  "caps": {                       // optional, may be absent
    "totalCap": "50000000000000",
    "maxCap": "100000000000000"
  },
  "timeLock": 0,                  // optional, may be absent
  "kyc": false,                   // optional, may be absent
  "isTransactional": true,
  "isRedeemable": true,
  "depositPacks": [
    { "name": "morpho-deposit", "stepsType": "instant" }
  ],
  "redeemPacks": [
    { "name": "morpho-redeem", "stepsType": "instant" }
  ],
  "syncedAt": "2026-03-31T14:30:00.000Z"
}
```

### Key Fields

| Field                                  | Type             | Description                                                                                                                  |
| -------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `address`                              | `string`         | Vault contract address                                                                                                       |
| `network`                              | `string`         | Network name (e.g., `"base"`, `"ethereum"`)                                                                                  |
| `chainId`                              | `number`         | EVM chain ID                                                                                                                 |
| `slug`                                 | `string`         | Unique vault identifier across providers                                                                                     |
| `protocol`                             | `object`         | Protocol metadata (name, logo, URL)                                                                                          |
| `underlyingTokens`                     | `array`          | Tokens the vault accepts for deposit (with optional weight for multi-asset vaults)                                           |
| `lpTokens`                             | `array`          | Tokens representing the vault position. Typically empty; use the vault's `address` field as `toToken` for Composer deposits. |
| `rewardTokens`                         | `array?`         | Additional reward tokens (e.g., governance tokens). Optional, may be absent.                                                 |
| `analytics.apy`                        | `object`         | Current APY breakdown: `base` (nullable), `reward` (nullable), `total`                                                       |
| `analytics.apy1d` / `apy7d` / `apy30d` | `number \| null` | Rolling average APY over 1 day, 7 days, and 30 days. Nullable, may be `null` for new vaults.                                 |
| `analytics.tvl`                        | `object`         | Total value locked. `usd` is always present; `native` is optional.                                                           |
| `isTransactional`                      | `boolean`        | Whether deposits are available via Composer                                                                                  |
| `isRedeemable`                         | `boolean`        | Whether withdrawals are available via Composer                                                                               |
| `depositPacks` / `redeemPacks`         | `array`          | Composer zap-pack entries describing available deposit/redeem methods                                                        |
| `description`                          | `string?`        | Vault description. Optional, may be absent.                                                                                  |
| `caps`                                 | `object?`        | Deposit caps (`totalCap`, `maxCap`). Optional, may be absent.                                                                |
| `timeLock`                             | `number?`        | Lock period in seconds (0 = no lock). Optional, may be absent.                                                               |
| `kyc`                                  | `boolean?`       | Whether the vault requires KYC. Optional, may be absent.                                                                     |

### Transactional Capabilities

The `isTransactional` and `isRedeemable` flags are derived from Composer's zap-pack data, not from the vault itself. This tells you whether the LI.FI infrastructure can execute deposits and withdrawals for this vault:

* **`isTransactional: true`** means you can use [Composer's quote endpoint](/composer/guides/api-integration) with this vault's contract address as `toToken` to deposit.
* **`isRedeemable: true`** means you can use Composer with this vault's contract address as `fromToken` to withdraw.

Use these flags to control your UI. For example, hide the "Deposit" button for vaults where `isTransactional` is `false`.

***

## Supported Protocols and Chains

The Earn Data API aggregates vaults from 20+ protocols across 20 chains. Use the discovery endpoints to see what is currently indexed:

* `GET /v1/chains` — returns all chains with at least one active vault
* `GET /v1/protocols` — returns all protocols with at least one active vault

These endpoints reflect live data from the sync pipeline and will grow as new protocols and chains are onboarded.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/earn/quickstart">
    Make your first Earn API calls in under 5 minutes
  </Card>

  <Card title="API Integration Guide" icon="code" href="/earn/guides/api-integration">
    Full endpoint reference with all parameters and response shapes
  </Card>
</CardGroup>
