# Vaults Data API

## Vaults Data API

Welcome to the **Bonzo Vaults Data API**. The Vaults API exposes real-time and historical data for the **Bonzo Yield Vaults** product — a family of automated yield strategies that deploy user deposits into liquidity pools, lending markets, and other on-chain venues on the Hedera network. It is intended for third parties building dashboards, portfolio trackers, analytics platforms, bots, and any other tooling that needs programmatic access to vault state, performance, and user positions.

Bonzo Vaults ships in two flavors, each with its own data service:

* **Dual-Asset DEX Vaults** — concentrated-liquidity vaults that hold a pair of assets and auto-compound trading fees and incentive rewards. These are powered by Beefy-style strategy contracts and serve liquidity to venues like SaucerSwap.
* **Single-Asset DEX Vaults** — ICHI vaults that accept a single deposit token and internally manage a paired position. Users only ever deposit and withdraw the deposit token; the vault handles the rest.

Both services share the same overall shape — the same routing conventions, the same query patterns, and the same general response objects — but they expose data unique to each strategy class. This page documents both as a single, unified surface so an integrator can read across them with minimal friction.

#### Key Features

* **Real-Time Vault Data** — TVL, APY/APR breakdowns, share prices, fees, and harvest history, refreshed continuously.
* **User Position Tracking** — per-vault and aggregate position views, including yield, P\&L, and historical snapshots.
* **Historical Charts** — APY, TVL, share price, portfolio performance, and harvest-fee timeseries for any timeframe.
* **Platform Analytics** — protocol-wide TVL, fees, revenue, and snapshot summaries.
* **Public Endpoints** — no authentication required for any of the read endpoints documented below.
* **Hedera-native Identifiers** — every contract is exposed with both its EVM-style address (`0x…`) and its Hedera entity ID (`0.0.…`) for compatibility with HashScan, the Hedera mirror node, and EVM tools.

***

### Base URLs

The two vault types are served from two separate base URLs. Pick the one that matches the vault you are working with:

| Vault type                              | Base URL                                     |
| --------------------------------------- | -------------------------------------------- |
| **Dual-Asset DEX Vaults** (Beefy-style) | `https://mainnet-vaults.bonzo.finance`       |
| **Single-Asset DEX Vaults** (ICHI)      | `https://mainnet-single-asset.bonzo.finance` |

All endpoints below are prefixed with `/v1/api/…`. The health endpoint lives at `/v1/health` and a service-info endpoint is exposed at `/`.

{% hint style="info" %}
A vault's `id` is unique within its own service. A dual-asset vault ID will not resolve against the single-asset service and vice versa. Treat the two services as independent data sources keyed by `(baseUrl, vaultId)`.
{% endhint %}

***

### Common Concepts

The same handful of objects show up across nearly every endpoint. Read this section once and the rest of the page becomes a thin reference.

#### Networks and identifiers

Both APIs run against Hedera mainnet (`chainType: "hedera_mainnet"`, `network: "Hedera"`). Each contract appears with two identifiers:

* `contractAddress` — EVM 20-byte address, e.g. `0xcfba07324bd207C3ED41416a9a36f8184F9a2134`.
* `contractId` — Hedera native entity ID, e.g. `0.0.10164550`.

Use whichever one matches your tooling. Tokens follow the same convention via `address` and `contractId` fields on each asset object.

#### Asset and pair-token objects

Every vault carries an array of underlying assets. The shape is consistent across both services:

```typescript
interface Asset {
  symbol: string;        // e.g. "USDC", "HBAR", "SAUCE"
  address: string;       // EVM 0x… address
  contractId: string;    // Hedera 0.0.X ID
  decimals: number;
  price?: string;        // USD price at the time of the snapshot
}
```

Single-asset vaults additionally surface a `pairToken` — the secondary token the vault rebalances against — using the same shape.

#### TVL, APY, and APR

| Field                                                       | Meaning                                                                                                                                                |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `tvl` / `TVL`                                               | Total Value Locked in the vault, USD. Returned as a string for precision and (on the single-asset API) also as a number under `TVL`.                   |
| `apy`                                                       | Net annualized yield, expressed as a decimal — e.g. `0.157` is 15.7%. **Note:** the single-asset API returns APY as a percent number (e.g. `16.379…`). |
| `apy30d`                                                    | 30-day rolling APY (single-asset API).                                                                                                                 |
| `daily`                                                     | 1-day yield estimate (decimal on dual-asset, percent number on single-asset).                                                                          |
| `harvestApy7d`, `harvestApy30d`                             | Realized APY measured from the vault's own harvest history over the trailing window (dual-asset only).                                                 |
| `vaultApr`, `vaultApy`, `tradingApr`, `rewardApr`, `clmApy` | Component APRs that roll into `apy`. Useful when displaying a breakdown.                                                                               |
| `apySource`                                                 | Which input drove the headline APY: `"harvest"`, `"price"`, `"manual"`, etc.                                                                           |
| `confidence`                                                | Confidence scoring object on dual-asset vaults: `{ score, level: "low" \| "medium" \| "high", reasons: string[] }`.                                    |

