Poll until wallet is ready
After creating a wallet, pollGET /v2/wallets/{id} every 1-2 seconds until status !== "creating":
cURL
while true; do
STATUS=$(curl -s "$BASE_URL/v2/wallets/$WALLET_ID" \
-H "Authorization: Bearer $GROUND_API_KEY" | jq -r .status)
if [ "$STATUS" = "idle" ] || [ "$STATUS" = "failed" ]; then break; fi
sleep 1.5
done
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));
}
}
import time, requests
def wait_until_ready(wallet_id, api_token):
while True:
r = requests.get(
f"{BASE_URL}/v2/wallets/{wallet_id}",
headers={"Authorization": f"Bearer {api_token}"},
)
wallet = r.json()
if wallet["status"] == "idle":
return wallet
if wallet["status"] == "failed":
raise RuntimeError(f"wallet {wallet_id} failed: {wallet['failureReason']}")
time.sleep(1.5)
List wallets
cURL
curl -X GET "$BASE_URL/v2/wallets?limit=25" \
-H "Authorization: Bearer $GROUND_API_KEY"
const res = await fetch(`${BASE_URL}/v2/wallets?limit=25`, {
headers: { Authorization: `Bearer ${GROUND_API_KEY}` },
});
console.log(await res.json());
import requests
res = requests.get(
f"{BASE_URL}/v2/wallets?limit=25",
headers={"Authorization": f"Bearer {GROUND_API_KEY}"},
)
print(res.json())
cURL
curl -X GET "$BASE_URL/v2/wallets?limit=25&cursor=$NEXT_CURSOR" \
-H "Authorization: Bearer $GROUND_API_KEY"
const res = await fetch(`${BASE_URL}/v2/wallets?limit=25&cursor=${NEXT_CURSOR}`, {
headers: { Authorization: `Bearer ${GROUND_API_KEY}` },
});
console.log(await res.json());
import requests
res = requests.get(
f"{BASE_URL}/v2/wallets?limit=25&cursor={NEXT_CURSOR}",
headers={"Authorization": f"Bearer {GROUND_API_KEY}"},
)
print(res.json())
Get a single wallet
cURL
curl -X GET "$BASE_URL/v2/wallets/$WALLET_ID" \
-H "Authorization: Bearer $GROUND_API_KEY"
const res = await fetch(`${BASE_URL}/v2/wallets/${WALLET_ID}`, {
headers: { Authorization: `Bearer ${GROUND_API_KEY}` },
});
console.log(await res.json());
import requests
res = requests.get(
f"{BASE_URL}/v2/wallets/{WALLET_ID}",
headers={"Authorization": f"Bearer {GROUND_API_KEY}"},
)
print(res.json())
List deposits
cURL
curl -X GET "$BASE_URL/v2/wallets/$WALLET_ID/deposits?limit=50" \
-H "Authorization: Bearer $GROUND_API_KEY"
const res = await fetch(`${BASE_URL}/v2/wallets/${WALLET_ID}/deposits?limit=50`, {
headers: { Authorization: `Bearer ${GROUND_API_KEY}` },
});
console.log(await res.json());
import requests
res = requests.get(
f"{BASE_URL}/v2/wallets/{WALLET_ID}/deposits?limit=50",
headers={"Authorization": f"Bearer {GROUND_API_KEY}"},
)
print(res.json())
Activity feed
The activity endpoint provides a unified, reverse-chronological feed of customer-visible deposits, withdrawals, and rebalances. Usescope=all for organization-wide activity, or pass one or more walletId parameters to filter to specific wallets.
In workflow details, use endpoint IDs and stepKind to identify products and
actions. Labels and step names are display text.
cURL
curl -X GET "$BASE_URL/v2/activity?walletId=$WALLET_ID&limit=20" \
-H "Authorization: Bearer $GROUND_API_KEY"
const res = await fetch(`${BASE_URL}/v2/activity?walletId=${WALLET_ID}&limit=20`, {
headers: { Authorization: `Bearer ${GROUND_API_KEY}` },
});
console.log(await res.json());
import requests
res = requests.get(
f"{BASE_URL}/v2/activity?walletId={WALLET_ID}&limit=20",
headers={"Authorization": f"Bearer {GROUND_API_KEY}"},
)
print(res.json())
| Param | Description |
|---|---|
limit | Max items per page. Runtime clamps invalid, missing, and oversized values into the supported 1-100 range. |
cursor | Opaque cursor from nextCursor for pagination |
walletId | Optional repeatable wallet ID filter. |
scope | Optional all for organization-wide activity. |
type | Optional type filter: deposit, withdrawal, or rebalance |
status | Optional comma-separated status filter: created, processing, completed, partially_completed, failed, cancelled, or all |
startAt | Optional inclusive ISO-8601 UTC lower bound for activity timestamps. |
endAt | Optional exclusive ISO-8601 UTC upper bound for activity timestamps. |
curl -X GET "$BASE_URL/v2/activity?walletId=$WALLET_ID&status=created,processing&limit=20" \
-H "Authorization: Bearer $GROUND_API_KEY"
{
"data": [
{
"id": "8f9720c1-2679-4d56-afc3-9b18edb83ce2",
"type": "deposit",
"status": "processing",
"amountUsd": "5000.000000",
"timestamp": "2026-02-05T09:40:00.000Z",
"deposit": {
"id": "8f9720c1-2679-4d56-afc3-9b18edb83ce2",
"amount": "5000.000000",
"token": "usdc",
"chain": "ethereum",
"fromAddress": "0xfeed00000000000000000000000000000000beef",
"txHash": "0xb4ec6ad9f2f2d75fb8df30c6e49b1f319138f0172d7bff7c402e7dcb7f017e8a",
"status": "processing",
"createdAt": "2026-02-05T09:40:00.000Z",
"completedAt": null,
"walletId": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db",
"cashPositionId": null
},
"walletId": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db"
},
{
"id": "11b17950-1f5c-4d36-8f0d-0f3d1d0c6a45",
"type": "withdrawal",
"status": "processing",
"amountUsd": "65000.000000",
"timestamp": "2026-02-05T11:00:00.000Z",
"withdrawal": {
"id": "11b17950-1f5c-4d36-8f0d-0f3d1d0c6a45",
"amountRequestedUsd": "65000.000000",
"amountPaidUsd": null,
"amountPaidToPartnerUsd": null,
"feeUsd": "0.000000",
"destinationChain": "ethereum",
"destinationAddress": "0x76F8fc6667E239f83a547d4e16225d6a34f6FA22",
"destinationToken": "usdc",
"status": "processing",
"legsCompleted": 0,
"legsTotal": 1,
"payoutLegs": [
{
"status": "pending_customer_approval",
"amountUsd": "65000.000000",
"from": {
"kind": "yield_source",
"id": "syrup-usdc",
"label": "Syrup USDC"
},
"to": {
"kind": "external_payout",
"id": "external_payout:ethereum:usdc",
"label": "External payout (Ethereum)"
},
"startedAt": "2026-02-05T11:00:00.000Z",
"completedAt": null,
"stepsCompleted": 1,
"stepsTotal": 2,
"steps": [
{
"name": "Redeeming from Syrup USDC",
"stepKind": "yield_source_redeem",
"sequenceRole": "yield_redeem",
"protocolType": "syrup",
"stepOrdinal": 0,
"chain": "ethereum",
"txKind": "yield_source_redeem",
"state": "completed",
"startedAt": "2026-02-05T11:01:00.000Z",
"completedAt": "2026-02-05T11:02:00.000Z",
"cancelledAt": null
},
{
"name": "Sending payout",
"stepKind": "external_payout_transfer",
"sequenceRole": "external_payout_transfer",
"protocolType": "external_payout",
"stepOrdinal": 1,
"chain": "ethereum",
"txKind": "external_payout_transfer",
"state": "pending_customer_approval",
"startedAt": "2026-02-05T11:03:00.000Z",
"completedAt": null,
"cancelledAt": null
}
]
}
],
"failureReason": null,
"createdAt": "2026-02-05T11:00:00.000Z",
"completedAt": null
},
"walletId": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db"
},
{
"id": "449f9ed4-b924-4a2d-9b18-e372cc5c4d65",
"type": "rebalance",
"status": "created",
"amountUsd": "12000.000000",
"timestamp": "2026-02-05T12:00:00.000Z",
"rebalance": {
"id": "449f9ed4-b924-4a2d-9b18-e372cc5c4d65",
"status": "created",
"createdAt": "2026-02-05T12:00:00.000Z",
"updatedAt": "2026-02-05T12:00:00.000Z",
"startedAt": "2026-02-05T12:00:00.000Z",
"completedAt": null,
"legsCompleted": 0,
"legsTotal": 1,
"amountUsd": "12000.000000",
"rebalanceLegs": [
{
"status": "created",
"amountUsd": "12000.000000",
"from": {
"kind": "cash",
"id": "cash:base:usdc",
"label": "Cash (Base)"
},
"to": {
"kind": "yield_source",
"id": "morpho-gauntlet-usdc",
"label": "Morpho Gauntlet USDC Prime"
},
"startedAt": "2026-02-05T12:00:00.000Z",
"completedAt": null,
"stepsCompleted": 0,
"stepsTotal": 1,
"steps": [
{
"name": "Depositing into Morpho Gauntlet USDC Prime",
"stepKind": "yield_source_deposit",
"sequenceRole": "yield_deposit",
"protocolType": "morpho",
"stepOrdinal": 0,
"chain": "ethereum",
"txKind": "yield_source_deposit",
"state": "created",
"startedAt": null,
"completedAt": null,
"cancelledAt": null
}
]
}
],
"failureReason": null
},
"walletId": "9d1a1c83-3a1c-4c14-9c5a-0c9a57a4a7db"
}
],
"nextCursor": null
}
nextCursor as cursor to fetch the next page. See API
Conventions for the list envelope.
| Field | Description |
|---|---|
data | Activity items for the current page. |
data[].id | Unique ID for the activity parent |
data[].type | "deposit", "withdrawal", or "rebalance" |
data[].status | Public status: created, processing, completed, failed, or cancelled |
data[].amountUsd | Amount as a fixed-precision decimal string (6 decimal places) |
data[].timestamp | ISO-8601 timestamp of when the activity occurred |
data[].deposit | Present for deposit rows |
data[].withdrawal | Present for withdrawal rows |
data[].rebalance | Present for rebalance rows |
nextCursor | Opaque cursor for the next page, or null |
List withdrawals
Filter by status to monitor in-flight withdrawals:cURL
curl -X GET "$BASE_URL/v2/wallets/$WALLET_ID/withdrawals?status=processing&limit=50" \
-H "Authorization: Bearer $GROUND_API_KEY"
const res = await fetch(
`${BASE_URL}/v2/wallets/${WALLET_ID}/withdrawals?status=processing&limit=50`,
{ headers: { Authorization: `Bearer ${GROUND_API_KEY}` } },
);
console.log(await res.json());
import requests
res = requests.get(
f"{BASE_URL}/v2/wallets/{WALLET_ID}/withdrawals",
params={"status": ["processing"], "limit": 50},
headers={"Authorization": f"Bearer {GROUND_API_KEY}"},
)
print(res.json())
Deposit address readiness
ReadGET /v2/wallets/{id} until the intended network’s address appears in depositAddresses. Already returned addresses remain usable while others are being prepared.
Show an address-setup indicator while provisioning continues. If the intended address is absent and setup returns failed, contact Ground. See Address readiness for funding steps and Supported Chains for network keys.