Skip to main content

Overview

Yield.xyz is the ultimate yield infrastructure for Web3, providing one unified API for every yield across 75+ networks. Instead of building and maintaining your own vaults or integrating directly with individual DeFi protocols like Morpho, Aave, or Lido, you can integrate Yield.xyz once and unlock 1,000+ standardized opportunities across staking, lending, and DeFivaults. Yield.xyz’s API is self-custodial by design: it constructs ready-to-sign transactions for yield actions but leaves execution and signing entirely in your control. You fetch opportunities and action flows from Yield.xyz, and have Turnkey sign and broadcast them under your policy-controlled keys.

Why Yield.xyz instead direct protocol integrations?

  • No protocol maintenance – skip deploying/managing your own vaults or building dozens of one-off integrations.
  • Unified API – discover, enter, exit, manage, and track positions across 75+ chains and 1,500+ yields with one interface.
  • Web2 Style UX — full abstraction of Web3 complexity via Optimized Allocator Vaults (OAVs) which automatically offramp and reinvest any incentive token issued by any protocol. Additional features include charging of deposit, management, and/or performance fees, as well as modules for e.g. cross chain routing.
  • Pre-configured OAVs – instantly offer access to 10–20 standardized and pre-configured Optimized Allocator Vaults (“grab-off-the-shelf”) across popular assets.
  • Custom OAVs – request dedicated OAVs for specific strategies or branded products.
  • Monetization – ability to layer on additional user-level fees per OAV as well as revenue sharing from validators on all staking integrations
    • Note: Yield.xyz enforces a minimum 10% fee
    • Note: the validator revenue share is applicable only to PVN members (>30 of the largest validator service providers)
  • Security & control – Turnkey enforces transaction policies so client keys can only interact with the exact vaults/tokens you allow.
By combining Yield.xyz and Turnkey, you deliver a production-ready yield experience in your app with minimal effort: your users can discover, deposit, track, manage, and withdraw – all signed securely with Turnkey. The working example can be found here.

Getting started

Follow the Turnkey Quickstart to set up:
  • Organization ID – logical grouping of resources( e.g. users, wallets, policies).
  • Root quorum user – a root user with an API key pair.
  • Non-Root User – a secondary user (with its own API key) outside the root quorum.
  • Wallet – hierarchical deterministic (HD) wallet having at least an Ethereum wallet account.
  • Turnkey Client & Signer – initialize a Turnkey client (TurnkeyClient) with your API key pair and connect a signer (TurnkeySigner) from @turnkey/ethers to your RPC provider.
After creating a non-root user with a different API key, the next step is to remove it from the root quorum. You can do this from the Turnkey dashboard or API. Here’s a simple script that shows how to update the root quorum using @turnkey/sdk-server. Also, make sure you have a wallet with an Ethereum account created within this organization and have it funded with some ETH and USDC on Base Mainnet. Follow the Yield Project Setup to create:
  • Yield API KEY – to make authenticated requests to the Yield.xyz API.
Once configured, you’ll be able to:
  1. Discover available yields with GET /v1/yields.
  2. Act on them with POST /v1/actions/{enter|exit|manage}.
  3. Track balances and status with GET /v1/yields/{id}/balances 

Setting up the policies for the non-root user

Now, we want to use the non-root user for signing transactions to Yield.xyz and restrict it to only be able to interact with the USDC and Yield vault smart contracts. We’ll define a new API client that uses the organization’s root user to create the required policies.
Each policy uses the eth.tx.data field to identify which smart contract function is being called. The first four bytes of this field represent the function selector. For the approve function, the selector is 0x095ea7b3; for deposit it is 0x6e553f65; and for withdraw, it’s 0xba087652. This allows the policies to precisely restrict the non-root user to only those permitted contract calls.
import { Turnkey } from "@turnkey/sdk-server";
import * as dotenv from "dotenv";
import * as path from "path";

// Load environment variables from `.env.local`
dotenv.config({ path: path.resolve(process.cwd(), ".env.local") });

