> ## 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.

# Create a Wallet

> Create a portfolio wallet and poll for activation.

Creating a wallet is asynchronous. `POST /v2/wallets` returns immediately with `status: "creating"`. Deposit addresses and on-chain state are not populated synchronously — poll `GET /v2/wallets/{id}` until `status` becomes `"idle"`.

## Create a portfolio wallet

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST "$BASE_URL/v2/wallets" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "0b7e3b4d-88a5-4a75-8c0f-3b7b4f9d9f1d",
    "label": "RWA Yield Portfolio",
    "strategy": {
      "allocations": {
        "usdc": [
          { "yieldSourceId": "ground-ustb-vault", "pct": 50 },
          { "yieldSourceId": "ground-jaaa-usdc-vault", "pct": 50 }
        ],
        "usdt": [
          { "yieldSourceId": "cash", "pct": 100 }
        ]
      }
    }
  }'
```

| Field                  | Required | Description                                                                    |
| ---------------------- | -------- | ------------------------------------------------------------------------------ |
| `requestId`            | Yes      | UUID v4 idempotency key                                                        |
| `label`                | No       | Human-readable wallet name                                                     |
| `strategy`             | Yes      | Object containing `allocations`                                                |
| `strategy.allocations` | Yes      | An object keyed by `usdc` and/or `usdt`. Each included array must sum to 100%. |

Place each yield source under the token it accepts, as shown by its `depositToken` in `GET /v2/wallets/yield-sources`. Use `cash` to keep funds uninvested in that token. If you omit USDC or USDT when creating a wallet, that token defaults to 100% cash.

The request above uses RWA sources available in the production catalog. Both
production and sandbox expose `ground-jaaa-usdt-vault` under `usdt`. Sandbox
also exposes token-specific JTRSY rows when returned by its live catalog:
`ground-jtrsy-usdc-vault` belongs under
`usdc`, and `ground-jtrsy-usdt-vault` belongs under `usdt`. Always use the live
environment-specific catalog rather than assuming a row is active.

A first POST with a new `requestId` returns **`200 OK`** with a minimal creating envelope (no deposit addresses, zero balances). An idempotent replay with the same `requestId` **and an identical payload** returns **`200 OK`** with the wallet's current state. Reusing a `requestId` with a **divergent payload** (different label or allocations) returns **`409 request_id_conflict`** — use a fresh `requestId` for a genuinely new wallet. See [Idempotency](/docs/portfolio-wallets/api-conventions#idempotency) for the full comparison rules.

## Creating response

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db",
  "label": "RWA Yield Portfolio",
  "status": "creating",
  "failureReason": null,
  "createdAt": "2026-02-05T08:15:00Z",
  "depositAddresses": {},
  "balance": {
    "totalUsd": "0.000000",
    "withdrawableUsd": "0.000000",
    "reservedUsd": "0.000000",
    "earnedUsd": "0.000000"
  },
  "positions": [],
  "strategyAllocations": {
    "usdc": [
      { "yieldSourceId": "ground-ustb-vault", "targetWeightBps": 5000 },
      { "yieldSourceId": "ground-jaaa-usdc-vault", "targetWeightBps": 5000 }
    ],
    "usdt": [
      { "yieldSourceId": "cash", "targetWeightBps": 10000, "token": "usdt", "chain": "ethereum" }
    ]
  }
}
```

## Polling for activation

