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.
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.
New wallets prepare Stellar automatically. Poll until depositAddresses.stellar_testnet appears in sandbox or depositAddresses.stellar appears in production. Other returned addresses are usable while Stellar setup continues.
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.