async function main() {
  const turnkeyClient = new Turnkey({
    apiBaseUrl: "https://api.turnkey.com",
    apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY!,
    apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY!,
    defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID!,
  }).apiClient();

  // The id of the non-root user that you'll be using to sign the Yield related transactions
  const userId = process.env.NONROOT_USER_ID!;

  //approval policy
  const approvalPolicy = {
    policyName:
      "Allow API key user to call the approve function on the USDC_ADDRESS",
    effect: "EFFECT_ALLOW" as const,
    consensus: `approvers.any(user, user.id == '${userId}')`,
    condition: `eth.tx.to == '${process.env.USDC_ADDRESS}' && eth.tx.data[0..10] == '0x095ea7b3'`,
    notes: "",
  };

  const { policyId: approvalPolicyId } =
    await turnkeyClient.createPolicy(approvalPolicy);

  console.log(
    [
      `Created approval policy:`,
      `- Name: ${approvalPolicy.policyName}`,
      `- Policy ID: ${approvalPolicyId}`,
      `- Effect: ${approvalPolicy.effect}`,
      `- Consensus: ${approvalPolicy.consensus}`,
      `- Condition: ${approvalPolicy.condition}`,
      ``,
    ].join("\n"),
  );

  //deposit policy
  const depositPolicy = {
    policyName:
      "Allow API key user to call the deposit function on the gtUSDCf_VAULT_ADDRESS",
    effect: "EFFECT_ALLOW" as const,
    consensus: `approvers.any(user, user.id == '${userId}')`,
    condition: `eth.tx.to == '${process.env.gtUSDCf_VAULT_ADDRESS}' && eth.tx.data[0..10] == '0x6e553f65'`,
    notes: "",
  };

  const { policyId: depositPolicyId } =
    await turnkeyClient.createPolicy(depositPolicy);

  console.log(
    [
      `Created deposit policy:`,
      `- Name: ${depositPolicy.policyName}`,
      `- Policy ID: ${depositPolicyId}`,
      `- Effect: ${depositPolicy.effect}`,
      `- Consensus: ${depositPolicy.consensus}`,
      `- Condition: ${depositPolicy.condition}`,
      ``,
    ].join("\n"),
  );

  //withdraw policy
  const withdrawPolicy = {
    policyName:
      "Allow API key user to call the withdraw function on the gtUSDCf_VAULT_ADDRESS",
    effect: "EFFECT_ALLOW" as const,
    consensus: `approvers.any(user, user.id == '${userId}')`,
    condition: `eth.tx.to == '${process.env.gtUSDCf_VAULT_ADDRESS}' && eth.tx.data[0..10] == '0xba087652'`,
    notes: "",
  };

  const { policyId: withdrawPolicyId } =
    await turnkeyClient.createPolicy(withdrawPolicy);

  console.log(
    [
      `Created withdraw policy:`,
      `- Name: ${withdrawPolicy.policyName}`,
      `- Policy ID: ${withdrawPolicyId}`,
      `- Effect: ${withdrawPolicy.effect}`,
      `- Consensus: ${withdrawPolicy.consensus}`,
      `- Condition: ${withdrawPolicy.condition}`,
      ``,
    ].join("\n"),
  );
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

Discover a yield (with metadata)

Discovery is just a read to the Yield.xyz API — Turnkey doesn’t change this step. You’ll typically do it server-side (to keep your Yield API key secret), then surface the results to your app where you’ll later enter using your Turnkey signer. Example: USDC yields on Base
const res = await fetch(
  'https://api.yield.xyz/v1/yields?network=base&token=USDC&limit=10',
  { headers: { 'X-API-KEY': process.env.YIELD_API_KEY! } }
);
const result = (await res.json()) as any; 
const items = result.items 

// pick one yield
const selected = items[0];
const YIELD_ID = selected.id;

// metadata is included in the object
const apy = selected.rewardRate;
const token = selected.token;
const metadata = selected.metadata;

Exemplary Yields

To simplify integration, Yield.xyz provides a set of ready-to-use yields across both Stablecoins/DeFi and staking — designed to offer clean UX, consistent APIs, and monetization support. These yields are already live and have seen significant adoption across our clients.
Stablecoin/DeFi Yields The Stablecoin/DeFi yields provided here are wrapped using Optimized Allocator Vaults (OAVs), which automatically handle:
  • Incentive off-ramping & reinvestment
  • Asset wrapping (where applicable)
  • Fee charging (performance, management, deposit)
This makes OAVs unique: they enable fee capture for partners while simultaneously simplifying the user experience, ensuring yield products feel as seamless as mainstream fintech offerings. We’ve deployed two sets of OAVs with pre-configured fees — available via API Keys:
  • 10% fee OAVs: 4bea9274-7cef-4e43-995b-f35147469ede
  • 20% fee OAVs: e35de2d4-93e2-4cf8-b016-b0838fec1f20
For reference, the expanded list of yields most popular among existing clients (already wrapped into OAVs) can be found here.
Yield IDYield NameProtocolMonetization
arbitrum-usdc-gtusdcc-0x7e97fa6893871A2751B5fE961978DCCb2c201E65-4626-vaultGauntlet USDC CoreMorphoAvailable deposit, performance, management fees
ethereum-usds-susds-0xa3931d71877c0e7a3148cb7eb4463524fec27fbd-4626-vaultUSDS Sky Savings RateSkyAvailable deposit, performance, management fees
ethereum-usdc-fusdc-0x9Fb7b4477576Fe5B32be4C1843aFB1e55F251B33-4626-vaultFluid USDC VaultFluidAvailable deposit, performance, management fees
base-usdc-smusdc-0x616a4e1db48e22028f6bbf20444cd3b8e3273738-4626-vaultSeamless USDC VaultMorphoAvailable deposit, performance, management fees
base-usdc-aave-v3-lendingUSDC Aave LendingAaveAvailable deposit, performance, management fees
Staking Yields These staking yields are accessible via Yield.xyz, which:
  • Enables delegations to any active validator
  • Supports validator revenue sharing (50–85% of validator fees) with preferred validators
  • Standardizes interactions across networks (undelegation, cooldowns, reward tracking)
Yield IDNetworkExemplary ValidatorValidator AddressMonetization
solana-sol-native-multivalidator-stakingSolanaMeriaH2tJNyMHnRF6ahCQLQ1sSycM4FGchymuzyYzUqKEuydkDeposit fees and revenue share
tron-trx-native-stakingTronLuganodesTGyrSc9ZmTdbYziuk1SKEmdtCdETafewJ9Revenue share
bsc-bnb-native-stakingBinanceFigment0x477cB5d87144b2a6d93f72e32f5E01a459260D68Revenue share
ethereum-eth-everstake-stakingEthereumEverstakeN/ARevenue share
ethereum-eth-figment-stakingEthereumFigmentN/ARevenue share
hyperevm-hype-native-stakingHyperliquidMeria0x950f8dd5e5030e1fa6ad2cdc4295809d185925d0Revenue share
cosmos-atom-native-stakingCosmosChorus Onecosmosvaloper15urq2dtp9qce4fyc85m6upwm9xul3049e02707Deposit fees and revenue share
The full list of staking yields can be found in the Yield.xyz docs. Full Yield List For the full list of live yields (DeFi + staking), you can: → View the Yield.xyz Dashboard → Query via the Yield API as showcased in the above “Discover a yield” section.

Enter the yield (deposit via Yield.xyz)

First, we’ll call the Yield.xyz POST /v1/actions/enter endpoint to get the transactions required to enter the Morpho USDC vault on Base. We need to specify the yield ID for this vault, the amount to deposit, and our wallet address. For example, Yield.xyz’s identifier for Morpho’s Base USDC vault might be "base-usdc-gtusdcf-0x236919f11ff9ea9550a4287696c2fc9e18e6e890-4626-vault"(you can discover yield IDs via the Yield.xyz API or docs). We’ll deposit 0.5 USDC in this example. The code below calls the Yield.xyz API (using a fetch request; you could also use Yield.xyz’s SDK) and retrieves the transactions. It then uses the non-root Turnkey user to sign and send each transaction in sequence:
import * as path from "path";
import * as dotenv from "dotenv";
import { ethers } from "ethers";
import { TurnkeySigner } from "@turnkey/ethers";
import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server";

// Load environment variables from `.env.local`
dotenv.config({ path: path.resolve(process.cwd(), ".env.local") });

async function main() {
  // Initialize the Turnkey client
  const turnkeyClient = new TurnkeyServerSDK({
    apiBaseUrl: "https://api.turnkey.com",
    apiPublicKey: process.env.NONROOT_API_PUBLIC_KEY!,
    apiPrivateKey: process.env.NONROOT_API_PRIVATE_KEY!,
    defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID!,
  });

  // Initialize the Turnkey Signer
  const turnkeySigner = new TurnkeySigner({
    client: turnkeyClient.apiClient(),
    organizationId: process.env.TURNKEY_ORGANIZATION_ID!,
    signWith: process.env.SIGN_WITH!,
  });

  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL!);
  const connectedSigner = turnkeySigner.connect(provider);

  // Prepare entry via Yield.xyz
  const depositAmount = "0.5";
  const enterPayload = {
    yieldId: process.env.YIELD_ID!, // e.g."base-usdc-gtusdcf-0x236919f11ff9ea9550a4287696c2fc9e18e6e890-4626-vault"
    address: process.env.SIGN_WITH!,
    arguments: { amount: depositAmount },
  };

  const enterRes = await fetch("https://api.yield.xyz/v1/actions/enter", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": process.env.YIELD_API_KEY!,
    },
    body: JSON.stringify(enterPayload),
  });
  const action = await enterRes.json();
  console.log("Yield API response:", JSON.stringify(action, null, 2));

  // Sign and broadcast each transaction step
  for (const tx of action.transactions) {
    const unsignedTx = JSON.parse(tx.unsignedTransaction);
    const sent = await connectedSigner.sendTransaction({
      to: unsignedTx.to,
      data: unsignedTx.data,
      value: unsignedTx.value ?? "0x0",
      chainId: unsignedTx.chainId,
    });
    console.log("Broadcasted tx:", sent.hash);
    await sent.wait(); //waiting for the approve transaction to be mined
  }
}

