Fetch Rewards Data
Fetch a user's Morpho Vault and Market rewards from the Merkl API, with caching and error handling.
This tutorial shows how to fetch a user's Morpho Vault and Market rewards from the Merkl API.
What You'll Learn
- How to query user-specific rewards from Merkl API
- Handle caching and errors for user-specific reward data
Prerequisites
- Basic understanding of Reward Programs
- Familiarity with REST APIs
- A tool for making API requests (curl, fetch, or axios)
API Landscape Overview
For current user rewards, use the Merkl API:
| API | Use Case | Rewards Type | Data Provided |
|---|---|---|---|
| Morpho REST API | Known token metadata | Token data | For a known token, use GET /v0/tokens/{token-selector} |
| 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 |
Recommended Strategy:
- Use Merkl API for user-specific claimable rewards.
- For legacy URD rewards, direct users to rewards-legacy.morpho.org
Fetching User-Specific Rewards
Merkl API (Current Programs)
To get a user's claimable Merkl rewards:
Endpoint:
GET https://api.merkl.xyz/v4/users/{address}/rewards?chainId={chainId}Example:
curl "https://api.merkl.xyz/v4/users/0x1234...5678/rewards?chainId=1"Response Structure:
[
{
"chain": { "id": 1, "name": "Ethereum" },
"rewards": [
{
"token": { "address": "0xREWARD_TOKEN", "symbol": "MORPHO", "decimals": 18 },
"amount": "2000000000000000000",
"claimed": "1000000000000000000",
"pending": "0",
"proofs": ["0xproof1", "0xproof2"]
}
]
}
]The response is an array of per-chain objects, each with a rewards array. A token's currently-claimable balance is amount - claimed (both are cumulative). pending is reward not yet in a live merkle root.
TypeScript Example:
async function fetchMerklRewards(userAddress: string, chainId: number) {
const response = await fetch(
`https://api.merkl.xyz/v4/users/${userAddress.toLowerCase()}/rewards?chainId=${chainId}`
);
const data = await response.json();
// The endpoint returns an array of per-chain objects; flatten to a list of rewards.
const rewards = data.flatMap((entry) => entry.rewards);
// Aggregate the unclaimed balance per token (amount - claimed)
const claimableByToken: Record<string, bigint> = {};
for (const reward of rewards) {
const unclaimed = BigInt(reward.amount) - BigInt(reward.claimed);
claimableByToken[reward.token.address] =
(claimableByToken[reward.token.address] || 0n) + unclaimed;
}
return claimableByToken;
}Legacy Rewards (Pre-Merkl)
Performance Considerations
Caching
User Merkl Rewards:
- Cache for 5-10 minutes
- Updates every 8 hours, but users expect fresh data
Parallel Fetching
When fetching rewards for multiple users, independent Merkl requests can run in parallel.
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
Resources
- Merkl Docs: docs.merkl.xyz/integrate-merkl/app
- Legacy Rewards Lookup: rewards-legacy.morpho.org
Merkl Distribution System
Understand Merkl's offchain reward calculations, Merkle tree distribution, and user claims, with integration points for Morpho reward data.
Create a Rewards Program
Create a Morpho Vault or market reward program with Merkl, then check which campaign types the Morpho App displays.