Prerequisites
Set your base URL and API token once, then reuse them for every request. Use sandbox while you build, then switch to production by swapping the base URL. The endpoint structure stays the same, but sandbox uses explicit testnet chain keys such asethereum_sepolia.
cURL
Conventions
- JSON field names are
camelCase. - Enum-like string values (for example
status,type, and webhookevent/eventTypes) arelower_snake_case.- Example:
payout.status = pending_customer_approval
- Example:
1. List available yield sources
Fetch the yield sources you can allocate to. Each yield source has a stableid you will use as yieldSourceId when creating a wallet.
cURL
yieldSources array. Note each source’s id and apyBps to decide your allocation.
2. Create a portfolio wallet
Create a Portfolio Wallet by passingstrategy.allocations with your chosen yield allocation. Allocation percentages must sum to 100.
cURL
yieldSourceId and pct. Legacy positionKey / targetWeightBps payloads remain accepted for backwards compatibility, but new integrations should use yield source IDs.
The response includes the wallet id and depositAddresses per chain. Save the wallet id for the remaining steps:
cURL
3. Deposit actual funds
Send a stablecoin transfer from your custody to the chain you want to fund.Plain
4. Await Deposit Confirmation
Deposits are detected on-chain and then processed. You can track the latest deposit status either by polling the deposits endpoints or by subscribing to webhooks. Poll (REST):- List deposits for a wallet:
GET /v2/wallets/{id}/deposits - Fetch a single deposit:
GET /v2/wallets/{id}/deposits/{depositId}
cURL
portfolio_wallet.deposit.status_changed
deposit.status):
processingcompletedfailed
5. Fetch the updated balance
Fetch the wallet to see current balances after the deposit is processed. Key fields in the response:balance.totalUsd— total wallet value across positions, cash, and accrued yieldbalance.withdrawableUsd— conservative amount the customer can withdraw nowbalance.availableToInitiateUsd— same value on wallet responses, kept for backwards compatibilitybalance.pendingWithdrawalUsd— active withdrawal encumbrancesbalance.earnedUsd— lifetime yield earned since wallet creationpositions[]— current per-source balances and target allocations
cURL
6. Withdraw (including the signing flow)
Ground uses Turnkey to manage signing flows, but you do not need a relationship with Turnkey to sign approvals.
turnkeyActivityId while it is in pending_customer_approval.
cURL
id from the response (this is the withdrawal id used for status checks):
cURL
Signing keys are provisioned and managed in your Ground Portal account. Ensure you always store signing keys safely as lost or compromised keys could result in lost funds.
Node
7. Await Withdrawal Confirmation
After approval (if required), the withdrawal is kicked off automatically. You can track the latest withdrawal status either by polling the withdrawal endpoint or by subscribing to webhooks. Poll (REST):cURL
portfolio_wallet.withdrawal.status_changedportfolio_wallet.withdrawal.payout.status_changed(per-leg payouts)
withdrawal.status):
pendingprocessingcompletedfailedcancelled
withdrawal.payouts[].status):
planningprocessingpending_customer_approvalpending_broadcastbroadcastedcompletedfailedcancelledskipped