main().catch((err) => {
  console.error("Error running Yield deposit example:", err);
  process.exit(1);
});
In the above flow, the first transaction is an ERC-20 approval allowing the vault contract to spend 0.5 USDC on our behalf, and the second is the actual deposit into the vault. Yield.xyz figured out these steps for us – we didn’t have to manually craft the token approve or vault deposit call (no need to find contract ABIs or addresses ourselves). After executing these, our USDC is now deposited and earning yield in the vault.

Check user balance

After depositing, we can query the Yield.xyz API to confirm our position and even fetch the current yield stats. Yield.xyz provides a portfolio endpoint to get a unified view of a user’s balances in any yield.
const balanceRes = await fetch(
  `https://api.yield.xyz/v1/yields/${yieldId}/balances`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": process.env.YIELD_API_KEY!,
    },
    body: JSON.stringify({ address: turnkeyAccount.address }),
  }
);
const balances = await balanceRes.json();
console.log("Vault balances:", JSON.stringify(balances, null, 2));
The response will include the amount of USDC we have active in the vault (and any pending yield or rewards). For instance, it might show an active balance of ~0.5 USDC, and possibly any claimable rewards if applicable, all in one payload. Yield.xyz normalizes these outputs across all yields, so even if we were querying a staking position or another DeFi protocol, the format would be consistent.

