Skip to main content

Pendle Hosted SDK

Pendle accommodates a vast array of assets, each characterized by its unique nuances and complexities. While the Pendle protocol remains immutable, the underlying assets don't share this feature, requiring our app and SDK to be updated frequently to align with changes in these assets.

To address this, Pendle has introduced a hosted version of our SDK. It ensures the output remains consistent with Pendle's UI and keeps up-to-date with the latest protocol changes. The API design prioritizes simplicity and stability, with a high rate limit to meet the needs of most users.

Supported functions

  • Swap
  • Add liquidity
  • Add liquidity ZPI
  • Remove liquidity
  • Mint PT & YT
  • Redeem PT & YT
  • Transfer liquidity
  • Transfer liquidity ZPI
  • Roll over PT
  • Add liquidity dual
  • Remove liquidity dual
  • Mint SY
  • Redeem SY

All actions above can be accessed via one universal Convert API.

Examples

Swap

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&tokensOut=0xf99985822fb361117fcf3768d34a6353e6022f5f&amountsIn=1000000000&enableAggregator=true&aggregators=kyberswap&additionalData=impliedApy,effectiveApy

In code:

export async function swapTokenToPt() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${USDC_ADDRESS}`,
amountsIn: 1000000000,
tokensOut: `${PT_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
enableAggregator: true,
aggregators: "kyberswap",
additionalData: "impliedApy,effectiveApy",
});
}

Add liquidity

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0&tokensOut=0xc374f7ec85f8c7de3207a10bb1978ba104bda3b2&amountsIn=1000000000000000000

In code:

