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 | REJECTEDPosition value accrues yield continuously and is already included in getPortfolio() /
getTreasuryOverview() — deployed funds never leave the org's books.
A durable, server-to-server record of every deposit, withdrawal, and claim.
Subscribe to Order.* events on the earn domain — the same
Submitted → Approved → Broadcast → Confirmed sequence every vertical shares. Registration and
signature verification are in the webhooks guide.
The same events, live — for a dashboard that wants push without a receiver.
Same subscription and scoping rules as webhooks — see the WebSockets guide. Live-only: an event published while you're disconnected is missed, so pair this with polling or webhooks rather than relying on it alone.
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).