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

# Vault Yield & Fees

> Standardized realized APY, Merkl incentives, yield durability, before/after-fees APY, deposit status, and deposit/redemption terms on every vault.

Protocol-reported APYs aren't comparable: Morpho reports a smoothed average, Aave a spot supply rate, Lagoon a weekly APR, Yearn a net APR. Webacy publishes one standardized yield per vault, then breaks it down so you can see where it comes from, what fees cost, and whether you can actually get it.

Every field on this page is returned on the vault `metadata` object by [`GET /vaults`](https://docs.webacy.com/vault-risk-intelligence) (list) and `GET /vaults/{address}` (detail), and on the [V3 vault detail](https://docs.webacy.com/api-reference/vault-risk-v3/get-vault-risk-detail-v3.md). All yields are decimal ratios (`0.0291` = 2.91%).

> [!NOTE]
>
> These fields are informational. None of them changes a vault's risk score or letter grade.

## What you get

> **Standardized APY**
>
> The vault's realized yield, measured the same way for every protocol, with its source and window.

> **Incentives**
>
> Third-party reward campaigns (Merkl), kept separate from the base yield, with eligibility and end dates.

> **Yield durability**
>
> A 0–100 score for how much of the yield a typical depositor can count on if incentives stop.

> **Fees**
>
> APY before and after the vault's fees, with the fee rates and where they came from.

> **Deposit status**
>
> Whether a new depositor can deposit right now, and who is allowed to.

> **Flow terms**
>
> Whether deposits and redemptions settle instantly or through a request queue, and any lockup.

***

## Standardized APY

When `apy_measure` starts with `realized_`, `apy` is the vault's **realized share-price yield**: how much the value of one vault share actually grew, annualized. Its `apy_source` is then `onchain.share_price` (Webacy's own on-chain read) or `tradingstrategy.share_price` (an independent share-price feed, corroborated against a live on-chain read). When no realized yield is available, `apy` is the protocol's own figure instead (a spot, smoothed, or projected rate), and `apy_source` / `apy_measure` say which. Check `apy_measure` before treating `apy` as measured depositor earnings.

```text theme={null}
realized APY = (share price now / share price N days ago) ^ (365 / N) − 1
```

