Skip to main content
This quickstart walks through the full Portfolio Wallet lifecycle: quoting a strategy, creating a wallet, funding it, and initiating a withdrawal.

Prerequisites

Create your API key at portal.groundtech.co, then export it below.
export BASE_URL="https://sandbox.groundtech.co"
export GROUND_API_TOKEN="your_api_token"
See API Conventions for authentication, pagination, rate limits, and error handling.

1. Get a strategy quote

Give your liquidity constraints and receive one or more Pareto-optimal strategy options.
curl -X POST "$BASE_URL/v2/wallets/quote" \
  -H "Authorization: Bearer $GROUND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "c3353fff-87cf-4c7c-b68c-2700139dd4e6",
    "minApyTargetBps": 500,
    "liquidityConstraints": [
      { "maxProcessingTime": "PT1H", "minWeightBps": 5000 }
    ]
  }'
Pick the one that best fits your yield/liquidity tradeoff to create your Portfolio Wallet with.

2. Create a Portfolio Wallet

Use the quote response to inform the allocation strategy you’d like for your wallet:
curl -X POST "$BASE_URL/v2/wallets" \
  -H "Authorization: Bearer $GROUND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "0b7e3b4d-88a5-4a75-8c0f-3b7b4f9d9f1d",
    "label": "Treasury Portfolio",
    "strategy": {
      "allocations": [
        { "yieldSourceId": "resolv-lp", "pct": 40 },
        { "yieldSourceId": "usdz", "pct": 60 }
      ]
    }
  }'
The response includes depositAddresses — one per supported chain.

3. Deposit USDC

Send USDC to the wallet’s deposit address on any supported chain. In sandbox, use Sepolia USDC on Ethereum. You can get Sepolia USDC from the Circle faucet or bridge testnet ETH via the Sepolia faucet.

4. Check balance and yield

curl "$BASE_URL/v2/wallets/$WALLET_ID" \
  -H "Authorization: Bearer $GROUND_API_TOKEN"
{
  "id": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db",
  "label": "Treasury Portfolio",
  "createdAt": "2026-02-05T08:15:00.000Z",
  "depositAddresses": {
    "arbitrum": "0x21246509968c4d24611f414560971AEc2e3A079B",
    "ethereum": "0x21246509968c4d24611f414560971AEc2e3A079B"
  },
  "balance": {
    "totalUsd": "82500.000000",
    "withdrawableUsd": "82500.000000",
    "pendingWithdrawalUsd": "0.000000",
    "inTransitUsd": "0.000000",
    "earnedUsd": "1250.000000"
  },
  "positions": [
    { "yieldSourceId": "resolv-lp", "name": "Resolv LP", "valueUsd": "30000.000000", "pct": 40 },
    { "yieldSourceId": "usdz", "name": "T-Bills (M0)", "valueUsd": "52500.000000", "pct": 60 }
  ]
}

5. Preview a withdrawal

curl -X POST "$BASE_URL/v2/wallets/$WALLET_ID/withdrawal-preview" \
  -H "Authorization: Bearer $GROUND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "destinationChain": "polygon",
    "amountUsd": 65000
  }'
{
  "amountUsd": "65000.000000",
  "feeUsd": "0.000000",
  "availableUsd": "82500.000000",
  "estimatedCompletionTime": "PT2H"
}

6. Initiate a withdrawal

curl -X POST "$BASE_URL/v2/wallets/$WALLET_ID/withdraw" \
  -H "Authorization: Bearer $GROUND_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "df8b7be6-e110-4f6d-9b2d-7c44a5b1f0b0",
    "destinationChain": "ethereum",
    "amountUsd": 65000,
    "destinationAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
  }'

7. Track the withdrawal

Poll the withdrawal or subscribe to webhooks:
curl "$BASE_URL/v2/wallets/$WALLET_ID/withdrawals/$WITHDRAWAL_ID" \
  -H "Authorization: Bearer $GROUND_API_TOKEN"
The withdrawal moves through statuses: pendingprocessingcompleted. If Turnkey approval is required, the withdrawal enters processing with customerApprovalState: "required" — see Transaction Approvals.

Next steps