Skip to main content
The portfolio response returns a top level object with a timestamp, a sections object that reports indexing status and freshness for each product, and one array for each product section. Each position is returned already valued, with its own value and price included.
Run the endpoints live in the API playground: portfolio and pending rewards.

Parameters

ParameterInRequiredDescription
pubkeypathYesWallet address (base58).
programIdqueryNoKLend program ID to scope results.

Response object

FieldTypeDescription
timestampstringISO timestamp of the response.
sectionsobjectIndexing status and freshness per product. See Section state.
lending multiply leveragearrayBorrow-side obligations (see the Position fields tabs).
liquidity earn privateCredit stakingarrayThe remaining product positions.

Position fields by product

One entry per obligation. The tag field distinguishes the kind (Vanilla, Multiply, and so on). Multiply and leverage entries add depositMint and borrowMint.
FieldTypeDescription
obligationstringObligation pubkey.
marketstringLending market pubkey.
tagstringObligation kind (Vanilla, Multiply, …).
netValuestringUSD net value (deposits minus borrows).
totalDepositValuestringUSD value of all deposits.
totalBorrowValuestringUSD value of all borrows.
ltvstringCurrent loan-to-value (for example "0.38").
maxLtvstringMaximum borrowing LTV.
liquidationLtvstringLTV at which liquidation triggers.
leveragestringPosition leverage (for example "1.56").
depositsarrayDeposited assets (Token object).
borrowsarrayBorrowed assets (Token object).
depositMintstringMultiply and leverage only: collateral mint.
borrowMintstringMultiply and leverage only: debt mint.

Shared building blocks

Entries in deposits, borrows, and the liquidity tokenA / tokenB share a common shape, with a few context-specific extras.
FieldTypeDescription
mintstringToken mint.
symbolstringToken symbol.
amountstringToken amount.
valuestringUSD value.
pricestringToken price.
reservestringReserve pubkey (deposits and borrows).
maxLtvstringDeposits only: collateral max LTV.
liquidationLtvstringDeposits only: collateral liquidation LTV.
borrowFactorstringBorrows only: borrow factor.
Each product key in sections reports whether the wallet has data and how fresh it is. A section with indexed: false has no data for this wallet.
FieldTypeDescription
indexedbooleanfalse means no data for this wallet and product.
positionsRefreshedOnstring | nullISO timestamp positions were last refreshed.
pricesRefreshedOnstring | nullISO timestamp prices were last refreshed.
errorsarrayErrors encountered while loading this section.

Pending rewards

GET /portfolio/{pubkey}/rewards returns pending farm rewards across products: a timestamp and a farms array. Each farm entry lists its pending rewards.
FieldTypeDescription
farmstringFarm pubkey.
userStatestringUser state pubkey.
delegateestringWallet pubkey.
positionTypestringHuman-readable source (for example Borrow Markets).
activeStakeAmountstringActive staked amount.
tokenMintsarrayAssociated token mints.
rewardsarrayPending rewards (see below).
FieldTypeDescription
mintstringReward token mint.
amountstringPending amount.
indexnumberReward index.
typenumberReward type.
tokenProgramstringToken program of the reward mint.

Examples

1

Calculate LTV and liquidation headroom for each lending position

Compare ltv against liquidationLtv to measure how close a position is to liquidation.
lendingPositions
const WALLET = 'YOUR_WALLET_ADDRESS';
const API = 'https://api.kamino.finance';

const portfolio = await (await fetch(`${API}/portfolio/${WALLET}`)).json();

(portfolio.lending || []).forEach((pos, i) => {
  const ltvPct = (parseFloat(pos.ltv) * 100).toFixed(2);
  const liqPct = (parseFloat(pos.liquidationLtv) * 100).toFixed(2);
  const headroom = ((parseFloat(pos.liquidationLtv) - parseFloat(pos.ltv)) * 100).toFixed(2);

  console.log(`\n--- Lending position ${i + 1} (${pos.tag}) ---`);
  console.log(`  Net value: $${parseFloat(pos.netValue).toFixed(2)}`);
  console.log(`  LTV:       ${ltvPct}% (liq ${liqPct}%)`);
  console.log(`  Headroom:  ${headroom}% before liquidation`);
});
2

List earn vault positions with shares and USD value

earnPositions
const portfolio = await (await fetch(`${API}/portfolio/${WALLET}`)).json();

(portfolio.earn || []).forEach((pos) => {
  console.log({
    vault: pos.vault,
    name: pos.name,
    symbol: pos.symbol,
    shares: pos.shares,
    amount: parseFloat(pos.amount).toFixed(6),
    netValueUsd: '$' + parseFloat(pos.netValue).toFixed(4),
  });
});
3

Check which product sections are stale or failed to load

Use sections to decide whether positions are stale or a product failed to load.
sectionFreshness
const portfolio = await (await fetch(`${API}/portfolio/${WALLET}`)).json();
const now = Date.now();

Object.entries(portfolio.sections).forEach(([name, sec]) => {
  if (!sec.indexed) return console.log(`${name}: not indexed`);

  const age = (ts) => (ts ? ((now - new Date(ts).getTime()) / 60_000).toFixed(1) + 'm ago' : 'never');
  const errors = sec.errors.length ? ` ⚠ ${sec.errors.length} error(s)` : '';

  console.log(`${name}: positions ${age(sec.positionsRefreshedOn)}, prices ${age(sec.pricesRefreshedOn)}${errors}`);
});
4

List pending farm rewards across all products

pendingRewards
const rewards = await (await fetch(`${API}/portfolio/${WALLET}/rewards?rewardTypes=0,1,2,3`)).json();
const farms = rewards.farms || [];

console.log(`Pending rewards across ${farms.length} farm(s):`);

farms.forEach((f) => {
  console.log(`\n  Farm: ${f.farm} (${f.positionType})`);
  (f.rewards || []).forEach((r) => console.log(`    ${r.amount} (mint ${r.mint}, type ${r.type})`));
});
5

Sum total portfolio value and break it down per product

Sum netValue from each section (and value for staking) for a portfolio total, then break it down per product.
totalValue
const portfolio = await (await fetch(`${API}/portfolio/${WALLET}`)).json();

const products = ['lending', 'multiply', 'leverage', 'liquidity', 'earn', 'privateCredit', 'staking'];

let totalValue = 0;
const breakdown = [];

products.forEach((p) => {
  const positions = portfolio[p] || [];
  const value = positions.reduce((sum, pos) => sum + parseFloat((p === 'staking' ? pos.value : pos.netValue) || '0'), 0);
  totalValue += value;
  if (positions.length) breakdown.push({ product: p, value, count: positions.length });
});

console.log(`Total portfolio value: $${totalValue.toFixed(2)}`);
breakdown
  .sort((a, b) => b.value - a.value)
  .forEach((b) => console.log(`  ${b.product}: $${b.value.toFixed(2)} (${b.count} position(s))`));

Calculate portfolio totals

The API returns valued positions but no portfolio-wide rollups, so you compose them:
  • Net worth: sum netValue across every section, except staking, which exposes value instead. Multiply and leverage netValue is already deposits minus borrows, so totals reflect real equity.
  • USD conversion: positions carry value and price, but for any raw amounts you price yourself, use the Oracle prices endpoint.