* **Windows:** 7, 30, and 90 days. The headline `apy` is the 90-day window, or the 30-day window when the vault is younger. The 7-day window is published for monitoring but is never the headline.
* **Source:** share prices are read on-chain by Webacy at the block for each date (`convertToAssets` for ERC-4626 vaults, `pricePerShare` for Yearn v2, `getPricePerFullShare` for Beefy, the reserve's normalized income for Aave). Where an independent share-price feed also covers the vault, the two are compared and a disagreement is flagged.
* **Net of fees by construction:** protocols that take their fee inside the share price (Morpho, Euler, Yearn, Lagoon, and others) are already net of that fee.
* **Guards:** Webacy's pipeline refuses a realized result outside −95% to +50% rather than publishing it. A share price rising faster than that is usually interest accruing on debt that won't be repaid. Funds whose share price tracks a market price (equity or gold index funds) are refused too, because that's a price return, not yield. The API then publishes `apy` only when it is above 0 and at most 500%, so a realized loss appears only in `realized_apy_windows`.

| Field | Meaning |
| :- | :- |
| `apy` | The headline yield. Never negative: a realized loss is read from `realized_apy_windows`. |
| `apy_kind` | `null` for ordinary vault yield. `incentive_reward` means `apy` is a campaign reward rate paid from a separate escrow, not yield the deposits earn. Treat any other non-null value as not ordinary yield, and leave these rows out when ranking or comparing `apy`. |
| `apy_source` | Where `apy` came from. `onchain.share_price` and `tradingstrategy.share_price` are realized share-price yield. Other values name the protocol's own figure when no realized yield is available, e.g. `morpho.avgNetApy`, `euler.supplyApy`, `aave.supplyInfo.apy`, `lagoon.weeklyApr.linearNetApr`. |
| `apy_measure` | What kind of number it is: a realized window (`realized_90d`, `realized_30d`, `realized_7d`, `realized_lifetime`), or the protocol measure (`spot`, `smoothed`, `trailing_7d`, `trailing_30d`, `projected`, `realized`). |
| `apy_native` | The protocol's own reported figure when `apy` is the realized yield, so you can show "realized 2.91% (protocol reports 3.16%)". |
| `realized_apy_windows` | All realized windows, e.g. `{"realized_7d": 0.0315, "realized_30d": 0.0305, "realized_90d": 0.0291}`. Signed, so a loss shows here. |

> [!TIP]
>
> A gap between `apy` and `apy_native` is information, not an error. Protocol figures are often spot rates or include rewards that never reach the share price. The realized figure is what depositors actually earned.

The vault pipeline runs every 6 hours. Each vault's `data_as_of` says when its record was last measured; a failed read keeps the previous record, so `data_as_of` can be older than the latest run.

***

## Incentives

`incentives` describes third-party reward campaigns run through [Merkl](https://merkl.xyz), matched to the vault by chain and address. Incentives are paid from a sponsor's budget, not earned by the deposits, so they are **never added into `apy`**. The object is `null` when the vault has no Merkl campaign.

| Field | Meaning |
| :- | :- |
| `incentive_apr` | Total incentive APR across live campaigns. |
| `incentive_apr_liquid` / `incentive_apr_speculative` | The part paid in tradable tokens vs. points or pre-launch tokens with no market value yet. |
| `incentive_apr_restricted` | The part only some depositors can earn (for example, Coinbase-verified addresses only). A typical depositor's incentive is `incentive_apr − incentive_apr_restricted`. |
| `incentive_share` | Share of the total yield that comes from incentives, in \[0, 1]. `incentive_share_basis` says which base yield it was computed against (`merkl_native`, `realized_share_price`, or `merkl_total`). |
| `incentive_streak_days` | Days of unbroken campaign coverage. `incentive_current_end` is the latest end date among live campaigns. |
| `incentive_campaigns_active` | Up to 20 live campaigns, soonest-ending first (`incentive_campaigns_active_count` gives the full count): each one's own `apr`, reward token, `start` / `end`, `eligibility` (`open`, `conditional`, `restricted`, `unknown`), `hooks`, and `reward_quality` (`stable`, `stable_depegging`, `volatile`, `unverified`, `unpriced`). |
| `incentive_coverage_spans` | Campaign coverage over the last 365 days, for drawing a renewal timeline. |

> [!WARNING]
>
> Read `incentive_apr` together with `incentive_apr_restricted`. An ordinary depositor's incentive is `incentive_apr − incentive_apr_restricted`. When all of it is restricted, an ordinary depositor earns only the base `apy`.
>
> `null` on `incentive_apr_restricted` (or any eligibility APR field) means eligibility wasn't computed. Don't read it as 0, and don't treat the incentive as open. APR whose eligibility is unknown is not counted as restricted, so the subtraction above can include it (`incentive_apr_liquid_eligibility_unknown` gives that part).

Also returned: `incentive_apr_liquid_restricted`, `incentive_apr_liquid_eligibility_unknown`, `incentive_apr_liquid_low_quality` (open token APR paid in a token with no reliable value), `incentive_apr_boosted` (campaigns with per-user boosts, so the headline is an average), `incentive_eligibility_hooks`, `incentive_reward_qualities`, `incentive_self_funded`, `merkl_native_apr`, and `merkl_total_apr`. Each campaign row also carries `boosted`.

***

## Yield durability

`incentives.yield_durability` scores how much of a vault's current yield a **typical depositor** can count on if incentives are not renewed. The base yield counts as fully durable; only the incentive part is discounted:

```text theme={null}
score = 100 × [ (1 − share) + share × liquid_fraction × renewal × funding ]
```

* `share` is the incentive share of the yield an ordinary depositor can earn. Restricted campaigns are left out, so it can be lower than the headline `incentive_share`.
* `liquid_fraction` is the share of the open incentives paid in tradable tokens. Points and pre-launch tokens count as 0, and so does a token with no reliable value. APR that Merkl reports but can't attribute to a campaign, or whose eligibility is unknown, counts as 0.5. When no incentive is open to an ordinary depositor, it is 0.5 and has no effect, because `share` is 0.
* `renewal` grows with the campaign streak: 0.25 + 0.65 × min(streak days / 365, 1), so between 0.25 and 0.90.
* `funding` is 0.85 when the vault's own curator funds the campaign, otherwise 1.

| `tier` | Score |
| :- | :- |
| `high` | 80 or more |
| `medium` | 50 to below 80 |
| `low` | below 50 |
| `no_incentive` | the live campaign pays 0% |

`flags` add context independent of the tier: `incentive_dependent` (incentives are 50% or more of the typical depositor's yield), `short_streak` (under 30 days of unbroken campaigns), `points_incentive` / `pretge_incentive`, `self_subsidised`, and `restricted_incentive` (some incentive APR is gated and was excluded from the score). `drivers` returns the inputs above.

> [!NOTE]
>
> A vault whose incentives are all restricted can score `high`: for an ordinary depositor its yield is all base yield, which is fully durable. The `restricted_incentive` flag tells you this is the case.

***

## Fees

`fees` gives the yield before and after the vault's own fees, with the rates behind them. The object is `null` when nothing is known about the vault's fees.

| Field | Meaning |
| :- | :- |
| `apy_after_fees` | What a depositor earns after the vault's fees. Same window as `apy`. |
| `apy_before_fees` | The yield before fees: `apy_after_fees / (1 − performance) + management`. |
| `fee_gap_reason` | Why `apy_before_fees` is `null`: `no_apy`, `treatment_unknown`, `apy_source_unclassified`, `fee_not_on_whole_yield` (e.g. Beefy, whose fee applies only to harvested rewards), or `rate_unknown`. |
| `fee_treatment` | `in_share_price` when the protocol takes its fee inside the share price, otherwise `unknown`. |
| `fee_model` | The rates: `performance_bps`, `management_bps`, `entry_bps`, `exit_bps` (basis points, 1000 = 10%), plus `source` (where they were read, e.g. `morpho_api`, `lagoon_api`) and `management_source` (`protocol_design` when the protocol has no management fee by design). |

A rate the source doesn't provide is never assumed: `apy_before_fees` stays `null` and `fee_gap_reason` says why. Entry and exit fees are reported in `fee_model` but not folded into either APY.

***

## Deposit status

`deposit_status` says whether a new depositor can deposit right now.

| Field | Meaning |
| :- | :- |
| `status` | `open`, `capped` (at capacity), `paused`, `closed` (deliberately not accepting deposits, e.g. shut down or a supply cap of zero), or `unknown` (no reliable signal; never guessed). |
| `reason` | Machine-readable detail, e.g. `supply_cap_reached`, `supply_cap_zero`, `max_cap_headroom`, `cap_unverified`, `shutdown`, or `fund_<status>` for a fund (`fund_open`, `fund_upcoming`). |
| `source` | The signal that decided it, e.g. `erc4626_max_deposit`, `euler_supply_cap`, `aave_supply_cap`, `lagoon_max_cap`, `centrifuge_fund_status`. For `unknown` it names the signal that was inconclusive; `null` when no signal applied. |
| `capacity_usd` | Remaining deposit capacity in USD when measurable; `0` when capped; `null` when unlimited or when the status is `unknown`. |
| `permission` | `permissionless`, `permissioned` (KYC, allowlist, or a deposit gate), or `unknown`. |

***

## Flow terms

`flow_terms` says how deposits and redemptions settle. The object is `null` when nothing is known.

| Field | Meaning |
| :- | :- |
| `deposit_flow` / `redemption_flow` | `sync` (settles in the same transaction), `async` (you submit a request and the vault settles it later), or `unknown`. |
| `settlement_seconds` | Typical wait for an async leg; `0` when both legs are sync. |
| `lockup_seconds` | Minimum holding period; `0` where the protocol has none by design. |
| `source` | Where the terms came from: `protocol_design`, `lagoon_api`, or `erc165_supports_interface` (ERC-7540 request-based vaults detected on-chain). |

A `sync` redemption can still be limited by available liquidity. See `pct_tvl_withdrawable` and the withdrawal signals in [Vault Risk Intelligence](https://docs.webacy.com/vault-risk-intelligence.md).

***

## Filtering and sorting

On the vault list (`GET /vaults`):

| Parameter | Use |
| :- | :- |
| `sort=apy_desc` | Rank by the standardized `apy`. |
| `sort=incentive_apr_desc` / `sort=durability_desc` | Rank vaults with a live Merkl incentive by incentive APR or durability score (vaults without one sort last). |
| `hasIncentives=true` | Only vaults with a live incentive. |
| `incentiveEndingWithinDays=30` | Only vaults whose live campaigns all end within that many days (1–365). |
| `durabilityTier=low` | Filter by durability tier: `high`, `medium`, `low`, `no_incentive`. |

***

## Example

Steakhouse High Yield USDC Edition (Morpho, Base). Excerpt of `metadata` from `GET /vaults/0xbeeff2490feffa212fac2f6553682c219e6a8845?chain=base`, trimmed to the fields on this page:

```json theme={null}
{
  "apy": 0.02909878,
  "apy_source": "onchain.share_price",
  "apy_measure": "realized_90d",
  "apy_native": 0.03161807619573665,
  "realized_apy_windows": {
    "realized_7d": 0.03150485,
    "realized_30d": 0.03046602,
    "realized_90d": 0.02909878
  },
  "fees": {
    "apy_after_fees": 0.02909878,
    "apy_before_fees": 0.03879837,
    "fee_gap_reason": null,
    "fee_treatment": "in_share_price",
    "fee_model": {
      "performance_bps": 2500,
      "management_bps": 0,
      "entry_bps": null,
      "exit_bps": null,
      "source": "morpho_api",
      "management_source": "morpho_api",
      "method": "fee_model_v1"
    }
  },
  "flow_terms": {
    "deposit_flow": "sync",
    "redemption_flow": "sync",
    "settlement_seconds": 0,
    "lockup_seconds": 0,
    "source": "protocol_design"
  },
  "incentives": {
    "incentive_source": "merkl",
    "incentive_apr": 0.02609344,
    "incentive_apr_liquid": 0.02609344,
    "incentive_apr_speculative": 0,
    "incentive_apr_restricted": 0.02609344,
    "incentive_share": 0.4526,
    "incentive_share_basis": "merkl_native",
    "incentive_streak_days": 133,
    "incentive_current_end": "2026-11-20T18:00:00Z",
    "incentive_campaigns_active": [
      {
        "apr": 0.01,
        "symbol": "MORPHO",
        "type": "TOKEN",
        "start": "2026-10-21T18:00:00Z",
        "end": "2026-11-20T18:00:00Z",
        "eligibility": "restricted",
        "hooks": ["COINBASE_ATTESTATION", "WHITELIST_CAMPAIGN"],
        "reward_quality": "volatile"
      }
    ],
    "yield_durability": {
      "score": 100,
      "tier": "high",
      "flags": ["restricted_incentive"],
      "drivers": {
        "method": "yield_durability_v1",
        "liquid_fraction": 0.5,
        "renewal": 0.4868,
        "funding": 1
      }
    }
  }
}
```

How to read it:

* The vault's realized APY is **2.91%**, annualized from its share-price change over the last 90 days and measured on-chain. Morpho's own figure is 3.16%.
* Before the curator's 25% performance fee, the annualized APY is **3.88%**, so fees cost 0.97 percentage points a year.
* Sponsors pay another **2.61%** in incentives, but all of it is restricted (Coinbase-verified depositors), so an ordinary depositor earns 2.91% and an eligible one about 5.52%. `incentive_apr` is the authoritative total: the listed campaign's own `apr` is 1%, and the rest is APR Merkl reports for the vault without attributing it to a listed campaign.
* Durability is `high` with `restricted_incentive`: for an ordinary depositor the yield is all base yield. `liquid_fraction` is 0.5 because no incentive is open to an ordinary depositor, so it has no effect on the score.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.