#### Share price and user position math

Vault deposits are tokenized as **shares**. A user's underlying balance is `shares × sharePrice`, and yield is the change in that quantity since their entries.

* `sharePrice` is returned in raw on-chain precision; `sharePriceUsd` is the USD-normalized version.
* `userPosition.deposited` / `depositedUSD` capture cost basis.
* `userPosition.currentValue` and `currentValueInUSD` capture the present mark-to-market value.
* `userPosition.yield` is realized + unrealized yield since deposit.
* `userPosition.pnl = { amount, percentage }` is convenience math: `currentValue − deposited`.

#### Harvests

A **harvest** is the periodic on-chain operation that compounds collected fees and incentive rewards back into the vault. Harvest events are the primary fuel for realized APY measurements and for fee-attribution endpoints. Both APIs expose a `lastHarvest` timestamp on each vault, and both expose harvest-fee timeseries per user under `/charts/users/:address/harvest-fees`.

***

### Service Info & Health

Both services expose a service banner at the root and a liveness probe at `/v1/health`.

**`GET /`**

Returns the service identity and a directory of mounted route prefixes.

```bash
curl https://mainnet-vaults.bonzo.finance/
curl https://mainnet-single-asset.bonzo.finance/
```

```json
{
  "name": "Bonzo Vaults API",
  "version": "1.0.0",
  "description": "TypeScript API for Bonzo Yield Vaults on Hedera",
  "chainType": "hedera_mainnet",
  "endpoints": {
    "health": "/v1/health",
    "vaults": "/v1/api/vaults",
    "charts": "/v1/api/charts",
    "admin":  "/v1/api/admin",
    "users":  "/v1/api/users"
  },
  "documentation": "https://docs.bonzo.finance/api"
}
```

**`GET /v1/health`**

Liveness check. Returns `200 OK` with current uptime and version when the service is healthy.

```json
{
  "status": "ok",
  "timestamp": "2026-04-30T04:31:50.527Z",
  "uptime": 21827.68,
  "version": "1.0.0",
  "chainType": "hedera_mainnet"
}
```

***

### Dual-Asset DEX Vaults

Base URL: `https://mainnet-vaults.bonzo.finance`

Dual-asset vaults hold a pair of assets — typically a SaucerSwap concentrated-liquidity LP — and auto-rebalance the position while compounding trading fees and emissions. Each vault has both a vault contract and a separate strategy contract.

#### List Vaults

**`GET /v1/api/vaults`**

Returns the full set of dual-asset vaults along with summary metrics.

**Query Parameters**

| Parameter          | Type                     | Description                                                                        |
| ------------------ | ------------------------ | ---------------------------------------------------------------------------------- |
| `protocol`         | string                   | Filter by protocol (e.g. `SaucerSwap`).                                            |
| `strategy`         | string                   | Filter by strategy name.                                                           |
| `vaultType`        | string                   | Filter by vault type — `single`, `concentratedLiquidity`.                          |
| `minTvl`           | number                   | Minimum TVL filter, USD.                                                           |
| `minApy`           | number                   | Minimum APY filter (decimal, e.g. `0.05` = 5%).                                    |
| `sortBy`           | `tvl` \| `apy` \| `name` | Sort field.                                                                        |
| `sortOrder`        | `asc` \| `desc`          | Sort direction.                                                                    |
| `limit`            | number                   | Page size.                                                                         |
| `offset`           | number                   | Page offset.                                                                       |
| `afterTransaction` | boolean                  | When `true`, bypasses the cache. Use after a deposit/withdraw to pull fresh state. |

**Response**

```typescript
interface VaultListResponse {
  totalValueLocked: string;
  vaultCount: number;
  averageApy: string;
  totalYield: string;
  totalPnl: string;
  vaults: VaultSummary[];
}
```

Each `VaultSummary` includes (abbreviated):

```typescript
{
  id: string;
  name: string;                    // e.g. "SAUCE-XSAUCE"
  protocols: string[];             // e.g. ["SaucerSwap"]
  strategyType: string;            // e.g. "concentratedLiquidity"
  network: "Hedera";
  assets: Asset[];                 // pair tokens (length 2 for CLM)
  poolAddress: string;             // Hedera ID
  poolEvmAddress: string;          // 0x…
  apy: string;                     // decimal (0.157 = 15.7%)
  totalApy: string;
  vaultApr: string; vaultApy: string;
  tradingApr: string; rewardApr: string;
  clmApy: string;
  saucerswapFeesApr: string;
  saucerswapLariApr: string;
  saucerswapManualAprTotal: string;
  harvestApy7d: string; harvestApy30d: string;
  apySource: "harvest" | "price" | "manual" | string;
  confidence: { score: number; level: "low" | "medium" | "high"; reasons: string[] };
  apyBreakdown: { /* harvest windows, realized vs estimated, fee/lari details */ };
  priceRange: { /* current tick + main/alt range bounds for CLM */ };
  tvl: string;
  tokenPrice: number; tokenPrice0?: number; tokenPrice1?: number;
  sharePrice: string; sharePriceUsd: string;
  apyChange24hrs: number;
  tvlChange24hrs: number;
  safetyScore: number;             // 1–5
  lastHarvest: string;             // ISO timestamp
  vaultType: "concentratedLiquidity" | "single";
  contractAddress: string; contractId: string;
  strategyAddress: string; strategyContractId: string;
  fees: { deposit: number; withdrawal: number; performance: number };
  description: string;
  tabs: { overview: string; strategy: string; details: string; risks: object[] };
  userPosition: { /* zeroed when no `account` is supplied */ };
}
```