Exit the yield (withdraw funds)

Yield.xyz’s POST /v1/actions/exit endpoint returns the transaction data required to perform a withdrawal. Similar to the enter action, you specify the yield ID, your wallet address, and the withdrawal amount.
const exitPayload = {
  yieldId: process.env.YIELD_ID! ,
  address: process.env.SIGN_WITH!,
  arguments: { amount: "0.1" },
};

const exitRes = await fetch("https://api.yield.xyz/v1/actions/exit", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.YIELD_API_KEY!,
  },
  body: JSON.stringify(exitPayload),
});
const exitAction = await exitRes.json();

for (const tx of exitAction.transactions) {
	const unsignedTx = JSON.parse(tx.unsignedTransaction);
  const sent = await connectedSigner.sendTransaction({
        to: unsignedTx.to,
        data: unsignedTx.data,
        value: unsignedTx.value ?? '0x0',
        chainId: unsignedTx.chainId
      });
  console.log("Withdraw tx:", sent.hash);
}
In the first step, we requested to withdraw 0.1 USDC. Yield.xyz returned the appropriate transaction (a call to the vault’s withdraw function under the hood). We sent it with our Turnkey signer, and once mined, ~0.1 USDC would be back in our wallet.

Monetization

Monetization of yield interactions is possible on multiple levels depending on the yield type:
  • Staking.
    • Deposit Fees: Leverage FeeWrapper contracts (EVM) and atomic fee transfer mechanisms (non-EVM) to deduct a percentage of the deposit and transfer it to the recipient in the same transaction.
    • Revenue Share: Yield.xyz has agreements with 30+ validator service providers, entitling clients to a portion of validator revenues (typically 50%–85%).
  • DeFi.
    • Revenue Share: Some major protocols and curators provide revenue share on deposits via the Yield.xyz API.
    • User-Facing Fees via OAVs:
      • Optimized Allocator Vaults (OAVs) allow deposit, performance, and management fees to be configured at the user level.
      • Performance Fees: Charged on realized profits.
      • Management Fees: Flat annualized rate applied on AUM.
      • Deposit Fees: Automatically deducted at the time of deposit.