Poll `GET /v2/wallets/{id}` every 1-2 seconds until `status !== "creating"`:

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
async function waitUntilReady(walletId, apiToken) {
  while (true) {
    const res = await fetch(`${BASE_URL}/v2/wallets/${walletId}`, {
      headers: { Authorization: `Bearer ${apiToken}` },
    });
    const wallet = await res.json();
    if (wallet.status === "idle") return wallet;
    if (wallet.status === "failed") {
      throw new Error(`wallet ${walletId} failed: ${wallet.failureReason}`);
    }
    await new Promise((r) => setTimeout(r, 1500));
  }
}
```

See [Polling](/docs/portfolio-wallets/polling) for more on the poll pattern.

## Ready response

Once `status === "idle"`, the response is ready for deposits:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db",
  "label": "RWA Yield Portfolio",
  "status": "idle",
  "failureReason": null,
  "createdAt": "2026-02-05T08:15:00Z",
  "depositAddresses": {
    "arbitrum": "0x21246509968c4d24611f414560971AEc2e3A079B",
    "base": "0x21246509968c4d24611f414560971AEc2e3A079B",
    "ethereum": "0x21246509968c4d24611f414560971AEc2e3A079B",
    "polygon": "0x21246509968c4d24611f414560971AEc2e3A079B",
    "solana": "7nYzKxM3bP4oEFbqkPmA5E2rYJ8HqKz8vFg9abc1"
  },
  "balance": {
    "totalUsd": "0.000000",
    "withdrawableUsd": "0.000000",
    "reservedUsd": "0.000000",
    "earnedUsd": "0.000000"
  },
  "positions": [
    {
      "id": "ground-ustb-vault",
      "kind": "yield_source",
      "label": "Invesco USTB tokenized by Superstate",
      "valueUsd": "0.000000",
      "yieldSourceId": "ground-ustb-vault",
      "pct": 50
    },
    {
      "id": "ground-jaaa-usdc-vault",
      "kind": "yield_source",
      "label": "Janus Henderson JAAA (USDC)",
      "valueUsd": "0.000000",
      "yieldSourceId": "ground-jaaa-usdc-vault",
      "pct": 50
    }
  ],
  "strategyAllocations": {
    "usdc": [
      { "yieldSourceId": "ground-ustb-vault", "targetWeightBps": 5000 },
      { "yieldSourceId": "ground-jaaa-usdc-vault", "targetWeightBps": 5000 }
    ],
    "usdt": [
      { "yieldSourceId": "cash", "targetWeightBps": 10000, "token": "usdt", "chain": "ethereum" }
    ]
  }
}
```

### Key fields

| Field                     | Description                                                                                                                                                                                     |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`                  | `"creating"` during provisioning, `"idle"` when ready, `"withdrawal_active"` / `"rebalance_active"` / `"withdrawal_and_rebalance_active"` while work is running, `"failed"` if setup terminated |
| `failureReason`           | Populated only when `status === "failed"` — short human-readable reason                                                                                                                         |
| `depositAddresses`        | Per-chain addresses to fund the wallet. Empty until `status === "idle"`.                                                                                                                        |
| `balance.totalUsd`        | Total economically owned wallet value                                                                                                                                                           |
| `balance.withdrawableUsd` | Amount that can be withdrawn now                                                                                                                                                                |
| `balance.reservedUsd`     | Customer-owned value currently reserved by active withdrawals or rebalances                                                                                                                     |
| `balance.earnedUsd`       | Lifetime yield earned (monotonic)                                                                                                                                                               |
| `positions`               | Current cash and yield-source holdings with USD values. Yield-source positions include `yieldSourceId` and `pct`; configured cash allocations may also include `pct`.                           |
| `strategyAllocations`     | Desired targets grouped by stablecoin. Target weights use basis points and each returned group totals 10,000.                                                                                   |

## Failed response

If wallet setup fails terminally, `GET /v2/wallets/{id}` returns:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db",
  "label": "Core Yield Portfolio",
  "status": "failed",
  "failureReason": "Turnkey create_wallet activity ACTIVITY_STATUS_REJECTED: act_abc",
  "createdAt": "2026-02-05T08:15:00Z",
  "depositAddresses": {},
  "balance": { "totalUsd": "0.000000", "withdrawableUsd": "0.000000", "reservedUsd": "0.000000", "earnedUsd": "0.000000" },
  "positions": []
}
```

Failed wallets cannot be recovered by retrying the same `requestId`. Create a new wallet with a fresh `requestId` and contact support if the failure reason is unclear.

## Rebalancing

Portfolio wallets are best-effort targets. Over time, or after deposits and withdrawals, holdings drift from target allocations. The system rebalances to bring positions back toward the strategy targets. Deposits first appear as cash and are then deployed into the configured yield sources.

## Sandbox notes

In sandbox, deposit address keys include the network suffix (e.g. `ethereum_sepolia` instead of `ethereum`). Sandbox USDT uses a Ground-owned mock contract. See [Supported Chains](/docs/portfolio-wallets/supported-chains) for details.