```bash
curl 'https://mainnet-vaults.bonzo.finance/v1/api/vaults?sortBy=tvl&sortOrder=desc&limit=10'
```

#### Get Vault by ID

**`GET /v1/api/vaults/:id`**

Returns the full detail object for a single vault. Same shape as a `VaultSummary` plus richer breakdowns.

**Path Parameters**

| Parameter | Type   | Description                                            |
| --------- | ------ | ------------------------------------------------------ |
| `id`      | string | Vault ID (the `id` field returned from `GET /vaults`). |

**Query Parameters**

| Parameter          | Type    | Description   |
| ------------------ | ------- | ------------- |
| `afterTransaction` | boolean | Bypass cache. |

```bash
curl 'https://mainnet-vaults.bonzo.finance/v1/api/vaults/68d4d6bdcf25aba1bd699033'
```

#### List a User's Positions

**`GET /v1/api/vaults/user-positions?account=0x…`**

Lightweight, fast endpoint that returns every dual-asset vault and the caller's position in each. Designed for "My Vaults" dashboards. Yield/PnL math is **omitted** in this response for performance — call the per-vault detail endpoint below to get those.

**Query Parameters**

| Parameter                                       | Type                                      | Required | Description                          |
| ----------------------------------------------- | ----------------------------------------- | -------- | ------------------------------------ |
| `account`                                       | string                                    | yes      | EVM address of the user.             |
| `protocol`, `strategy`, `vaultType`, `minValue` | filters                                   | no       | Same semantics as the list endpoint. |
| `sortBy`                                        | `deposited` \| `currentValue` \| `shares` | no       | Sort field.                          |
| `sortOrder`                                     | `asc` \| `desc`                           | no       | Sort direction.                      |
| `limit`, `offset`                               | number                                    | no       | Pagination.                          |
| `afterTransaction`                              | boolean                                   | no       | Bypass cache.                        |

**Response**

```typescript
{
  summary: { positionCount: number; userDeposits: string; averageApy: string };
  positions: Array<{
    vaultId: string;
    vaultName: string;
    deposited: string; depositedUSD: string;
    currentValue: string; currentValueInUSD: string;
    token0Balance: string; token0BalanceUsd: string;
    token1Balance: string; token1BalanceUsd: string;
    shares: string;
    apy: string;
  }>;
}
```

```bash
curl 'https://mainnet-vaults.bonzo.finance/v1/api/vaults/user-positions?account=0xYourAddress'
```

#### Get a User's Position in a Specific Vault

**`GET /v1/api/vaults/user-positions/:id?account=0x…`**

Returns the full position record — including yield breakdown and P\&L — for a single vault.

```typescript
interface UserPositionDetailResponse {
  account: string;
  vaultId: string;
  vaultName: string;
  depositedAsset0: string;   depositedAsset1: string;
  depositedAsset0Usd: string; depositedAsset1Usd: string;
  depositedUSD: string;
  currentValue: string;       currentValueInUSD: string;
  shares: string;
  yield: string;
  yieldData: { yieldAmt: string; yieldAmtUSD: string; yieldPercentage: string };
  pnl:       { amount: string; percentage: string };
  lastUpdated: string;
}
```

```bash
curl 'https://mainnet-vaults.bonzo.finance/v1/api/vaults/user-positions/68d4d6bdcf25aba1bd699033?account=0xYourAddress'
```

#### Charts & Analytics

All chart endpoints share a `timeframe` query parameter that accepts `1D`, `1W`, `1M`, `3M`, `1Y`, `ALL`, or `EVERY` (full snapshot history at native resolution). Defaults vary per endpoint.

**`GET /v1/api/charts/vaults/:id/historical-rate`**

APY/TVL timeseries for a vault, broken down by harvest-window and SaucerSwap fee/LARI APR sources.

```typescript
{
  data: Array<{
    timestamp: string;
    apy: number;
    tvl: number;
    label: string;
    harvestApy7d?: number;
    harvestApy30d?: number;
    saucerswapLariApr?: number;
    saucerswapFeesApr?: number;
    saucerswapManualAprTotal?: number;
  }>;
  timeframe: string;
}
```

```bash
curl 'https://mainnet-vaults.bonzo.finance/v1/api/charts/vaults/:id/historical-rate?timeframe=1M'
```

**`GET /v1/api/charts/vaults/:id/metrics-history`**

Vault-level metrics history — TVL, APY, share price (and per-token share price), total assets, daily yield, and unique user count.

