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:
| API | Use Case | Rewards Type | Data Provided |
|---|---|---|---|
| Morpho API | Vault/Market reward rates | Merkl only | APRs, reward token info, integrated with vault/market data |
| Merkl API | User claimable rewards | Merkl only | User balances, claim data, real-time rewards |
| Legacy Rewards | User claimable rewards | URD only | Deprecated. Use rewards-legacy.morpho.org |
- Use Morpho API for displaying reward APRs on vaults/markets
- Use Merkl API for user-specific Merkl rewards
- 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
}
}
}
}{
"address": "0xb576765fB15505433aF24FEe2c0325895C559FB2",
"chainId": 1
}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.
- Use
vaultV2ByAddressfor 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
}
}
}
}
}
}supplyApr: Reward APR for suppliersborrowApr: 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}curl "https://api.merkl.xyz/v4/userRewards?user=0x1234...5678"{
"1": { // Chain ID
"0xVAULT_OR_MARKET_ADDRESS": {
"claimable": {
"0xREWARD_TOKEN_ADDRESS": {
"accumulated": "1234567890",
"unclaimed": "1234567890",
"symbol": "MORPHO",
"decimals": 18
}
}
}
}
}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
- 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:
| API | Rate Limit | Notes |
|---|---|---|
| Morpho API | 5k / 5 min | Use responsibly |
| Merkl API | 10 request / second | Cache responses |
Best Practice: Cache aggressively and fetch only when needed.
Next Steps
- Display rewards: Follow the Integrate Display tutorial
- Enable claiming: See the Claim Rewards tutorial
- Full example: Check out the Complete Integration Guide
Resources
- Morpho API Playground: api.morpho.org/graphql
- Merkl Docs: docs.merkl.xyz/integrate-merkl/app
- Legacy Rewards Lookup: rewards-legacy.morpho.org
- Example Code: morpho-org/merkl-morpho-recipe
