Monitor 10 Wallets
Canonical HTTP, SDK, and CLI starter for monitoring a fixed wallet set with recent activity, transactions, holdings, and token flows.
Monitor 10 wallets
Use this guide when your job is not “explore one address” but “keep a fixed set of wallets under watch.”
This is the canonical public starter for that workflow across:
- HTTP when you want zero-install integration
- the TypeScript SDK when you are wiring application code
- the CLI when you want reproducible shell commands and local files
What this starter covers
- optional bulk classification for the watched set
- recent activity per watched wallet
- recent transactions per watched wallet
- current token holdings per watched wallet
- token-specific inflows and outflows across the watched set
If you need one top-level enrichment pass before the per-wallet reads, use Classify addresses in bulk. Keep the activity, transactions, holdings, and transfer calls below for the full monitoring view.
Shared environment
export STARKSCAN_API_KEY="YOUR_STARKSCAN_API_KEY"
export STARKSCAN_CHAIN="SN_MAIN"
STARKSCAN_BASE_URL="${STARKSCAN_BASE_URL:-https://api.starkscan.co}"
export STARKSCAN_WATCHED_WALLETS="0xwalletA,0xwalletB,0xwalletC,0xwalletD,0xwalletE,0xwalletF,0xwalletG,0xwalletH,0xwalletI,0xwalletJ"
export STARKSCAN_WATCHED_TOKENS="0xstrkToken,0xethToken,0xusdcToken"
export STARKSCAN_ACTIVITY_LIMIT="50"
export STARKSCAN_TRANSACTION_LIMIT="50"
export STARKSCAN_TRANSFER_LIMIT="100"STARKSCAN_BASE_URL is a shell helper for these HTTP examples. Leave it unset
for production, or set it only for preview or self-hosted hosts. All examples
below call the normal /v1/* routes relative to that base.
HTTP file starter
Use this first when you are driving Starkscan from an editor with .http support and you want to see the exact request and response contract before you automate loops.
Save this as monitor-wallets.http:
@starkscan = https://api.starkscan.co
@chain = SN_MAIN
@apiKey = YOUR_STARKSCAN_API_KEY
@wallet = 0xwalletA
@token = 0xstrkToken
@activityLimit = 50
@transactionLimit = 50
@transferLimit = 100
GET {{starkscan}}/v1/{{chain}}/address/{{wallet}}/activity?limit={{activityLimit}}
X-Starkscan-Api-Key: {{apiKey}}
###
GET {{starkscan}}/v1/{{chain}}/address/{{wallet}}/transactions?limit={{transactionLimit}}
X-Starkscan-Api-Key: {{apiKey}}
###
GET {{starkscan}}/v1/{{chain}}/address/{{wallet}}/token-holdings
X-Starkscan-Api-Key: {{apiKey}}
###
GET {{starkscan}}/v1/{{chain}}/token/{{token}}/transfers?address={{wallet}}&limit={{transferLimit}}
X-Starkscan-Api-Key: {{apiKey}}Duplicate the request blocks per wallet or token when you need a small fixed watch set from the editor. If you need shell loops and JSON files on disk, use the shell starter below.
Shell HTTP starter
Use this when you want zero-install shell automation and local JSON artifacts.
set -euo pipefail
OUTPUT_DIR="${OUTPUT_DIR:-./starkscan-wallet-monitor-rest}"
mkdir -p "$OUTPUT_DIR"
# fetch <url> <dest>: write only on success so a failed request never leaves an
# empty/partial JSON artifact (shell > would truncate the file before curl runs).
fetch() {
local tmp
tmp="$(mktemp)"
if curl -fsS -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" "$1" -o "$tmp"; then
mv "$tmp" "$2"
else
rm -f "$tmp"
return 1
fi
}
IFS=',' read -r -a STARKSCAN_WALLETS <<< "$STARKSCAN_WATCHED_WALLETS"
IFS=',' read -r -a STARKSCAN_TOKENS <<< "$STARKSCAN_WATCHED_TOKENS"
for wallet in "${STARKSCAN_WALLETS[@]}"; do
wallet="$(printf '%s' "$wallet" | xargs)"
fetch "${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/address/$wallet/activity?limit=$STARKSCAN_ACTIVITY_LIMIT" \
"$OUTPUT_DIR/${wallet}.activity.json"
fetch "${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/address/$wallet/transactions?limit=$STARKSCAN_TRANSACTION_LIMIT" \
"$OUTPUT_DIR/${wallet}.transactions.json"
fetch "${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/address/$wallet/token-holdings" \
"$OUTPUT_DIR/${wallet}.holdings.json"
done
for token in "${STARKSCAN_TOKENS[@]}"; do
token="$(printf '%s' "$token" | xargs)"
url="${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/token/$token/transfers?limit=$STARKSCAN_TRANSFER_LIMIT"
for wallet in "${STARKSCAN_WALLETS[@]}"; do
wallet="$(printf '%s' "$wallet" | xargs)"
url="${url}&address=${wallet}"
done
fetch "$url" "$OUTPUT_DIR/${token}.transfers.json"
doneSDK starter
Only move to the SDK when this workflow belongs inside application code. If you are still validating routes, auth, or payloads, stay on one of the HTTP starters above.
Save this as monitor-wallets.ts:
import { mkdir, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { createStarkscanClient } from '@starkscan/sdk';
function requiredEnv(name: string): string {
const value = process.env[name]?.trim();
if (!value) throw new Error(`${name} is required`);
return value;
}
function csvEnv(name: string): string[] {
return requiredEnv(name)
.split(',')
.map((value) => value.trim())
.filter(Boolean);
}
const customBaseUrl = process.env.STARKSCAN_BASE_URL?.trim();
const apiKey = requiredEnv('STARKSCAN_API_KEY');
const chainId = process.env.STARKSCAN_CHAIN?.trim() || 'SN_MAIN';
const wallets = csvEnv('STARKSCAN_WATCHED_WALLETS');
const tokens = csvEnv('STARKSCAN_WATCHED_TOKENS');
const activityLimit = Number(process.env.STARKSCAN_ACTIVITY_LIMIT || '50');
const transactionLimit = Number(process.env.STARKSCAN_TRANSACTION_LIMIT || '50');
const transferLimit = Number(process.env.STARKSCAN_TRANSFER_LIMIT || '100');
const outputDir = process.env.STARKSCAN_OUTPUT_DIR?.trim() || './starkscan-wallet-monitor-sdk';
const starkscan = createStarkscanClient({
apiKey,
chainId,
...(customBaseUrl ? { baseUrl: customBaseUrl } : {}),
});
await mkdir(outputDir, { recursive: true });
for (const wallet of wallets) {
const [activity, transactions, holdings] = await Promise.all([
starkscan.addressActivity(wallet, undefined, activityLimit),
starkscan.addressTransactions(wallet, undefined, transactionLimit),
starkscan.addressTokenHoldings(wallet),
]);
await writeFile(join(outputDir, `${wallet}.activity.json`), JSON.stringify(activity, null, 2));
await writeFile(
join(outputDir, `${wallet}.transactions.json`),
JSON.stringify(transactions, null, 2),
);
await writeFile(join(outputDir, `${wallet}.holdings.json`), JSON.stringify(holdings, null, 2));
}
for (const token of tokens) {
const transfers = await starkscan.tokenTransfers(token, {
addresses: wallets,
limit: transferLimit,
});
await writeFile(
join(outputDir, `${token}.transfers.json`),
JSON.stringify(transfers, null, 2),
);
}Run it with:
npm install @starkscan/[email protected]
bun run ./monitor-wallets.tsIf you need a single typed summary layer, derive it from the activity, transactions, holdings, and filtered transfer reads above rather than depending on an unpublished batch helper.
Use that only as a top-level summary. Keep the activity, transactions, holdings, and transfer calls for the full monitoring view.
CLI starter
Use the CLI when you want repeatable shell commands, local JSON files, and no app code.
set -euo pipefail
OUTPUT_DIR="${OUTPUT_DIR:-./starkscan-wallet-monitor-cli}"
mkdir -p "$OUTPUT_DIR"
# save <dest> <cmd...>: write only on success so a failed command never leaves an empty file.
save() {
local dest="$1"; shift
local tmp
tmp="$(mktemp)"
if "$@" > "$tmp"; then
mv "$tmp" "$dest"
else
rm -f "$tmp"
return 1
fi
}
IFS=',' read -r -a STARKSCAN_WALLETS <<< "$STARKSCAN_WATCHED_WALLETS"
IFS=',' read -r -a STARKSCAN_TOKENS <<< "$STARKSCAN_WATCHED_TOKENS"
for wallet in "${STARKSCAN_WALLETS[@]}"; do
wallet="$(printf '%s' "$wallet" | xargs)"
save "$OUTPUT_DIR/${wallet}.activity.json" \
starkscan --output-format json address-activity "$wallet" --limit "$STARKSCAN_ACTIVITY_LIMIT"
save "$OUTPUT_DIR/${wallet}.transactions.json" \
starkscan --output-format json address-transactions "$wallet" --limit "$STARKSCAN_TRANSACTION_LIMIT"
save "$OUTPUT_DIR/${wallet}.holdings.json" \
starkscan --output-format json address-token-holdings "$wallet"
done
for token in "${STARKSCAN_TOKENS[@]}"; do
token="$(printf '%s' "$token" | xargs)"
transfer_args=()
for wallet in "${STARKSCAN_WALLETS[@]}"; do
wallet="$(printf '%s' "$wallet" | xargs)"
transfer_args+=(--address "$wallet")
done
save "$OUTPUT_DIR/${token}.transfers.json" \
starkscan --output-format json token-transfers "$token" "${transfer_args[@]}" --limit "$STARKSCAN_TRANSFER_LIMIT"
doneIf your workflow needs a single shell sanity check before the full loop:
starkscan status
starkscan address-activity "$(printf '%s' "$STARKSCAN_WATCHED_WALLETS" | cut -d',' -f1)" --limit 10Which surface to keep using
- Stay on the API guide when you need raw HTTP debugging, auth behavior, or retries.
- Stay on the SDK when the monitoring loop is part of application code.
- Stay on the CLI when you want shell automation and local files.
- Move to MCP only when the consumer is an MCP client rather than a direct integrator.
When any of these calls fail, see Your first error for 401 / 400 / 403 / 429 responses, the error envelope, and the exact fix for each.