```typescript
{
  data: Array<{
    timestamp: string;
    tvl: number; apy: number; dailyYield: number;
    sharePrice: string;
    sharePriceToken0?: string; sharePriceToken1?: string; sharePriceUsd?: string;
    totalShares: string;
    totalAsset0?: number; totalAsset1?: number;
    userCount: number;
  }>;
  summary: { currentTvl: number; currentApy: number; totalUsers: number; avgDailyYield: number };
}
```

**`GET /v1/api/charts/vaults/:id/portfolio-performance?account=0x…`**

User-specific P\&L chart for a single vault.

```typescript
{
  data: Array<{ timestamp: string; atDeposit: number; currentValue: number; yield: number; totalValue: number }>;
  summary: { totalDeposited: string; currentValue: string; totalYield: string; totalPnl: string; pnlPercentage: string };
}
```

**`GET /v1/api/charts/vaults/:id/risk?days=30`**

Volatility, max drawdown, Sharpe ratio, and 95% VaR computed over the last `days` (1–365, default 30).

```typescript
{
  vaultId: string;
  period: string;
  metrics: { volatility: string; maxDrawdown: string; sharpeRatio: string; valueAtRisk95: string };
  calculatedAt: string;
}
```

**`GET /v1/api/charts/users/:address/positions`**

Snapshot history of all of a user's positions across vaults. Optionally filter to a single `vaultId`.

```typescript
{
  data: Array<{
    timestamp: string;
    asset0TotalDepositedUsd: number; asset1TotalDepositedUsd: number;
    assetTotalDepositedUsd: number; depositedUsd: number;
    yieldInUSD: number;
    token0Balance: number; token1Balance: number;
    token0BalanceUsd: number; token1BalanceUsd: number;
    totalBalanceInUSD: number;
    shares: string; sharePrice: string;
  }>;
  timeframe: string;
}
```

**`GET /v1/api/charts/users/:address/:vaultId/position-history`**

Same shape as above, scoped to a single vault, with both raw and USD-denominated token balances.

**`GET /v1/api/charts/users/:address/harvest-fees`**

Harvest-fee attribution timeseries for a user. Optionally scoped by `vaultId`, `timeframe`, or an explicit `startDate`/`endDate` (ISO 8601). Returns per-harvest fee splits across both pair tokens plus running cumulative totals.

```typescript
{
  userAddress: string;
  vaultId: string;        // or "all"
  totalFeesCollectedUsd: number;
  totalFeesInPeriod: number;
  cumulativeTotals: {
    token0?: { symbol: string; amount: number; amountUsd: number };
    token1?: { symbol: string; amount: number; amountUsd: number };
    totalUsd: number;
  };
  breakdown: { token0?: { symbol; amountInPeriod }; token1?: { symbol; amountInPeriod } };
  data: Array<{
    timestamp: string;
    harvestTxHash: string;
    sharePercentage: number;
    feesCollected: {
      token0?: { symbol; amount; amountUsd; tokenPrice };
      token1?: { symbol; amount; amountUsd; tokenPrice };
      totalUsd: number;
    };
    cumulativeFeesUsd: number;
    /* + cumulative token amounts */
    vaultId: string;
  }>;
  totalHarvests: number;
  filters: { timeframe?: string; startDate?: string; endDate?: string };
}
```

**`GET /v1/api/charts/users/:address/harvest-fees/summary`**

Aggregate-only version of the above — total fees collected, harvest count, average fee per harvest, first/last harvest. Useful for "lifetime earnings" tiles.

**`GET /v1/api/charts/vaults/:id/harvest-fees/users`**

Leaderboard endpoint — every user's cumulative harvest fees in a given vault, ordered descending. Supports `startDate`, `endDate`, and `limit` (1–1000, default 100).

**`GET /v1/api/charts/analytics/overview`**

Snapshot of the platform: TVL, vault count, average APY, total users, total yield generated.

```json
{ "totalValueLocked": "99673.65…", "vaultCount": 4, "averageApy": "6.7775", "totalUsers": 300, "totalYieldGenerated": "$3.38K" }
```

**`GET /v1/api/charts/analytics/platform-stats/latest`**

Most recent daily snapshot of platform-wide totals and revenue split.

```typescript
{
  chainType: "hedera_mainnet";
  date: string;          // YYYY-MM-DDT00:00:00Z bucket
  capturedAt: string;
  totals: { feesUsd: number; revenueUsd: number; withdrawalsUsd: number; vaultsTvlUsd: number; totalVaultsCount: number };
  daily:  { feesUsd: number; revenueUsd: number };
  revenueBreakdown: { feeSharePortionUsd: number; withdrawalSharePortionUsd: number };
}
```

**`GET /v1/api/charts/analytics/platform-stats/history?timeframe=3M`**

Historical timeseries of the same shape, one record per day, for charting protocol-level metrics.

**`GET /v1/api/charts/prices?tokens=HBAR,USDC,SAUCE`**

Spot prices for any comma-separated list of token symbols, returned with their oracle source and capture timestamp.

