Skip to main content
This recipe walks through the end-to-end flow: deploying a vault, depositing funds, checking positions, withdrawing with accrued yield, and claiming reward incentives. Support for gas sponsorship and policies is coming soon.
Earn is an Enterprise feature. Reach out to [email protected] to request access.

Prerequisites

1. Deploy a fee vault

Configure a fee vault from the Wallet infrastructure > Earn page in the Privy Dashboard. During setup, you will set:
  1. A Morpho vault to allocate assets into
  2. The percentage of generated yield your app receives
  3. An admin wallet to claim fees and manage your vault configuration
If the admin wallet is not a Privy embedded wallet, it must be able to sign onchain transactions to manage the vault and claim fees. Exchange wallets, cold storage, and other non-signing wallets are not supported. Once set, Privy cannot reassign the admin wallet.
Privy assigns all fee vault roles to the admin wallet. This ensures that developers can update their fee vault configurations in the future. Learn more about fee vault roles here. Reach out to [email protected] to make fee vault configuration changes.

2. Copy the vault ID

After setup, Privy provides a unique vault_id for the vault. Copy this value — it is required for all deposit and withdraw API calls. To verify the vault is live, query its details with the get vault details endpoint:
curl https://auth.privy.io/api/v1/ethereum_yield_vault/{vault_id} \
  -H "privy-app-id: <your-app-id>" \
  -H "Authorization: Basic <credentials>"
Example response
{
  "id": "cm7oxq1el000e11o8iwp7d0d0",
  "name": "Gauntlet USDC Prime",
  "provider": "morpho",
  "vault_address": "0x04422053aDDbc9bB2759b248B574e3FCA76Bc145",
  "asset_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  "caip2": "eip155:1",
  "user_apy": 500,
  "tvl_usd": 1000000,
  "available_liquidity_usd": 500000
}

3. Deposit funds into the vault

Wallets with owner_id present must provide an authorization signature as a request header for deposit, withdraw, and claim operations.
Deposit assets from a wallet into the vault using the deposit endpoint. Privy handles the ERC-20 approval and deposit in a single call. The wallet depositing funds and the admin wallet will receive shares corresponding to the fee share split.
curl -X POST https://auth.privy.io/api/v1/wallets/{wallet_id}/ethereum_yield_deposit \
  -H "privy-app-id: <your-app-id>" \
  -H "Authorization: Basic <credentials>" \
  -H "Content-Type: application/json" \
  -d '{
    "vault_id": "cm7oxq1el000e11o8iwp7d0d0",
    "asset_amount": "1000000"
  }'
asset_amount is specified in the token’s smallest unit. For USDC (6 decimals), "1000000" equals 1 USDC.
The response includes an operation id and a status of "pending". Poll the status with get sweep by ID, or listen for the yield.deposit.confirmed webhook to know when the deposit is confirmed onchain.
Example response
{
  "id": "cm7oxq1el000e11o8iwp7d0d0",
  "wallet_id": "fmfdj6yqly31huorjqzq38zc",
  "vault_id": "cm7oxq1el000e11o8iwp7d0d0",
  "type": "deposit",
  "status": "pending",
  "asset_amount": "1000000",
  "share_amount": null,
  "created_at": 1631573050000,
  "updated_at": 1631573050000
}

4. Check a wallet’s position

After a deposit is confirmed, query the wallet’s holdings using the get position endpoint. The assets_in_vault field reflects the current redeemable value, including any accrued yield.
curl https://auth.privy.io/api/v1/wallets/{wallet_id}/ethereum_yield_vault?vault_id={vault_id} \
  -H "privy-app-id: <your-app-id>" \
  -H "Authorization: Basic <credentials>"
Example response
{
  "asset": {
    "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "symbol": "USDC"
  },
  "total_deposited": "1000000",
  "total_withdrawn": "0",
  "assets_in_vault": "1050000",
  "shares_in_vault": "1000000000000000000"
}
Calculating yield: compare assets_in_vault to net contributions (total_deposited - total_withdrawn). The difference is the earned yield.

5. Withdraw funds from the vault

Redeem vault shares and return assets — plus any accrued yield — to the wallet using the withdraw endpoint. The returned asset_amount reflects the original deposit plus yield earned.
curl -X POST https://auth.privy.io/api/v1/wallets/{wallet_id}/ethereum_yield_withdraw \
  -H "privy-app-id: <your-app-id>" \
  -H "Authorization: Basic <credentials>" \
  -H "Content-Type: application/json" \
  -d '{
    "vault_id": "cm7oxq1el000e11o8iwp7d0d0",
    "asset_amount": "1050000"
  }'
Track the withdrawal by polling get sweep by ID or listening for the yield.withdraw.confirmed webhook.
Example response
{
  "id": "cm7oxq1el000e11o8iwp7d0d0",
  "wallet_id": "fmfdj6yqly31huorjqzq38zc",
  "vault_id": "cm7oxq1el000e11o8iwp7d0d0",
  "type": "withdraw",
  "status": "pending",
  "asset_amount": "1050000",
  "share_amount": null,
  "created_at": 1631573050000,
  "updated_at": 1631573050000
}

6. Claim reward incentives

Some vaults distribute additional token incentives on top of base yield. Collect these with the claim endpoint. Claims operate at the chain level — pass a CAIP-2 identifier rather than a vault ID. For apps with multiple vaults on the same chain, a single claim collects rewards across all vaults.
curl -X POST https://auth.privy.io/api/v1/wallets/{wallet_id}/ethereum_yield_claim \
  -H "privy-app-id: <your-app-id>" \
  -H "Authorization: Basic <credentials>" \
  -H "Content-Type: application/json" \
  -d '{
    "caip2": "eip155:8453"
  }'
Track the claim by polling get claim by ID or listening for the yield.claim.confirmed webhook.
Example response
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "caip2": "eip155:8453",
  "status": "pending",
  "rewards": [
    {
      "token_address": "0x1234567890abcdef1234567890abcdef12345678",
      "token_symbol": "MORPHO",
      "amount": "115631364898103632676"
    }
  ],
  "created_at": 1631573050000,
  "updated_at": 1631573050000
}
Claiming rewards is separate from withdrawing yield. To realize deposit earnings, use the withdraw endpoint. Claiming does not affect withdrawals or ongoing earnings.
Privy emits webhooks when vault operations are confirmed onchain. Subscribe to earn events from the Configuration > Webhooks page in the Privy Dashboard to keep your app synchronized without polling.
EventFired when
yield.deposit.confirmedA vault deposit is confirmed onchain
yield.withdraw.confirmedA vault withdrawal is confirmed onchain
yield.claim.confirmedA reward claim transaction is confirmed onchain
For full webhook setup instructions and payload schemas, see the webhooks overview.

Next steps