Skip to main content
Portfolio Wallets earn yield from multiple sources with different accrual mechanics. This guide explains how yield is computed and how to use the yield endpoint for detailed reporting.

How yield accrues

All yield sources are variable-rate. Rates change over time based on market conditions and protocol performance. These positions appreciate in value over time. When you deposit USDC, it is converted into the underlying yield token or vault shares at the current exchange rate. As the protocol earns yield, the NAV (net asset value) per share increases, making those shares worth more USDC. The wallet’s balance.totalUsd reflects the current market value of all positions, so NAV appreciation is automatically captured in the balance.

Wallet-level earnings

Yield is reported at the wallet level, not per position. This is because rebalances move funds between positions over time, making per-position attribution misleading. The earnedUsd field represents lifetime yield earned across all positions since the wallet was created. It is computed internally using per-position yield accrual tracking rather than a simple deposit/withdrawal accounting formula, so it accurately reflects actual yield even through rebalances and partial withdrawals. Yield does not move on the same cadence for every source:
  • syrup-usdc updates continuously from live onchain share-to-assets conversion.
  • Morpho ERC-4626 vaults exposed by the live catalog update continuously from live onchain ERC-4626 conversion reads.
For the simple case of one completed deposit and no returned principal, balance.totalUsd = depositUsd + balance.earnedUsd exactly to the smallest USDC unit.

The yield endpoint

Use GET /v2/wallets/:id/yield for a detailed yield breakdown:
curl -X GET "$BASE_URL/v2/wallets/$WALLET_ID/yield" \
  -H "Authorization: Bearer $API_TOKEN"
{
  "walletId": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db",
  "earnedUsd": "250.000000",
  "currentBalanceUsd": "82500.000000",
  "positions": [
    {
      "yieldSourceId": "syrup-usdc",
      "name": "Syrup USDC",
      "apyBps": 453,
      "pct": 40
    },
    {
      "yieldSourceId": "morpho-gauntlet-usdc",
      "name": "Morpho Gauntlet USDC Prime",
      "apyBps": 472,
      "pct": 30
    },
    {
      "yieldSourceId": "morpho-steakhouse-usdc",
      "name": "Morpho Steakhouse USDC Prime",
      "apyBps": 468,
      "pct": 30
    }
  ]
}

Response fields

FieldDescription
earnedUsdCumulative yield earned (same as balance.earnedUsd on the wallet)
currentBalanceUsdCurrent total wallet balance
positionsPer-source APY and allocation breakdown

Yield source fields

FieldDescription
yieldSourceIdIdentifier for the yield source
nameDisplay name
apyBpsCurrent annualized yield in basis points (100 bps = 1%). null if unavailable.
pctTarget allocation percentage for this source in the wallet’s strategy

Displaying yield to users

  1. Total earned — use balance.earnedUsd from the wallet response or earnedUsd from the yield endpoint
  2. Current APY — compute a blended APY from the yield endpoint’s positions array:
    blendedApyBps = sum(source.apyBps * source.pct / 100) for each source
    
  3. Yield breakdown — show each yield source’s name, apyBps, and pct from the yield endpoint

Important notes

  • Ground surfaces annualized rates in apyBps, but the methodology varies by source. Syrup and Morpho vaults do not use identical lookback windows.
  • Balances may briefly lag deposits or withdrawals due to caching. See Balances and Yield for valuation notes.
  • earnedUsd is lifetime. It remains monotonic even when individual source valuations update on different cadences.