```json
{
  "prices": {
    "HBAR":  { "usd": 0.08822,    "source": "coingecko", "timestamp": "2026-04-30T04:31:47.808Z" },
    "USDC":  { "usd": 0.999666,   "source": "coingecko", "timestamp": "2026-04-30T04:31:47.724Z" },
    "SAUCE": { "usd": 0.0204217,  "source": "coingecko", "timestamp": "2026-04-30T04:31:47.704Z" }
  },
  "updatedAt": "2026-04-30T04:32:06.812Z"
}
```

#### User Action History

**`GET /v1/api/users/actions?address=0x…`**

On-chain action history for a user — deposits, withdrawals, and harvests — joined to vault metadata.

**Query Parameters**

| Parameter   | Type                                     | Required | Description               |
| ----------- | ---------------------------------------- | -------- | ------------------------- |
| `address`   | string                                   | yes      | User EVM address.         |
| `vaultId`   | string                                   | no       | Filter to a single vault. |
| `sortBy`    | `timestamp` \| `action` \| `blockNumber` | no       | Default `timestamp`.      |
| `sortOrder` | `asc` \| `desc`                          | no       | Default `desc`.           |
| `limit`     | number                                   | no       | 1–100, default 50.        |
| `offset`    | number                                   | no       | Default 0.                |

```typescript
{
  data: Array<{
    id: string;
    vaultId: string;
    vault: { id; name; protocols; strategy; strategyType; vaultType; asset?; assets? };
    chainType: "hedera_mainnet";
    userAddress: string;
    action: "deposit" | "withdraw" | "harvest" | string;
    mode: string;
    assetAmount: string; assetDepositedUsd: string;
    asset0Amount: string; asset1Amount: string;
    totalDepositedUsd: string;
    sharesAmount: string; sharePrice: string;
    txHash: string; blockNumber: number;
    timestamp: string; createdAt: string;
  }>;
  pagination: { total: number; limit: number; offset: number; hasMore: boolean };
}
```

***

### Single-Asset DEX Vaults

Base URL: `https://mainnet-single-asset.bonzo.finance`

Single-asset vaults are ICHI vaults on Hedera. The user deposits a single token (e.g. HBAR or USDC) and the vault internally manages a paired position. The deposited token is referred to as `asset[0]` and the secondary token as `pairToken` / `asset[1]`. Many fields below mirror the dual-asset surface; the differences are noted inline.

{% hint style="info" %}
On the single-asset API, `apy`, `apy30d`, and `daily` are returned as **percent numbers** (e.g. `16.379` means 16.379%), not decimals. Convert accordingly on the consumer side.
{% endhint %}

#### List Vaults

**`GET /v1/api/vaults`**

Returns the set of single-asset (ICHI) vaults along with summary metrics.

**Query Parameters**

| Parameter          | Type                                          | Description                             |
| ------------------ | --------------------------------------------- | --------------------------------------- |
| `protocol`         | string                                        | Filter by protocol (e.g. `SaucerSwap`). |
| `vaultType`        | `single` \| `concentratedLiquidity` \| `ICHI` | Vault type filter.                      |
| `minTvl`, `minApy` | number                                        | Threshold filters.                      |
| `sortBy`           | `tvl` \| `apy` \| `name`                      | Sort field.                             |
| `sortOrder`        | `asc` \| `desc`                               | Sort direction.                         |
| `limit`, `offset`  | number                                        | Pagination (default `limit=50`).        |
| `afterTransaction` | boolean                                       | Bypass cache.                           |

**Response**

```typescript
interface VaultListResponse {
  summary: {
    totalValueLocked: string;
    vaultCount: number;
    averageApy: string;
    userDeposits: string;
  };
  vaults: VaultSummary[];
}
```

Each `VaultSummary` includes:

```typescript
{
  id: string;
  name: string;                       // e.g. "USDC", "HBAR"
  protocols: string[];                // e.g. ["SaucerSwap"]
  network: "Hedera";
  isERC20: boolean;
  isPairTokenERC20: boolean;
  contractAddress: string; contractId: string;
  poolAddress: string; poolEvmAddress: string;
  vaultDeployer: string; vaultDeployerContractId: string;
  vaultFactory: string;
  depositGuard: string; depositGuardContractId: string;
  volatilityCheck: string;
  pairToken: { symbol; address; decimals; contractId };
  assets: Array<{ symbol; address; decimals; contractId }>;
  apy: number;        // percent, e.g. 16.379
  apy30d: number;     // percent
  daily: number;      // percent
  tvl: string;        // USD
  TVL: number;        // USD (numeric duplicate)
  totalAsset0: string; totalAsset1: string;
  totalAsset0InUSD: string; totalAsset1InUSD: string;
  safetyScore: number;
  vaultType: "ICHI" | "single" | "concentratedLiquidity";
  chainType: "hedera_mainnet";
  description: string;
  isHidden: boolean;
  fees: { deposit: number; withdrawal: number; performance: number };
  tabs: { overview: string; risks: object[]; details?: object };
  apyChange24hrs: number;
  tvlChange24hrs: number;
  lastHarvest?: string;
}
```

```bash
curl 'https://mainnet-single-asset.bonzo.finance/v1/api/vaults?sortBy=tvl&sortOrder=desc'
```

#### Get Vault by ID

**`GET /v1/api/vaults/:id`**