You can identify which monetization options apply to a given yield in the yield metadata, specifically the possibleFeeTakingMechanisms object → API Reference

Web2 UX via OAVs

Beyond monetization, OAVs deliver a Web2-grade experience for Web3 yields.
  • Automatic Off-Ramping & Reinvestment: Incentive tokens are automatically off-ramped into the deposit asset and reinvested, ensuring users earn pure yield in their deposit token.
  • Automatic Wrapping/Swapping: Complex asset flows are handled automatically, reducing friction and mirroring the simplicity of Web2 fintech apps.
  • Unified UX: End-users interact only with their deposit asset — no juggling of dozens of reward tokens, no manual reinvestments.
This makes OAVs unique: they enable fee capture for partners while simultaneously simplifying the user experience, ensuring yield products feel as seamless as mainstream fintech offerings.For reference, the yields most popular among existing clients (already wrapped into OAVs) can be found **here.** We’ve deployed two sets of OAVs with pre-configured fees — available via API Keys:
  • 10% fee OAVs: 4bea9274-7cef-4e43-995b-f35147469ede
  • 20% fee OAVs: e35de2d4-93e2-4cf8-b016-b0838fec1f20

Conclusion

With this integration you can:
  • Discover yield opportunities across 70+ networks.
  • Enter and Exit with standardized transactions.
  • Track balances and rewards.
  • Use Turnkey’s policy engine to ensure signing operations can only interact with the intended smart contracts.
All transactions are constructed by Yield.xyz for the selected yield opportunities and signed with Turnkey — no need to write custom contract logic or manage ABIs. Partners can start with baseline access to public validator delegation and curated OAVs, then request custom OAVs with client-specific fee structures (in addition to the minimum 10% platform fee). This lets you go to market with yield in days, not months — with more revenue, less engineering overhead, and stronger security guarantees than building and maintaining protocol integrations yourself.