> For the complete documentation index, see [llms.txt](https://docs.buoy.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.buoy.finance/developers/rest-api.md).

# REST API

Buoy's backend exposes a public, read-only REST API — the same one the official app uses. It serves indexed vault data, analytics, live quotes, live per-venue allocation, depositor leaderboards, and user positions, so you don't need to run your own indexer.

## Base URL

```
https://europe-west1-buoy-loan.cloudfunctions.net/app/api/v1
```

An interactive Swagger UI and the OpenAPI 3.1 document are served by the API itself at `/docs` and `/openapi.json` under the same base. That spec covers the core surface (vaults, drafts, performance, quotes, positions, leaders, stats, builders, ingest); a few newer read endpoints — allocation, depositors, trading-agent, agent-eligibility — are documented on this page but not yet in the spec.

All read endpoints below are public and require no authentication.

## Vaults

| Endpoint                                 | Returns                                                                                                                                                                                                                                                                                                                   |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /vaults`                            | Paginated vault list. Params: `offset`, `limit` (max 100, default 20), `sort` (`apr`\|`age`\|`name`\|`createdAt`, default `apr`), `order` (`asc`\|`desc`), `featured`, `leader`                                                                                                                                           |
| `GET /vaults/{address}`                  | Full vault detail — adds `description`, `performanceFeeBps`, `router`, `factory`, `asset`                                                                                                                                                                                                                                 |
| `GET /vaults/{address}/performance`      | Chart time-series. Params: `range` (`1d`\|`7d`\|`30d`\|`90d`\|`1y`\|`all`, default `30d`), `metric` (`pnl`\|`accountValue`\|`pps`, default `pnl`), `resolution` (`auto`\|`1m`\|`5m`\|`15m`\|`1h`\|`4h`\|…)                                                                                                                |
| `GET /vaults/{address}/allocation`       | Live per-venue capital breakdown: `abstractionMode`, spot USDC, each perp venue (default + HIP-3) with `accountValue` / `withdrawable` / `unrealizedPnl` / `collateralSymbol` / `usdcCollateral`, and EVM-side USDC                                                                                                       |
| `GET /vaults/{address}/depositors`       | Depositor leaderboard, sorted by current value: `shares`, `vaultAmountUsdc`, `totalDepositedUsdc`, `totalWithdrawnUsdc`, `allTimePnlUsdc`. Params: `offset`, `limit` (max 100)                                                                                                                                            |
| `GET /vaults/{address}/whitelist`        | The vault's depositor whitelist: `whitelistEnabled` and `entries[]` of `{ account, capUsdc, updatedAtBlock }` (position cap in USDC base units; addresses with a cap of 0 are not listed). Empty and `false` on pre-v3 vaults. What each address has used against its cap is `VaultPolicy.depositedUsdcOf`, read on-chain |
| `GET /vaults/{address}/trading-agent`    | Live HyperCore agent status: `agent`, `registered`, `state` (`registered`\|`unset`\|`unregistered`\|`expired`), `needsSetup`, `validUntil`                                                                                                                                                                                |
| `GET /vaults/agent-eligibility?address=` | Whether an address can be registered as a vault's HyperCore API wallet (Core rejects addresses that already have a Hyperliquid account)                                                                                                                                                                                   |

### Vault fields worth knowing

* `apr` — headline APR, computed **identically to Hyperliquid vaults**: `r30 = PnL(30d) / (TVL − PnL(30d))`, multiplied by 12 when positive and reported raw (un-annualized) when negative.
* `pastMonthReturn` — the raw `r30` behind `apr`.
* `currentApr` — a simple 7-day annualized return, for a shorter-horizon view.
* `maxDrawdownPct` — worst peak-to-trough share-price drop, as a fraction.
* `sparkline` — cumulative dollar-PnL points over the last 30 days (the same series the list thumbnail plots), so its shape always agrees with the sign of `apr`.
* `riskLevel` (`low`|`medium`|`high`), `strategy` (`market_neutral`|`directional`|`long_biased`), `xHandle`, `image`, `tagline`, `badges` — leader-declared profile fields, `null` until set.
* `status` — `active` | `paused` | `wound_down`.
* `minLeaderShareBps`, `maxTvlUsdc`, `whitelistEnabled` — the vault's [deposit limits](/for-vault-leaders/deposit-limits.md) (vault v3): the Leader's minimum share in bps (`0` = none), the TVL cap in USDC base units (`null` = none) and whether the depositor whitelist is on. Pre-v3 vaults report `0` / `null` / `false`.
* `tvl` — **gross** NAV in the asset's base units: HyperCore spot + perp/HIP-3 venues + the vault's EVM-side USDC, minus uncredited pending deposits. It does **not** subtract locked withdrawal obligations (`totalOwedUsdc`). On `GET /vaults/{address}` it's a live value cached up to 5 minutes (invalidated by any on-chain event for that vault); on `GET /vaults` the overlay is non-blocking and may fall back to the last stored snapshot.

{% hint style="warning" %}
Gross vs net matters. If you need the value backing the remaining shares — for position sizing, for example — subtract the vault's on-chain `totalOwedUsdc()`, or read `pricePerShare` from a quote endpoint, which is computed from a freshly read live NAV and already nets obligations out. See [Automating a Vault Strategy](/developers/automating-a-strategy.md).
{% endhint %}

{% hint style="info" %}
A vault younger than the metric's window annualizes over the **full window**, not its short lifetime, so a day-one gain reads as if it were earned over 30 days rather than exploding ×365. Young-vault figures are still noisy — treat them as directional, not predictive.
{% endhint %}

## Quotes

Pre-trade estimates combining on-chain state with live pricing — use these before sending a request:

| Endpoint                                          | Returns                                                                                                                                                                                                                                                                                                                |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /vaults/{address}/quote/deposit?amountUsdc=` | `expectedShares`, `minShares` (slippage floor), `pricePerShare`, `nativeFeeWei`, `interactionNonce`, `projectedYield`, `warnings`, and — when `user` is given and the vault has a binding deposit limit — `maxDepositUsdc`, the most that wallet could deposit right now. Optional: `slippageBps` (default 50), `user` |
| `GET /vaults/{address}/quote/withdraw?shares=`    | `expectedUsdc`, `minOut`, `pricePerShare`, `nativeFeeWei`, `interactionNonce`, `warnings`. Optional: `slippageBps`, `user`                                                                                                                                                                                             |

Quote responses include a `warnings` array worth surfacing to users — deposit quotes can carry `vault_paused`, `insufficient_usdc`, `insufficient_native` and `exceeds_max_deposit` (the amount is above `maxDepositUsdc`: the vault's contract would refuse the request outright — see [Deposit Limits](/for-vault-leaders/deposit-limits.md)); withdraw quotes `vault_paused`, `insufficient_shares`, `insufficient_liquidity`, `insufficient_native`.

## Users & positions

| Endpoint                                 | Returns                                                                                                                                                |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET /users/{address}/positions`         | All vault positions for a wallet: live share balance, open pending requests, recently settled requests. `?includeEmpty=true` to include zero positions |
| `GET /users/{address}/positions/{vault}` | Single-vault position                                                                                                                                  |

## Referrals

| Endpoint                        | Returns                                                                                                                                                                                                                                                                                                    |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /referrals/config`         | Program parameters: `referrerShareBps`, `refereeShareBps` (BPS of the referral fee — `protocolFeeShareBps` on-chain), `distributorAddress`, `claimingEnabled`                                                                                                                                              |
| `GET /referrals/{code}`         | Resolves a referral code to its owner (`code`, `ownerAddress`, `multiplier`, `createdAt`); 404 when unknown                                                                                                                                                                                                |
| `GET /users/{address}/referral` | The wallet's referral dashboard: its `code` (minted on first read — codes are derived from the address), `referredBy`, `referredUsers`, `accruedUsdc` with the `accruedAsReferrerUsdc` / `accruedAsRefereeUsdc` breakdown, `claimedUsdc` (read live from the RewardsDistributor), `claimableUsdc`, `rates` |

The two writes are wallet-signed rather than session-authed (see [Write endpoints](#write-endpoints)): `POST /users/{address}/referral/attribution` binds a wallet to the code it arrived with, and `POST /users/{address}/referral/claim-signature` returns a fresh backend signature for `RewardsDistributor.claim` — `cumulativeAmount` (the wallet's lifetime total; the contract pays the delta), `deadline`, `signature`, `distributorAddress`. It answers 409 when there is nothing to claim and 503 when claiming is not configured on the deployment.

## Leaders, stats, builders

| Endpoint                        | Returns                                                                                                     |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `GET /leaders/{address}`        | Leader profile: display name, bio, socials                                                                  |
| `GET /leaders/{address}/vaults` | All vaults run by a leader                                                                                  |
| `GET /stats`                    | Global stats: `vaultCount`, `leaderCount`, `totalUsers`, `weightedApr` (NAV-weighted across vaults), `asOf` |
| `GET /builders`                 | Protocol-whitelisted builders / trading terminals: name, fee rate, address, website                         |

## Data conventions

* **Token amounts and prices are integer base units serialized as strings** — never floats, never human-scaled decimals. USDC and shares use 6 decimals, native amounts 18, prices/ratios are 1e18-scaled. Example: `"1234560000"` = 1,234.56 USDC. Parse with a big-int library.
* **Rates:** on-chain rates in integer bps (`performanceFeeBps: 1000` = 10%); builder fees in decibps; analytics as fractional numbers (`0.1234` = 12.34%).
* **Timestamps:** RFC 3339 strings, unless a field is suffixed `Unix` (seconds). Exception: `timestamp` inside chart/sparkline points is Unix seconds.
* **Addresses:** serialized EIP-55 checksummed; lookups are case-insensitive.
* **Caching:** the list and stats endpoints are served from a short-lived cache (5 s and 30 s respectively), and listed TVL is overlaid with a live NAV value when one is warm — so two calls seconds apart can differ slightly.

## Write endpoints

The API's write surface is used by the official app:

* **Vault metadata drafts** (`POST /vaults/drafts`, `/drafts/{token}/image`, `/drafts/{token}/claim`) — the onboarding handshake that captures a vault's description, X handle and avatar before deployment, then binds them to the deployed address by verifying the on-chain leader.
* **Metadata edits** (`PATCH /vaults/{address}/metadata`) — authorized with an **EIP-712 signature from the vault's leader wallet**, verified against the on-chain leader. No account, no API key, no gas.
* **Referral attribution** (`POST /users/{address}/referral/attribution`) — binds a wallet to a referral code, authorized with an EIP-712 signature from that wallet over `ReferralAttribution(address account, string code)` (domain `Buoy` / `1` / chain id, no verifying contract). First-touch and permanent; refused once the wallet has ever deposited. **Claim signatures** (`POST /users/{address}/referral/claim-signature`) need no auth — the signature they return only ever pays the wallet it names.
* **Transaction ingest** (`POST /ingest/tx`) — a fast path that lets the app surface its own transactions before the indexer catches up. Authenticated (Firebase auth + App Check + per-uid rate limit).
* **Admin** (`PUT /admin/...`) — bearer-token gated, protocol-team only.

Leader-authored text and images are screened by automated moderation (Google Cloud Natural Language for text, SafeSearch for images) before publication.

For funds-related actions there is deliberately **no API**: deposits and withdrawals are on-chain only, from the user's own wallet.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.buoy.finance/developers/rest-api.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
