Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Fetch Rewards Data

This tutorial shows you how to fetch reward information for Morpho Vaults and Markets from both Merkl API and Morpho API. Understanding how to query both systems is essential for displaying complete reward information to your users.

What You'll Learn

  • How to fetch Vault V2 reward rates from Morpho API
  • How to query user-specific rewards from Merkl API
  • How to combine data from multiple sources for a complete picture

Prerequisites

  • Basic understanding of Reward Programs
  • Familiarity with REST and GraphQL APIs
  • A tool for making API requests (curl, fetch, axios, or GraphQL client)

API Landscape Overview

There are two main APIs for rewards data:

APIUse CaseRewards TypeData Provided
Morpho APIVault/Market reward ratesMerkl onlyAPRs, reward token info, integrated with vault/market data
Merkl APIUser claimable rewardsMerkl onlyUser balances, claim data, real-time rewards
Legacy RewardsUser claimable rewardsURD onlyDeprecated. Use rewards-legacy.morpho.org
Recommended Strategy:
  1. Use Morpho API for displaying reward APRs on vaults/markets
  2. Use Merkl API for user-specific Merkl rewards
  3. For legacy URD rewards, direct users to rewards-legacy.morpho.org

Fetching Morpho Vault V2 Rewards

Using Morpho API

Morpho Vault V2 rewards are pre-aggregated by the API. The rewards field on a Morpho Vault V2 already includes all reward sources across its supported adapters.

query VaultV2Rewards($address: String!, $chainId: Int!) {
  vaultV2ByAddress(address: $address, chainId: $chainId) {
    address
    name
    symbol
    apy
    netApy  # Complete APY including all rewards
 
    # Pre-aggregated rewards from all sources
    rewards {
      supplyApr
      asset {
        address
        symbol
        price {
          usd
        }
      }
    }
 
    # Adapters show where the vault allocates
    adapters {
      items {
        type      # Adapter type (liquidity, market, and other supported adapters)
        address
        assetsUsd
      }
    }
  }
}
Variables example:
{
  "address": "0xb576765fB15505433aF24FEe2c0325895C559FB2",
  "chainId": 1
}
Returned fields:

Fields below are returned as decimals (e.g. 0.05 = 5%).

  • apy: Current APY of the vault (before fees), derived from liquidity adapter rates.
  • netApy: Current net APY of the vault (after fees, including rewards), derived from liquidity adapter rates.
  • rewards[].supplyApr: APR for each reward token.
Key Integration Notes:
  • Use vaultV2ByAddress for Vault V2 reward queries
  • APY and rewards fields are at the top level of the response
  • No manual aggregation needed: the API pre-aggregates rewards from supported adapters

Fetching Market Rewards

Markets can have rewards for supply and borrow.

Using Morpho API

query MarketRewards($marketId: String!, $chainId: Int!) {
  marketById(marketId: $marketId, chainId: $chainId) {
    marketId
    loanAsset {
      symbol
    }
    collateralAsset {
      symbol
    }
    state {
      borrowApy
      supplyApy
      rewards {
        supplyApr
        borrowApr
        asset {
          address
          symbol
          price {
            usd
          }
        }
      }
    }
  }
}
Key Fields:
  • supplyApr: Reward APR for suppliers
  • borrowApr: Reward APR for borrowers (often negative, meaning borrowers earn rewards)

Fetching User-Specific Rewards

Merkl API (Current Programs)

To get a user's claimable Merkl rewards:

Endpoint:
GET https://api.merkl.xyz/v4/userRewards?user={address}
Example:
curl "https://api.merkl.xyz/v4/userRewards?user=0x1234...5678"
Response Structure:
{
  "1": {  // Chain ID
    "0xVAULT_OR_MARKET_ADDRESS": {
      "claimable": {
        "0xREWARD_TOKEN_ADDRESS": {
          "accumulated": "1234567890",
          "unclaimed": "1234567890",
          "symbol": "MORPHO",
          "decimals": 18
        }
      }
    }
  }
}
TypeScript Example:
async function fetchMerklRewards(userAddress: string) {
  const response = await fetch(
    `https://api.merkl.xyz/v4/userRewards?user=${userAddress}`
  );
  const data = await response.json();
 
  // Parse rewards by chain
  const chainId = 1; // Ethereum mainnet
  const rewards = data[chainId] || {};
 
  // Aggregate all claimable rewards
  const claimableByToken: Record<string, bigint> = {};
 
  for (const [campaignAddress, campaignData] of Object.entries(rewards)) {
    for (const [tokenAddress, tokenData] of Object.entries(
      campaignData.claimable || {}
    )) {
      const unclaimed = BigInt(tokenData.unclaimed || "0");
      claimableByToken[tokenAddress] =
        (claimableByToken[tokenAddress] || 0n) + unclaimed;
    }
  }
 
  return claimableByToken;
}

Legacy Rewards (Pre-Merkl)

Performance Considerations

Caching

Vault/Market Rewards (Morpho API):
  • Cache for 5-15 minutes
  • Rewards rates change infrequently
User Merkl Rewards:
  • Cache for 5-10 minutes
  • Updates every 8 hours, but users expect fresh data

Parallel Fetching

Always fetch from multiple APIs in parallel:

const [vaultData, merklRewards] = await Promise.all([
  fetchVaultFromMorphoAPI(vaultAddress),
  fetchMerklRewards(userAddress),
]);

Error Handling

async function fetchRewardsSafely(userAddress: string) {
  try {
    const merkl = await fetchMerklRewards(userAddress);
    return merkl;
  } catch (error) {
    console.error("Merkl API error:", error);
    return {}; // Fallback to empty
  }
}

API Rate Limits

Be mindful of rate limits:

APIRate LimitNotes
Morpho API5k / 5 minUse responsibly
Merkl API10 request / secondCache responses

Best Practice: Cache aggressively and fetch only when needed.

Next Steps

Resources