export async function addLiquiditySingleToken() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${WSTETH_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${MARKET_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Add liquidity ZPI

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0&tokensOut=0xc374f7ec85f8c7de3207a10bb1978ba104bda3b2,0xf3abc972a0f537c1119c990d422463b93227cd83&amountsIn=1000000000000000000

In code:

export async function addLiquiditySingleTokenKeepYt() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${WSTETH_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${MARKET_ADDRESS},${YT_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Remove liquidity

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0xc374f7ec85f8c7de3207a10bb1978ba104bda3b2&tokensOut=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0&amountsIn=1000000000000000000&enableAggregator=true

In code:

export async function removeLiquiditySingleToken() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${MARKET_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${WSTETH_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
enableAggregator: true,
});
}

Mint PT & YT

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0&tokensOut=0xf99985822fb361117fcf3768d34a6353e6022f5f,0xf3abc972a0f537c1119c990d422463b93227cd83&amountsIn=1000000000000000000

In code:

export async function mintPyFromToken() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${WSTETH_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${PT_ADDRESS},${YT_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Redeem PT & YT

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0xf99985822fb361117fcf3768d34a6353e6022f5f,0xf3abc972a0f537c1119c990d422463b93227cd83&tokensOut=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0&amountsIn=1000000000000000000,1000000000000000000

In code:

export async function redeemPyToToken() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${PT_ADDRESS},${YT_ADDRESS}`,
amountsIn: "1000000000000000000,1000000000000000000",
tokensOut: `${WSTETH_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Transfer liquidity

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0x9bc2fb257e00468fe921635fe5a73271f385d0eb,0x21aace56a8f21210b7e76d8ef1a77253db85bf0a,0x3787c19c32e727310708c0693aec00fb37a01e7b&tokensOut=0xc374f7ec85f8c7de3207a10bb1978ba104bda3b2&amountsIn=1000000000000000000,1000000000000000000,1000000000000000000&enableAggregator=true&aggregators=kyberswap

In code:

export async function transferLiquidity() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${FXSAVE_MARKET_ADDRESS},${FXSAVE_PT_ADDRESS},${FXSAVE_YT_ADDRESS}`,
amountsIn: "1000000000000000000,1000000000000000000,1000000000000000000",
tokensOut: `${MARKET_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
enableAggregator: true,
aggregators: "kyberswap",
});
}

Transfer liquidity ZPI

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0x9bc2fb257e00468fe921635fe5a73271f385d0eb,0x21aace56a8f21210b7e76d8ef1a77253db85bf0a,0x3787c19c32e727310708c0693aec00fb37a01e7b&tokensOut=0xc374f7ec85f8c7de3207a10bb1978ba104bda3b2,0xf3abc972a0f537c1119c990d422463b93227cd83&amountsIn=1000000000000000000,1000000000000000000,1000000000000000000&enableAggregator=true&aggregators=kyberswap

In code:

export async function transferLiquidityKeepYt() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${FXSAVE_MARKET_ADDRESS},${FXSAVE_PT_ADDRESS},${FXSAVE_YT_ADDRESS}`,
amountsIn: "1000000000000000000,1000000000000000000,1000000000000000000",
tokensOut: `${MARKET_ADDRESS},${YT_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
enableAggregator: true,
aggregators: "kyberswap",
});
}

Roll over PT

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0x21aace56a8f21210b7e76d8ef1a77253db85bf0a&tokensOut=0xf99985822fb361117fcf3768d34a6353e6022f5f&amountsIn=1000000000000000000&enableAggregator=true

In code:

export async function rollOverPt() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${FXSAVE_PT_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${PT_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
enableAggregator: true,
});
}

Add liquidity dual

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0xcbc72d92b2dc8187414f6734718563898740c0bc,0xf99985822fb361117fcf3768d34a6353e6022f5f&tokensOut=0xc374f7ec85f8c7de3207a10bb1978ba104bda3b2&amountsIn=1000000000000000000,1000000000000000000

In code:

export async function addLiquidityDualSyAndPt() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${SY_ADDRESS},${PT_ADDRESS}`,
amountsIn: "1000000000000000000,1000000000000000000",
tokensOut: `${MARKET_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Remove liquidity dual

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0xc374f7ec85f8c7de3207a10bb1978ba104bda3b2&tokensOut=0xf99985822fb361117fcf3768d34a6353e6022f5f,0xcbc72d92b2dc8187414f6734718563898740c0bc&amountsIn=1000000000000000000

In code:

export async function removeLiquidityDualSyAndPt() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${MARKET_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${PT_ADDRESS},${SY_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Mint SY

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0&tokensOut=0xcbc72d92b2dc8187414f6734718563898740c0bc&amountsIn=1000000000000000000

In code:

export async function mintSyFromToken() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${WSTETH_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${SY_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Redeem SY

GET https://api-v2.pendle.finance/core/v2/sdk/1/convert?receiver=<RECEIVER_ADDRESS>&slippage=0.01&tokensIn=0xcbc72d92b2dc8187414f6734718563898740c0bc&tokensOut=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0&amountsIn=1000000000000000000

In code:

export async function redeemSyToToken() {
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${SY_ADDRESS}`,
amountsIn: "1000000000000000000",
tokensOut: `${WSTETH_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
});
}

Send Transaction

After calling any of the Convert API functions above, you can inspect the response and send the transaction:

const res: ConvertResponse;

// Log the action and outputs
console.log("Action: ", res.action);
console.log("Outputs: ", res.routes[0].outputs);

// Send the transaction
getSigner().sendTransaction(res.routes[0].tx);

Please visit our Convert API demo to see more detailed examples.

Inputs

The Convert API accepts the following input parameters:

ParameterTypeRequiredDefaultDescription
tokensInstringYes-Array of input token addresses (comma-separated)
amountsInstringYes-Array of input token amounts in wei (comma-separated)
tokensOutstringYes-Array of expected output token addresses (comma-separated)
receiverstringYes-Address to receive the output tokens
slippagenumberYes-Maximum slippage tolerance (0-1, where 0.01 = 1%)
enableAggregatorbooleanNofalseEnable swap aggregators for token conversions
aggregatorsstringNo-Specific aggregators to use (comma-separated), see Routing
redeemRewardsbooleanNofalseWhether to redeem rewards during the action, applicable to actions: transfer-liquidity
needScalebooleanNofalseAggregator needScale parameter, only set to true when amounts are updated on-chain. When enabled, please make sure to buffer the input amount by about 2%, applicable to actions: swap
additionalDatastringNo-Additional data to include in response (comma-separated), see Additional data

Outputs

The Convert API returns the following response structure:

FieldTypeRequiredDescription
actionstringYesThe classified and executed action (e.g., mint-py, swap, add-liquidity)
inputsTokenAmountResponse[]YesInput tokens and amounts used in the action
requiredApprovalsTokenAmountResponse[]NoTokens requiring approval before execution
routesConvertResponse[]YesArray of route execution details, sorted by decresing output amount

TokenAmountResponse

FieldTypeRequiredDescription
tokenstringYesToken contract address (lowercase)
amountstringYesToken amount in wei (BigInt string)

ConvertResponse

FieldTypeRequiredDescription
contractParamInfoContractParamInfoYesParam info for the contract method called
txTransactionDtoYesComplete transaction data for execution
outputsTokenAmountResponse[]YesExpected output tokens and amounts
dataConvertDataYesAction-specific data

ContractParamInfo

FieldTypeRequiredDescription
methodstringYesContract method name (e.g., mintPyFromToken)
contractCallParamsNamestring[]YesParameter names array
contractCallParamsany[]YesParameter values array

TransactionDto

FieldTypeRequiredDescription
datastringYesEncoded transaction data (hex)
tostringYesContract address to call
fromstringYesSender address
valuestringYesNative token amount to send

ConvertData

FieldTypeRequiredDescription
aggregatorTypestringYesThe aggregator used, or VOID if none was used
priceImpactnumberYesPrice impact
impliedApyImpliedApyNoMarket APY information for yield actions. (for swap actions)
effectiveApynumberNoUser's effective APY after fees/slippage. (for swap actions)
paramsBreakdownParamsBreakdownNoMulti-step action breakdown (for transfer-liquidity)

ImpliedApy

FieldTypeRequiredDescription
beforenumberYesImplied APY before transaction
afternumberYesImplied APY after transaction

ParamsBreakdown

FieldTypeRequiredDescription
selfCall1ContractParamInfoYesParams info for selfCall1
selfCall2ContractParamInfoNoParams info for selfCall2
reflectCallContractParamInfoYesParams info for reflectCall

Features

Routing

Routing is a feature of the Pendle SDK that helps users find the most optimal route to interact with the Pendle system. This feature ensures that users can efficiently execute their transactions by identifying the best paths for their specific needs, whether it's swapping assets, adding or removing liquidity, or any other supported function.

To take advantage of the routing feature, users need to set the enableAggregator option to true. When this option is enabled, the system will automatically perform routing to find the most optimal route for the user's transaction. This ensures that users always get the best possible outcome when interacting with the Pendle system.

Select aggregators

When enableAggregator is set to true, you can control which aggregators are used by specifying the aggregators parameter. This parameter accepts a comma-separated list of aggregator names (e.g. "kyberswap,odos"). If not specified, the system will use all available aggregators to find the optimal route.

Using more aggregators generally results in better optimized routes since there are more options to choose from. However, each aggregator adds to the computing unit cost of the request (see rate limiting). You can balance between optimization and cost by selectively enabling only the aggregators you want to use.

Currently supported aggregators (can be fetched from fetch supported aggregators endpoint), this list is subject to change:

AggregatorCost (Computing Units)
kyberswap5
odos15
okx10
paraswap15

Example, this request will use KyberSwap and Odos aggregators to find the optimal route, and it cost 25 computing units (5 from kyberswap, 15 from odos, and 5 from the base computing cost):

export async function addLiquiditySingleToken() {
// Use 1 ETH to add liquidity to stETH pool with 1% slippage
const res = await callSDK<ConvertResponse>(`/v2/sdk/${CHAIN_ID}/convert`, {
tokensIn: `${ETH_ADDRESS}`,
amountsIn: '1000000000000000000',
tokensOut: `${STETH_LP_ADDRESS}`,
receiver: RECEIVER_ADDRESS,
slippage: 0.01,
enableAggregator: true,
aggregators: "kyberswap,odos",
});

console.log("Action: ", res.action);
console.log("Outputs: ", res.routes[0].outputs);
console.log("Price impact: ", res.routes[0].data.priceImpact);

// Send tx
getSigner().sendTransaction(res.routes[0].tx);
}

Reduce aggregator computing units

By default, when using aggregators, the system will use public API keys for each aggregator. This means that the computing unit cost for each aggregator will be added to the total cost of the request. To reduce the computing unit cost, you can use your own API key for each aggregator. This way, the computing unit cost for that aggregator will be reduced to 0. For example, if you use your own API key for Odos, the total computing unit cost will be 5 (base cost) + 5 (kyberswap cost) + 0 (odos cost with custom API key) = 10 computing units.

Currently you can use aggregator with your own API key by specifying specific field in the request headers.

AggregatorHeader KeyNote
kyberswapKYBERSWAP-API-KEY
odosODOS-API-KEY
okxOKX-ACCESS-KEY, OKX-ACCESS-SECRET, OKX-PASSPHRASENeed all three to return a valid response
paraswapPARASWAP-API-KEY

When using custom aggregators, please make sure to include the required headers in your request. If the headers are not provided, the system will default to using the public API for that aggregator.

Additional data

When an endpoint has an additionalData field, users can pass in some fields to receive more data, but it will cost more computing units.

For example, the swap action has additionalData with two available fields: impliedApy and effectiveApy. If the query parameters have additionalData=impliedApy, the response will have the implied APY before and after the swap action.

For additional usage, please refer to our external swagger to explore more.