Skip to main content
Create a wallet with a positions array defining your yield allocation strategy. You can source positions from POST /v2/portfolio-wallets/quote (see Yield Sources & Strategy Quoting) or specify them manually.

Create a portfolio wallet

curl -X POST "$BASE_URL/v2/portfolio-wallets" \
  -H "Authorization: Bearer $BRAID_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "0b7e3b4d-88a5-4a75-8c0f-3b7b4f9d9f1d",
    "label": "Treasury Portfolio",
    "positions": [
      { "positionKey": "usdz", "targetWeightBps": 6000 },
      { "positionKey": "rlp", "targetWeightBps": 4000 }
    ]
  }'
FieldRequiredDescription
requestIdYesUUID v4 idempotency key
labelYesHuman-readable wallet name
positionsYesArray of { positionKey, targetWeightBps }. Weights must sum to 10,000 bps.
Each position must include positionKey (from the yield source catalog) and targetWeightBps (integer, 0–10000).

Wallet response

The canonical wallet response (GET /v2/portfolio-wallets/:id) answers two questions: what is the wallet’s total value, and what is it targeting vs actually holding?
{
  "id": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db",
  "requestId": "0b7e3b4d-88a5-4a75-8c0f-3b7b4f9d9f1d",
  "label": "Treasury Portfolio",
  "blendedRateBps": 565,
  "status": "active",
  "createdAt": "2026-02-05T08:15:00.000Z",
  "updatedAt": "2026-02-05T10:05:00.000Z",
  "depositAddresses": {
    "arbitrum": "0x21246509968c4d24611f414560971AEc2e3A079B",
    "ethereum": "0x21246509968c4d24611f414560971AEc2e3A079B"
  },
  "globalWalletBalance": 82500,
  "targetPositions": [
    { "positionKey": "usdz", "targetWeightBps": 6000, "maxProcessingTime": "PT0H" },
    { "positionKey": "rlp", "targetWeightBps": 4000, "maxProcessingTime": "PT24H" }
  ],
  "actualPositions": [
    {
      "positionKey": "usdz",
      "asset": "usdz",
      "chain": "arbitrum",
      "balanceUnits": 52500,
      "valueUsd": 52500,
      "actualWeightBps": 6120,
      "targetWeightBps": 6000,
      "driftBps": 120,
      "updatedAt": "2026-02-05T10:06:00.000Z"
    },
    {
      "positionKey": "rlp",
      "asset": "rlp",
      "chain": "ethereum",
      "balanceUnits": 25000,
      "valueUsd": 30000,
      "actualWeightBps": 3880,
      "targetWeightBps": 4000,
      "driftBps": -120,
      "updatedAt": "2026-02-05T10:06:00.000Z"
    }
  ],
  "liquidityProfile": [
    { "maxProcessingTime": "PT0H", "weightBps": 6000 },
    { "maxProcessingTime": "PT24H", "weightBps": 4000 }
  ]
}

Key fields

FieldDescription
globalWalletBalanceTotal wallet value (principal + yield) across all positions
blendedRateBpsWeighted average APR across strategy positions
depositAddressesPer-chain addresses to fund the wallet (deposit rails only)
targetPositionsConfigured allocation targets
actualPositionsCurrent holdings with USD values and drift vs targets
liquidityProfileSummarizes how fast each portion of the wallet can be withdrawn

Cash positions

actualPositions can include synthetic cash_* entries (e.g. cash_usdc:cctp) for undeployed USDC. Cash positions represent idle funds that haven’t been invested into a yield position yet. They are excluded from drift calculations. See Withdraw Funds for how cash interacts with withdrawals.

Rebalancing and drift

Portfolio wallets are best-effort targets. Over time (or after deposits/withdrawals), holdings can drift from target weights. The wallet response includes:
  • actualPositions[].driftBps — per-position drift vs target weight
  • driftSummarymaxDriftBps and withinTolerance boolean
  • rebalancePolicy — effective server-side rebalance parameters
The system periodically rebalances to bring positions back toward target weights. Small deposits may remain as cash until it is economically worth deploying (considering gas, minimum trade sizing, and protocol constraints).

Sandbox notes

In sandbox, depositAddresses.ethereum is a Sepolia address and depositAddresses.solana is a Solana devnet address. The positionKey values and request shapes are identical to production. usdz is simulated in sandbox because USDZ is not available on testnets. The positionKey remains usdz for integration parity.