Returns the full detail object for a single ICHI vault. Same shape as a list `VaultSummary` plus an optional `userPosition` block when `account` is supplied.

**Query Parameters**

| Parameter          | Type    | Description                                                                     |
| ------------------ | ------- | ------------------------------------------------------------------------------- |
| `account`          | string  | EVM address — when supplied, the response includes the caller's `userPosition`. |
| `afterTransaction` | boolean | Bypass cache.                                                                   |

```typescript
// Embedded when account is supplied
userPosition: {
  token0Balance: string; token1Balance: string;
  token0BalanceUsd: string; token1BalanceUsd: string;
  depositedUsd: string;
  totalBalanceInUSD: string;
  totalBalanceInDepositToken?: string;
  depositTokenSymbol?: string;
  formattedToken0BalanceInUSD: string;
  formattedToken1BalanceInUSD: string;
  formattedTotalBalanceInUSD: string;
  shares: string;
  yieldData?: {
    yieldAmt: string;
    yieldAmtUSD: string;
    yieldPercentage: string;
    yieldAmtInDepositToken?: string;
    breakdown?: {
      token0: { symbol; quantity; quantityUsd };
      token1: { symbol; quantity; quantityUsd };
    };
  };
  pnl?: { amount: string; percentage: string };
}
```

```bash
curl 'https://mainnet-single-asset.bonzo.finance/v1/api/vaults/68d7e3156f4ac0445d628941?account=0xYourAddress'
```

#### List a User's Positions

**`GET /v1/api/vaults/user-positions?account=0x…`**

Returns every single-asset vault position held by a user, with summary totals.

```typescript
{
  summary: { positionCount: number; userDeposits: string; averageApy: string };
  positions: Array<UserPositionSummary>;
}
```

`UserPositionSummary` includes all the same fields as the embedded `userPosition` object on the vault detail response, plus `vaultId`, `vaultName`, `apy`, and `depositedUsd`.

#### Get a User's Position in a Specific Vault

**`GET /v1/api/vaults/user-positions/:id?account=0x…`**

**`GET /v1/api/vaults/:id/users/:address`**

Two equivalent paths for the same data — pick whichever fits your routing style. Returns a single `UserPositionSummary` or `404` if the user has no position in the vault.

```bash
curl 'https://mainnet-single-asset.bonzo.finance/v1/api/vaults/user-positions/68d7e3156f4ac0445d628941?account=0xYourAddress'
```

#### Charts & Analytics

**`GET /v1/api/charts/vault-tvl-apy/:id?timeframe=1M`**

TVL and APY timeseries for a single vault. Returns `apy` as a percent number (matching the vault detail convention).

```typescript
{
  data: Array<{ timestamp: string; apy: number; tvl: number; label: string }>;
  timeframe: string;
}
```

**`GET /v1/api/charts/tvl?timeframe=1M`**

**`GET /v1/api/charts/apy?timeframe=1M`**

Platform-wide TVL and APY timeseries respectively.

```typescript
{
  data: Array<{ timestamp: string; value: number; label?: string }>;
  timeframe: string;
}
```

**`GET /v1/api/charts/portfolio/:address?timeframe=1M`**

User portfolio P\&L chart — same shape as the dual-asset portfolio-performance endpoint:

```typescript
{
  data: Array<{ timestamp: string; atDeposit: number; currentValue: number; yield: number; totalValue: number }>;
  summary: { totalDeposited: string; currentValue: string; totalYield: string; totalPnl: string; pnlPercentage: string };
}
```

**`GET /v1/api/charts/user/:address/positions?timeframe=1M&vaultId=…`**

Per-user, per-vault position snapshots over time. `vaultId` filters to a single vault.

```typescript
{
  data: Array<{
    timestamp: string;
    vaultId: string; vaultName: string;
    shares: string;
    token0Balance: string; token1Balance: string;
    token0BalanceUsd: string; token1BalanceUsd: string;
    totalBalanceInUSD: string;
    formattedToken0BalanceInUSD?: string;
    formattedToken1BalanceInUSD?: string;
    formattedTotalBalanceInUSD?: string;
    yield?: string;
    pnl?: { amount: string; percentage: string };
    apy?: string;
    sharePrice: number; tvl: number;
    vaultType: "single" | "concentratedLiquidity" | "ICHI";
    tokenPrice?: number; tokenPrice0?: number; tokenPrice1?: number;
  }>;
  summary: { totalYield?: string; totalPnl?: number; totalPnlPercentage?: number };
}
```

**`GET /v1/api/charts/vault-performance/:id`**

30-day "Hold vs Vault" comparison series for a vault. Returns five strategy lines: hold deposit token, hold 50/50, Uniswap-style V2 LP, vault, vault with fees. Useful for "is my vault actually beating the alternative?" charts.

**`GET /v1/api/charts/users/:address/harvest-fees`**

Same fee-attribution shape as the dual-asset harvest-fees endpoint, plus an extra `depositTokenSymbol` and `totalFeesCollectedInDepositToken` field that re-prices total fees into the user's deposit token (helpful for single-asset UX). Supports `vaultId`, `timeframe`, `startDate`, `endDate`.

