getPositions, use it to display portfolio value in your UI.
Balances are enriched with net-of-pending-fee fields (balanceWithFee, underlyingAmountWithFee). The pending fee is derived from onchain current earnings × the Zyfi fee rate (10%). Gross fields (balance, underlyingAmount) are unchanged. If earnings cannot be fetched, *WithFee equals the gross value so the response shape stays stable.
Each position also includes pool_apy_withFee (pool_apy × 0.9). Gross pool_apy is unchanged.
Signature
Parameters
Returns
Detailed portfolio data including positions and balances by asset type, plus fee-adjusted balance fields.Return Type
Computing the total balance
portfolioByAssetType is not the user’s total balance. The backend builds
it from exactly two sources: the underlying amount of every deployed position
and the idle balances sitting in the Safe. Anything in neither place is missing
from it.
That gap is real under the yieldmaxxing
strategy. When the agent requests a redemption from a delayed-withdrawal
protocol, the position leaves the snapshot immediately while the funds stay in
the vault for a day or three. During that window they appear in no balance
field, only in pendingAsyncWithdrawals.
So an integration needs two different numbers, and showing one where the
other belongs is the most common mistake:
An in-flight amount is no longer withdrawable. A
withdrawFunds call only
reaches positions in the current snapshot and idle Safe balances, and the
in-flight amount is in neither. Calling it again will not pull those funds out
any faster. If every remaining position sits in a pool that already has a
REQUESTED or CLAIMABLE entry, the call throws — async pools allow only
one redemption at a time. They land on the user’s EOA on their own once the
protocol releases them, so the right UI is to show them as pending with their
estimatedClaimAt and disable withdraw until the entry reaches CLAIMED. See
withdrawFunds.
?? "0x0" below: when every position of an asset is in flight, the
backend drops the asset key from portfolioByAssetType altogether rather than
reporting a zero balance, and portfolioByAssetType itself can be {}.
requestable that settles immediately, cross-check
each entry of positions against
getAsyncOpportunities: a position
whose protocol_name and pool match an async opportunity will settle through
a delayed redemption, while idle balances and every other position settle in
the withdrawal transaction itself.
Displaying an in-flight redemption
Each entry carries what a progress UI needs:status, amount,
protocol.name, pool, and estimatedClaimAt. When the protocol is
temporarily refusing claims, statusMessage holds copy ready to display.
amount is hex-encoded least units, like every other balance in this
payload. For example, "0x98967f" is 9999999, so 9.999999 USDC at 6 decimals. Read it with
BigInt, never with parseInt or Number.
FAILED status is not a loss of funds: the protocol did not allow the claim
in time, so the position is restored and the request is retried on the next
cycle.
pauseMessageByToken is a companion field holding user-facing copy when
deposits are paused for a token (tokenized stocks over the weekend, for
example), keyed by token symbol.
How *WithFee is calculated
- Fee source:
current_earnings_by_chainonly (fetched in parallel with the portfolio) - Multiple positions on the same chain + token: fee is split proportionally by
underlyingAmount - Portfolio balances are live, but earnings used for the fee may be from a snapshot. Small mismatches are possible.
Example
Notes
- This method automatically resolves the smart wallet address from the EOA
- If no smart wallet exists for the user, returns an empty portfolio
- Auth is not required for this read path
portfolioByAssetTypeprovides balances grouped by token (e.g., USDC, WETH, EURC): positions plus idle Safe balances, and nothing elseportfolioByChainprovides the same balance structure grouped by chain, then by asset type- For the true total under the
yieldmaxxingstrategy, see Computing the total balance - Decode hex / wei amounts with the correct
decimals(USDC/EURC = 6, WETH = 18, …) - For earnings net of fee, see getOnchainEarnings
- For legacy position data, see getPositions