> ## Documentation Index
> Fetch the complete documentation index at: https://docs.groundtech.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Example: Treasury Portfolio

Enable automatic rebalancing when Ground should keep funds near percentage
targets. Ground deploys deposits and rebalances the wallet as balances change.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
sequenceDiagram
    participant Treasury
    participant App as "Your application"
    participant Ground

    App->>Ground: Create wallet with auto-rebalance
    Ground-->>App: Wallet and deposit addresses
    Treasury->>Ground: Send stablecoin
    Ground-->>App: Deposit completed
    Ground->>Ground: Deploy toward percentage targets
    Ground-->>App: Rebalance completed
    App->>Ground: Read balances, positions, and yield
    App->>Ground: Create withdrawal
    Ground-->>Treasury: Stablecoin payout
```

Store your API key in `GROUND_API_TOKEN`. The examples below use the sandbox API:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const baseUrl = "https://sandbox.groundtech.co";
const apiToken = process.env.GROUND_API_TOKEN!;
```

## 1. Fetch yield sources

Fetch the available yield sources before creating the wallet. Use the returned
`id` and `depositToken` values when building the strategy.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type YieldSource = {
  id: string;
  name: string;
  depositToken: "usdc" | "usdt";
  apyBps: number | null;
};

const response = await fetch(`${baseUrl}/v2/wallets/yield-sources`, {
  headers: { Authorization: `Bearer ${apiToken}` },
});

if (!response.ok) throw new Error(await response.text());
const catalog = (await response.json()) as { data: YieldSource[] };
```

## 2. Create the wallet

Allocations for each token must total 100%.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type Wallet = {
  id: string;
  autoRebalance: boolean;
  status: string;
  depositAddresses: Record<string, string>;
  positions: Array<{
    id: string;
    kind: string;
    label: string;
    valueUsd: string;
  }>;
};

const response = await fetch(`${baseUrl}/v2/wallets`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    requestId: crypto.randomUUID(),
    label: "Corporate Treasury",
    autoRebalance: true,
    strategy: {
      allocations: {
        usdc: [
          { yieldSourceId: "morpho-august-usdc-v2", pct: 60 },
          { yieldSourceId: "syrup-usdc", pct: 40 },
        ],
      },
    },
  }),
});

if (!response.ok) throw new Error(await response.text());
const treasuryWallet = (await response.json()) as Wallet;
```

The response starts with `status: "creating"`. Subscribe to
`portfolio_wallet.status_changed` before creating the wallet. When the matching
`walletId` reaches `idle`, read `GET /v2/wallets/{id}` to get its deposit
addresses. Handle `failed` as a provisioning failure, and use the wallet read
to reconcile a delayed or missed webhook.

## 3. Deposit funds

Send a supported stablecoin to the matching deposit address. Ground credits the
deposit and deploys the funds toward the target percentages.

Subscribe to these events or poll the related resources:

| Event                                       | Meaning                              |
| ------------------------------------------- | ------------------------------------ |
| `portfolio_wallet.deposit.status_changed`   | The deposit status changed           |
| `portfolio_wallet.rebalance.status_changed` | Deployment or rebalancing progressed |

Wait for the deposit to become `completed` before using it in your application.
See [Deposits](/docs/portfolio-wallets/deposits).

## 4. Read or update the portfolio

Read the wallet to get its current cash, investments, and balances:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const response = await fetch(
  `${baseUrl}/v2/wallets/${treasuryWallet.id}`,
  { headers: { Authorization: `Bearer ${apiToken}` } },
);

if (!response.ok) throw new Error(await response.text());
const currentTreasury = (await response.json()) as Wallet;

console.log(currentTreasury.positions);
```

Ground continues to maintain the target percentages. To change them, call
`PATCH /v2/wallets/{id}/strategy`.

## 5. View yield

Read lifetime earnings, estimated annualized yield, and the current breakdown
by yield source:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type WalletYield = {
  walletId: string;
  earnedUsd: string;
  annualizedUsd: string;
  currentBalanceUsd: string;
  positions: Array<{
    yieldSourceId: string;
    name: string;
    apyBps: number | null;
    deployedValueUsd: string;
  }>;
};

const response = await fetch(
  `${baseUrl}/v2/wallets/${treasuryWallet.id}/yield`,
  { headers: { Authorization: `Bearer ${apiToken}` } },
);

if (!response.ok) throw new Error(await response.text());
const treasuryYield = (await response.json()) as WalletYield;

console.log({
  earnedUsd: treasuryYield.earnedUsd,
  annualizedUsd: treasuryYield.annualizedUsd,
  positions: treasuryYield.positions,
});
```

See [Calculating Yield Accrual](/docs/portfolio-wallets/calculating-yield-accrual)
for display and calculation guidance.

## 6. Withdraw funds

Do not specify funding sources while automatic rebalancing is enabled. Ground chooses the
positions used for the withdrawal.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
const withdrawalRequest = {
  amountUsd: 1_000,
  token: "usdc",
  destinationChain: "ethereum_sepolia",
};

const previewResponse = await fetch(
  `${baseUrl}/v2/wallets/${treasuryWallet.id}/withdrawal-preview`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(withdrawalRequest),
  },
);

if (!previewResponse.ok) throw new Error(await previewResponse.text());
const preview = await previewResponse.json();

const withdrawalResponse = await fetch(
  `${baseUrl}/v2/wallets/${treasuryWallet.id}/withdrawals`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      ...withdrawalRequest,
      requestId: crypto.randomUUID(),
      destinationAddress: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    }),
  },
);

if (!withdrawalResponse.ok) throw new Error(await withdrawalResponse.text());
const withdrawal = await withdrawalResponse.json();

console.log({ preview, withdrawal });
```

Track `portfolio_wallet.withdrawal.status_changed` until the withdrawal
finishes. If it requires customer approval, complete the configured
[transaction approval](/docs/portfolio-wallets/transaction-approvals).

## Test the integration

In sandbox:

1. Create a wallet with automatic rebalancing and wait for `idle`.
2. Deposit test USDC to `depositAddresses.ethereum_sepolia`.
3. Confirm the deposit completes and a rebalance deploys the funds.
4. Confirm `GET /v2/wallets/{id}` returns the new positions.
5. Confirm `GET /v2/wallets/{id}/yield` returns the yield summary.
6. Preview and complete a small withdrawal.

Switch the base URL and API key before using production chain names and
addresses.