**`GET /v1/api/charts/analytics/overview`**

Platform-level summary. The single-asset service returns pre-formatted strings (e.g. `"$634.83K"`, `"6.39%"`):

```json
{
  "totalValueLocked": "$634.83K",
  "vaultCount": 22,
  "averageApy": "6.39%",
  "totalUsers": 307,
  "totalYieldGenerated": "$4.05K"
}
```

**`GET /v1/api/charts/analytics/global-stats`**

Latest snapshot + cumulative totals for fees and revenue.

```typescript
{
  latestSnapshot: {
    timestamp: string | null;
    totalValueLocked: number;
    totalFeesCollected: number;
    totalRevenue: number;
    vaultCount: number;
  };
  cumulative: { totalFeesCollected: number; totalRevenue: number };
  snapshotCount: number;
}
```

**`GET /v1/api/charts/analytics/global-stats/series?timeframe=1D`**

Time-series version of `global-stats` for charting protocol fees, revenue, and TVL.

```typescript
{
  data: Array<{ timestamp: string; totalValueLocked: number; totalFeesCollected: number; totalRevenue: number }>;
  timeframe: string;
}
```

**`GET /v1/api/charts/analytics/platform-stats/latest`**

**`GET /v1/api/charts/analytics/platform-stats/history?timeframe=EVERY`**

Identical shape to the dual-asset endpoints of the same name (see Dual-Asset Charts & Analytics), tracking per-day totals, revenue, fees, and withdrawals across all single-asset vaults.

#### User Token Balances

**`GET /v1/api/users/balances?address=0x…&tokenList=HBAR,USDC,0x…`**

Returns the user's wallet balances and USD valuations for an arbitrary list of tokens. `tokenList` accepts either symbols or contract addresses, comma-separated.

```typescript
{
  address: string;
  chainType: "hedera_mainnet";
  tokens: Array<{
    address: string;
    symbol: string;
    decimals: number;
    balance: string;
    price: string; priceSource: string;
    valueUSD: string;
    error?: string;            // present only if a single token failed to resolve
  }>;
  totalValueUSD: string;
}
```

```bash
curl 'https://mainnet-single-asset.bonzo.finance/v1/api/users/balances?address=0xYourAddress&tokenList=HBAR,USDC,SAUCE'
```

#### User Action History

**`GET /v1/api/users/actions`**

Same purpose as the dual-asset version — deposits and withdrawals — with a slightly richer per-action payload that captures both raw token amounts and the deposit-token normalization that ICHI vaults expose.

**Query Parameters**

| Parameter             | Type                    | Required                               | Description               |
| --------------------- | ----------------------- | -------------------------------------- | ------------------------- |
| `address`             | string                  | one of `address`/`vaultId` is required | User EVM address.         |
| `vaultId`             | string                  | one of `address`/`vaultId` is required | Filter to a vault.        |
| `action`              | `deposit` \| `withdraw` | no                                     | Action type.              |
| `limit`               | number                  | no                                     | 1–1000, default 100.      |
| `offset`              | number                  | no                                     | Default 0.                |
| `sortBy`, `sortOrder` | string                  | no                                     | Default `timestamp` desc. |

```typescript
{
  success: boolean;
  data: Array<{
    vaultId: string;
    vault: { /* vault metadata snapshot */ } | null;
    chainType: "hedera_mainnet";
    userAddress: string;
    action: "deposit" | "withdraw";
    mode: string;
    assetAmount: string; assetDepositedUsd: string;
    asset0Amount: string; asset1Amount: string;
    asset0Deposited: string; asset1Deposited: string;
    asset0DepositedUsd: string; asset1DepositedUsd: string;
    totalDepositedUsd: string;
    asset0Address: string; asset1Address: string;
    sharesAmount: string; sharePrice: string;
    fee0: string; fee1: string;
    leftover0: string; leftover1: string;
    netDeposited: string; netDepositedUsd: string;
    txHash: string; blockNumber: number;
    timestamp: string; createdAt: string;
  }>;
  pagination: { total: number; limit: number; offset: number; hasMore: boolean };
  filters: { address?; vaultId?; action?; chainType };
}
```

#### Pool Liquidity

The single-asset service exposes the underlying SaucerSwap pool's liquidity directly — useful for estimating slippage or sizing deposits.

**`GET /v1/api/pools/liquidity?tokenAContractId=0.0.X&tokenBContractId=0.0.Y`**

Look up a pool by its token pair using Hedera contract IDs.

**`GET /v1/api/pools/:poolId/liquidity`**

Look up a pool by its pool contract ID directly.

Both return:

```typescript
{
  poolId: string;
  tokenA: { contractId: string; symbol: string; amount: string; decimals: number; priceUsd: number; liquidityUsd: number };
  tokenB: { contractId: string; symbol: string; amount: string; decimals: number; priceUsd: number; liquidityUsd: number };
  totalLiquidityUsd: number;
  timestamp: string;
}
```

```bash
curl 'https://mainnet-single-asset.bonzo.finance/v1/api/pools/liquidity?tokenAContractId=0.0.456858&tokenBContractId=0.0.1456986'
```

