MOONEUM
Earn yield across DeFi protocols

Earn API

Deploy idle treasury funds into Aave, Lido, and Morpho programmatically — without leaving custody or approval controls behind.

Requires a key or token scoped to Earn. A common integration pattern is a scheduled job that sweeps balances above a buffer into a vetted opportunity — everything below is safe to run unattended, since deposits and withdrawals still route through your org's policy and approvals.

Opportunities & deposits

Browse opportunities

const { opportunities } = await client.listEarnOpportunities({
  chain: 'ethereum',
  sort: 'apy',
});
// -> [{ id, protocol, protocolId, category, chain, asset, apy, tvl, risk }, ...]

const { protocols } = await client.listEarnProtocols(); // ["aave", "lido", "morpho"]

listEarnOpportunities also filters by category and asset; your org's policies can further restrict which protocols and assets are usable regardless of what this list returns.

Deposit — an order, like everything else

const order = await client.createEarnOrder({
  walletId,
  chain: 'ethereum',
  protocol: 'aave',
  opportunityId,
  action: 'DEPOSIT', // or 'WITHDRAW'
  assetSymbol: 'USDC',
  amount: '50000',
  amountRaw: '50000000000',
});
await client.submitEarnOrder(order.id);

The order flows through approvals and signing — see Approvals & signing — and emits Order.* events on the earn domain along the way.

Track a position

Read live value and APY whenever you need it.

const { positions } = await client.getEarnPositions(walletAddress);
// -> [{ protocol, asset, shares, underlying, usdValue, apy, pendingRewards }, ...]

const order = await client.getEarnOrder(orderId);
// order.status -> DRAFT | PENDING_APPROVAL | APPROVED | BROADCAST | CONFIRMED | FAILED | REJECTED

Position value accrues yield continuously and is already included in getPortfolio() / getTreasuryOverview() — deployed funds never leave the org's books.

Withdraw & claim

Withdrawals are action: 'WITHDRAW' orders through the same create → submit flow as a deposit.

Lido is two-step

Unstaking ETH from Lido is claim-based: the withdraw order enters the protocol's exit queue, and a follow-up CLAIM leg completes it once the queue clears. Watch the order's legs — Order.* events carry a leg field (MAIN / CLAIM) — rather than assuming a single transaction.

Recurring deposits

await client.createRecurringEarnOrder({
  walletId,
  chain: 'ethereum',
  protocol: 'aave',
  opportunityId,
  action: 'DEPOSIT',
  assetSymbol: 'USDC',
  amount: '10000',
  interval: 'WEEKLY',
});

Each run is a fresh order through policy and approvals — changing the org's rules changes the job's behavior with no code change. Manage schedules with listRecurringEarnOrders, toggleRecurringEarnOrder(id, enabled), and removeRecurringEarnOrder(id).