***

### Error Handling

Every error response across both services follows the same envelope:

```json
{
  "error": "Bad Request",
  "message": "address is required",
  "status": 400
}
```

Common HTTP statuses you should plan for:

| Status | Meaning                                                            |
| ------ | ------------------------------------------------------------------ |
| `200`  | Success.                                                           |
| `400`  | Bad Request — a required parameter is missing or fails validation. |
| `401`  | Unauthorized — only relevant to the (non-public) `/admin` routes.  |
| `404`  | Not Found — vault or user position does not exist.                 |
| `409`  | Conflict — only emitted by admin endpoints.                        |
| `429`  | Rate Limit Exceeded.                                               |
| `500`  | Internal Server Error — including upstream RPC/oracle failures.    |

{% hint style="warning" %}
Both services currently return `500` (rather than `404`) when a vault `id` is not a valid Mongo ObjectId — e.g. requesting `/v1/api/vaults/foo` will surface an internal cast error. Treat any non-`200` response on a detail lookup as "not available" and re-derive the ID from the list endpoint.
{% endhint %}

***

### Rate Limiting

Each service applies a default IP-based rate limit of **100 requests per 15 minutes** to public routes. Exceeding the limit returns `429` with a standard `Retry-After`-style payload. There is no authentication tier today — well-behaved clients should:

* Cache list responses (TTL ≈ 30s aligns with the server's own cache headers).
* Batch users instead of polling per-user every render.
* Use the `afterTransaction=true` flag only when you actually need fresh state after a write.

***

### Best Practices

* **Use `user-positions` for "My Vaults" views.** It's an order of magnitude faster than calling vault detail per row, because it skips the full yield/PnL pass.
* **Hit `user-positions/:id` only for the vault the user is interacting with.** That is where the full breakdown lives.
* **Refresh state with `?afterTransaction=true` immediately after a deposit/withdraw**, and otherwise let the 30-second cache do its job.
* **Convert APY units before displaying.** Dual-asset returns decimals (`0.157`); single-asset returns percents (`16.379`). Normalize at your ingestion layer.
* **Use `chartType: "ICHI"` to detect single-asset vaults** in any context where a position can come from either service.
* **Snapshot `confidence.level` alongside any APY you display.** A `low` confidence reading with `price_fallback` reasons should be visually distinguished from a `high` confidence harvest-derived APY.
* **Always read both `contractAddress` and `contractId`.** The EVM address is for `eth_*` RPCs and EVM tools; the contract ID is for HashScan and the Hedera mirror node.
* **Implement exponential backoff on 5xx and 429.** Both services are tolerant to bursts but will rate limit aggressive crawlers.

***

### Example: End-to-End Integration

The following snippet pulls a unified "all of my vault positions" view across both services, sorts by current value, and prints a summary.

```javascript
const DUAL  = "https://mainnet-vaults.bonzo.finance/v1/api";
const ICHI  = "https://mainnet-single-asset.bonzo.finance/v1/api";

async function getPortfolio(account) {
  const [dual, ichi] = await Promise.all([
    fetch(`${DUAL}/vaults/user-positions?account=${account}`).then(r => r.json()),
    fetch(`${ICHI}/vaults/user-positions?account=${account}`).then(r => r.json()),
  ]);

  const positions = [
    ...dual.positions.map(p => ({ ...p, source: "dual-asset",   apy: Number(p.apy) * 100 })),
    ...ichi.positions.map(p => ({ ...p, source: "single-asset", apy: Number(p.apy) })),
  ]
    .filter(p => Number(p.totalBalanceInUSD ?? p.currentValueInUSD ?? 0) > 0)
    .sort((a, b) => Number(b.totalBalanceInUSD ?? b.currentValueInUSD) - Number(a.totalBalanceInUSD ?? a.currentValueInUSD));

  const totalUsd = positions.reduce(
    (sum, p) => sum + Number(p.totalBalanceInUSD ?? p.currentValueInUSD ?? 0),
    0,
  );

  return {
    totalValueUsd: totalUsd,
    positionCount: positions.length,
    positions,
  };
}

getPortfolio("0xYourAddress").then(console.log);
```

Drilling into a single position once the user clicks a row:

```javascript
async function getPositionDetail(source, vaultId, account) {
  const base = source === "dual-asset" ? DUAL : ICHI;
  const [position, history] = await Promise.all([
    fetch(`${base}/vaults/user-positions/${vaultId}?account=${account}`).then(r => r.json()),
    source === "dual-asset"
      ? fetch(`${base}/charts/vaults/${vaultId}/portfolio-performance?account=${account}&timeframe=1M`).then(r => r.json())
      : fetch(`${base}/charts/portfolio/${account}?timeframe=1M`).then(r => r.json()),
  ]);
  return { position, history };
}
```

***

### Support

For questions, integration help, or to report a discrepancy in the data, drop into the **#developers** channel in the [Bonzo Discord](https://discord.gg/bonzofinance) or open an issue on the Bonzo docs repo. The Vaults team monitors both during normal business hours.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bonzo.finance/hub/developer/bonzo-vaults/vaults-data-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
