Agent CLI
Use the Starkscan CLI for shell workflows, release validation, and local-first exports.
Agent CLI
Use the CLI when you need reproducible shell commands, local-first exports, or an operator-friendly surface that sits on top of the same Starkscan API contract.
Before using the CLI in unattended workflows, check the Launch matrix for the current release state and trust boundary. For npm package provenance, Socket links, and exact-version pinning rules, use Package trust.
Binary-backed contract
Run starkscan --help for the installed binary’s complete command and option
reference, starkscan <command> --help for command-local syntax, and
starkscan --version to record the installed release. The --help and
--version flags never make an API request. The public client surface matrix
records published CLI command stability and package state. CI derives the
visible command and flag set from the Clap definition, then checks this guide
and the docs-next mirror for drift. The guide is therefore a task-oriented
reference; the binary remains the authoritative source for argument syntax.
Use this surface for
- shell workflows with explicit commands and outputs
- local transfer exports and privacy-sensitive analysis
- release validation from a terminal
When not to start here
- Use the REST API first when you need zero-install integration.
- Use the SDK when you are writing app code.
Try in app before you script it
The explorer is still the fastest way to understand the data you are about to automate:
- Dashboard for top-level chain state
- Transactions for rows and detail pages
- Contracts for contract metadata and activity
- Watchlist for repeat address analysis
Install with npm or npx
Install the default npm CLI for normal use. For unattended use, resolve npm
latestand pin that exact version. The hosted MCP retirement requires CLI0.5.0or newer: earlier releases probe/mcpindoctor. Use0.5.7or newer for worker-parity manifest checks and exact locked Git dependencies whose workspaces contain package scripts, prebuilt-plugin permission, development-only dependencies, unrelated test members, or a custom TLS CA. Verify the0.5.7dist-tag and post-publish smoke first.
npm install -g @starkscan/cli
starkscan initFor a one-off agent run without a global install:
npx -y @starkscan/cli init --agent --output-format jsonThe npm launcher uses native CLI artifacts bundled in the published package when available, verifies archives against the bundled release manifest, caches the native Starkscan binary, and forwards all arguments to it. It does not require Rust or repository access.
Agents can inspect the launcher decision before running the native binary:
npx -y @starkscan/cli --launcher-jsonThe JSON includes the resolved binary path, package version, release tag,
source (bundled, download, or bin-path), cache-hit status, and
verification status. The launcher may resolve and verify the binary first, but
this command does not execute the native starkscan binary.
The public package and command are @starkscan/cli and starkscan.
First-run init
Run init before handing the CLI to an agent. It prints the active base URL, chain, auth placeholder, and validation commands without writing secrets to disk.
starkscan init
starkscan init --agent --output-format jsonPinned fallback
Public users should use npm or npx. Maintainer-only native artifact and source-install fallbacks are intentionally kept out of the public docs so external agents do not depend on repository internals.
Environment
export STARKSCAN_API_KEY="mzk_test_REPLACE_ME"
export STARKSCAN_CHAIN="SN_MAIN"
# Optional: only set this for preview or self-hosted hosts.
# export STARKSCAN_BASE_URL="https://preview.example.com/api"For hosted external access, the CLI defaults to https://api.starkscan.co.
Override STARKSCAN_BASE_URL only when targeting preview or a self-hosted host.
The CLI then calls the normal /v1/* routes underneath that base for you.
The CLI sends X-Starkscan-Api-Key for hosted API auth. Use STARKSCAN_*
env names for new beta clients.
Corporate and sandbox TLS proxies
The CLI keeps its bundled public roots and also loads the platform trust source.
For a corporate inspection proxy or sandbox gateway with an explicitly trusted
CA, point SSL_CERT_FILE at a PEM bundle or SSL_CERT_DIR at one or more
certificate directories before running starkscan. The variables use the
platform path-list delimiter. The CLI does not provide an insecure
skip-verification flag. If certificate verification fails, the error includes
the underlying TLS cause such as UnknownIssuer.
SSL_CERT_FILE=/run/secrets/sandbox-ca.pem starkscan statusThe CLI forwards STARKSCAN_API_KEY or --api-key only to Starkscan HTTPS
hosts or localhost/loopback fixtures. When intentionally testing a private API
host, pass --allow-untrusted-base-url explicitly so keys are not replayed to
an unexpected endpoint by default.
Supported STARKSCAN_CHAIN values are SN_MAIN and SN_SEPOLIA.
If you need a pinned native release instead of npm, use the maintainer release runbook for the matching Starkscan tag. External clients should not need repository access.
First successful commands
For any installed release, starkscan --help is authoritative.
starkscan status
starkscan address-activity 0xwallet --limit 50
starkscan address-summaries 0xwalletA 0xcontractB --output-format json
starkscan address-intelligence 0xwalletA 0xcontractB --output-format json
starkscan tx-details 0xtxA 0xtxB --log-limit-per-tx 32
starkscan contract-events 0xcontract --topic0 0x... --from-block 7800000 --limit 100
starkscan contract-entrypoints 0xtoken
starkscan contract-read 0xtoken --selector balanceOf --calldata 0xwallet
starkscan token-total-supply 0x0123...
starkscan token-balance-of <ownerAddress> <tokenAddress> --block-tag pendingstarkscan token-balance-of intentionally keeps the owner-first CLI order for shell readability.
The REST API and SDK remain token-first, so translate it as:
- CLI:
starkscan token-balance-of <ownerAddress> <tokenAddress> - REST:
GET ${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/token/<tokenAddress>/balance-of/<ownerAddress> - SDK:
starkscan.tokenBalanceOf(tokenAddress, ownerAddress)
Use that command only when you already know the exact token contract you want. If the workflow is "does this wallet already hold USDC?" or "paint the wallet home screen," separate candidate discovery from authoritative state:
- CLI discovery:
starkscan wallet-asset-discovery <ownerAddress> - CLI balances:
starkscan wallet-state <ownerAddress> - REST discovery:
GET ${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/address/<ownerAddress>/assets/discovery - REST balances:
POST ${STARKSCAN_BASE_URL:-https://api.starkscan.co}/v1/$STARKSCAN_CHAIN/query/wallet-state
That matters on Starknet because a symbol such as USDC can map to more than one live contract or alias. Discovery returns candidates and coverage, never a balance. Wallet state pins one block hash and calls each token contract; it never substitutes an indexed amount or treats an error as zero.
Add:
starkscan wallet-asset-discovery 0xwallet --limit 25
starkscan wallet-state 0xwallet --mode require_complete --limit 25
# When you already own the candidate list:
starkscan wallet-state 0xwallet --token 0xtokenA --token 0xtokenBFor wallet-safe decisions, use mode=require_complete and require walletSafe=true. A 503 means retry; it does not mean zero. Follow discovery nextCursor while hasMore=true, but remember that completeWithinScope=true is not global asset-universe completeness. The default scope also checks the curated registry, so use --scope discovered when a home screen intentionally needs only wallet-observed candidates and should avoid registry-only pagination. See Migrate to wallet state.
starkscan address-token-holdings <address> remains callable only to return
the typed retirement error. It never returns holdings; migrate to
wallet-asset-discovery followed by wallet-state.
General shell workflows
starkscan block 7800000
starkscan tx 0x1234abcd
starkscan tx-details 0x1234abcd 0x5678ef90 --log-limit-per-tx 32
starkscan search 0x1234abcd
starkscan search USDC --mode typed
starkscan address-activity 0xwallet --limit 50
starkscan address-transactions 0xwallet --limit 50
starkscan address-summaries 0xwalletA 0xcontractB --output-format json
starkscan address-intelligence 0xwalletA 0xcontractB --output-format json
starkscan contract-events 0xcontract --topic0 0x... --from-block 7800000 --limit 100
starkscan contract-entrypoints 0xtoken
starkscan contract-read 0xtoken --selector balanceOf --calldata 0xwallet
starkscan feed --max-events 10Any other read route
Routes without a dedicated command (staking, bridge and messages, classes, metrics, NFT and DeFi positions, global events and transfers) are one api call away. The route is relative to /v1/{chain}/; pass query parameters with --query KEY=VALUE, repeated as needed.
starkscan api staking/validators --query limit=10
starkscan api messages --query limit=5 --output-format json
starkscan api address/0xwallet/nft-positions --query limit=50
starkscan api metrics/networkapi only sends GET requests and refuses routes that leave /v1/{chain}/.
Summaries, attribution, and verification
starkscan address 0xwallet # address summary (activity counts, first/last seen)
starkscan address-attribution 0xwallet # best-known friendly label / attribution metadata
starkscan address-summaries 0xwalletA 0xcontractB
starkscan address-intelligence 0xwalletA 0xcontractB
starkscan token 0x0123... # token summary
starkscan contract-verification 0xcontract # verification status + source metadataaddress / token return the aggregate summary; use address-activity / token-transfers for the paged detail.
Live feed: snapshot or stream
starkscan feed # one snapshot
starkscan feed --stream --block-limit 5 --tx-limit 20 # follow /feed/stream
starkscan --output-format stream-json feed --stream --max-events 50The hosted live-feed stream is not yet open to API keys: feed --stream against api.starkscan.co exits with an auth error (HTTP 403), so poll the feed snapshot instead. Against a host that serves the stream, --stream follows the live feed; omit --max-events (or pass 0) to stream until interrupted. stream-json is accepted only by feed: feed --stream emits compact line-delimited events even when --pretty is also set, while feed without --stream emits a single {"type":"result",...} envelope. Any other command run with --output-format stream-json exits with a usage error.
Discover everything
starkscan examples # copy-pasteable API, CLI, and SDK snippets for your active host
starkscan doctor # check base URL, auth, and API reachabilityGlobal flags
These apply to every command and can be placed before or after the subcommand:
| Flag | Env | Default | Purpose |
|---|---|---|---|
--base-url | STARKSCAN_BASE_URL | https://api.starkscan.co | Optional Starkscan API base URL override; custom hosted values may be an API-host root or an app-host /api base |
--chain | STARKSCAN_CHAIN | SN_MAIN | chain id, currently SN_MAIN or SN_SEPOLIA |
--api-key | STARKSCAN_API_KEY | — | hosted API key (sent as X-Starkscan-Api-Key) |
--allow-untrusted-base-url | — | false | permit forwarding --api-key to a non-Starkscan, non-localhost base URL; use only for intentional private endpoints |
--output-format | — | text | text, json, or stream-json. text/json apply to every command; stream-json is accepted only by feed (line-delimited with --stream, one result envelope otherwise) and other commands reject it with a usage error |
--pretty | — | false | pretty-print JSON output |
--retries | — | 2 | retries for transient HTTP failures; values above 10 are clamped to 10 |
--timeout-ms | STARKSCAN_TIMEOUT_MS | 30000 | HTTP timeout in milliseconds |
Command-specific option reference
The binary defines these public command-local options. A dash means there is no
default: omit the flag to leave the corresponding API parameter unspecified.
Repeated options retain the order supplied on the command line. This table is
checked directly against the Clap command tree in CI; prefer the command’s
--help output if a future release adds an option before this guide is updated.
| Command(s) | Flag | Default | Contract |
|---|---|---|---|
init | --agent | false | Emit agent-oriented setup hints without writing credentials. |
block | --tx-limit | — | Bound transactions returned with the block. |
tx-details | --log-limit-per-tx | — | Bound logs per hydrated transaction. |
tx-details | --no-include-logs | false | Omit logs from the batch-hydration response. |
address-summaries, address-intelligence | --file | — | Add newline-delimited addresses; blank and comment lines are ignored. |
address-activity, address-transactions, address-token-holdings | --cursor | — | Pass the opaque cursor returned by the preceding page unchanged. |
address-activity, address-transactions, address-token-holdings | --limit | — | Request a bounded page; each route enforces its published server maximum. |
address-activity, address-transactions | --from-block, --to-block | — | Inclusive block bounds. --to-block starts the walk; pass --from-block again with every --cursor page. |
wallet-asset-discovery, wallet-state | --scope | discovered_plus_registry | Use discovered for wallet-observed candidates only; the default also evaluates the curated registry. |
wallet-asset-discovery, wallet-state | --cursor | — | Continue the current discovery/state page with its opaque cursor. |
wallet-asset-discovery, wallet-state | --limit | 25 | Request up to 25 candidates; server capacity can impose a lower published maximum. |
api | --query | — | Add one KEY=VALUE query parameter; repeat for more. The route itself must not contain ?. |
search | --mode | legacy | legacy matches exact hashes, addresses, and block numbers; typed also finds tokens by name or symbol. |
wallet-state | --token | — | Repeat an explicit candidate token address instead of relying only on discovery. |
wallet-state | --mode | require_complete | Require complete state or explicitly request verified_partial. |
wallet-state | --block-preference | latest_accepted_l2 | Select latest_accepted_l2, l1_accepted, or explicit. |
wallet-state | --block-hash | — | Required with --block-preference explicit unless --block-number is supplied. |
wallet-state | --block-number | — | Required with --block-preference explicit unless --block-hash is supplied. |
wallet-state | --include-nonce | false | Include the account nonce at the pinned state block. |
wallet-state | --include-class-hash | false | Include the account class hash at the pinned state block. |
contract-events | --topic0 | — | Compatibility shorthand for the first event key. |
contract-events | --topic1 | — | Compatibility shorthand for the second event key; requires topic 0 and explicit bounds. |
contract-events | --topic2 | — | Compatibility shorthand for the third event key; requires topic 0 and explicit bounds. |
contract-events | --topic3 | — | Compatibility shorthand for the fourth event key; requires topic 0 and explicit bounds. |
contract-events | --topic | — | Repeat POSITION=FELT for keys 0 through 15, positional ORs, and wildcard gaps. |
contract-events, token-transfers | --from-block | — | Inclusive lower block bound. |
contract-events, token-transfers | --to-block | — | Inclusive upper block bound. |
contract-events, token-transfers | --cursor | — | Continue an opaque page cursor unchanged. |
contract-events, token-transfers | --limit | — | Request a bounded page subject to the route maximum. |
contract-read | --selector | — | Required entrypoint name or selector felt. |
contract-read | --calldata | — | Repeat bounded calldata felts in call order. |
contract-read, token-total-supply, token-balance-of | --block-tag | latest | Use latest, pending, a block hash, or a non-negative block number. |
token-transfers | --address | — | Repeat address filters; the endpoint applies its documented filter semantics. |
feed | --stream | false | Follow the live stream instead of returning one snapshot. |
feed | --block-limit | 10 | Cap blocks in a feed snapshot or stream event. |
feed | --tx-limit | 10 | Cap transactions in a feed snapshot or stream event. |
feed | --max-events | 0 | Stop after this many stream events; 0 streams until interrupted. |
The retry budget is additional attempts: the default makes at most three total
requests. For 429 and 5xx responses, the CLI honors a numeric
Retry-After delay when the server provides one, capped at 30 seconds. Without
one it waits 250 ms after a rate limit or uses bounded exponential backoff
for other transient failures. Connect and timeout failures use the same retry
budget. After the budget is exhausted, inspect the JSON error envelope and
retry only when its exitClass is retryable for your workflow.
For agent callers, --output-format json keeps stdout parseable on failure:
successful commands return { "ok": true, "data": ... }; failures before a
result payload is emitted return
{ "ok": false, "error": { "code": "auth_error", "message": "HTTP 401: unauthorized", "exitCode": 3, "exitClass": "auth", "httpStatus": 401, "requestId": "starkscan-cli-..." } }
and still exit non-zero. Diagnostic commands such as doctor can emit
{ "ok": false, "data": ... } with a non-zero exit. stream-json failures emit
one compact type: "error" line, while text mode keeps human-readable errors on
stderr.
Transaction hashes, addresses, token addresses, and calldata values are
validated locally as 0x-prefixed Starknet field elements. Contract-read
selectors can be function names such as balanceOf or selector felts. Malformed
inputs exit 2 before any network request; JSON mode emits
code: "usage_error".
JSON output canonicalizes address-shaped fields such as address,
fromAddress, toAddress, contractAddress, and tokenAddress to lowercase
0x plus 64 hex characters. Hashes, calldata, selectors, and other felt values
are not rewritten.
CLI exit codes and the JSON exitClass are stable for agents:
| Exit code | exitClass | Meaning |
|---|---|---|
0 | — | successful command |
1 | runtime | unexpected runtime or upstream failure |
2 | usage | malformed input or unsupported command/flag |
3 | auth | missing, invalid, or unauthorized credentials |
4 | rate_limited | server rate limit exhausted |
5 | timeout | request or upstream timeout |
6 | not_found | requested resource is absent |
Local-first transfer exports
starkscan --output-format json token-transfers 0x0123... \
--address 0x0456... \
--address 0x0789... \
--from-block 7800000 \
--to-block 7802500 > transfers.jsonThat gives you a narrow token + address(es) + block range export directly on your machine instead of in a shared dump.
For multi-wallet monitoring without a block range, repeat --address the same way:
starkscan token-transfers 0x0123... \
--address 0xwalletA \
--address 0xwalletB \
--limit 100For the full external starter, including the matching REST and SDK flows plus the shared env contract, use Monitor 10 wallets.
Batch address classification
starkscan --output-format json address-summaries \
0xwalletA \
0xcontractB
starkscan --output-format json address-intelligence \
0xwalletA \
0xcontractBFor file-based batches, put one address per line and use the same command with --file:
starkscan --output-format json address-intelligence --file wallets.txtUse address-summaries when you already have a backend list of addresses and need ordered aggregate facts such as class hash, account hint, deployment metadata, latest activity, and activity count. Use address-intelligence when you also need utility classification fields such as label/protocol, generic account/contract typeLabel, deployed flag, and inbound-funds flag. Both commands preserve request order, reject duplicate or malformed addresses before making a request, ignore blank/comment lines in files, and follow the API batch cap of 128 addresses.
Contract event indexers
starkscan --output-format json contract-events 0xcontract \
--topic0 0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9 \
--from-block 7800000 \
--to-block 7800500 \
--limit 100Use contract-events when you need the canonical paginated log stream for one contract before applying protocol-specific decoding. Keep filters server-side first: contract address, exact positional topics, block range, then continue with --cursor. The named --topic0 through --topic3 flags remain compatible; repeat --topic POSITION=FELT for positions zero through fifteen and OR alternatives at one position. Omitted positions are wildcards. Any position after zero requires a topic0 plus explicit numeric --from-block and --to-block bounds. Ordinary keys are limited to 10,000 inclusive blocks; the CLI sends wider ranges so the server can apply Wallet-plan entitlement and the dynamic eventSearch.fullRange.selectorCoverage contract. For wide requests, use the exact selector-position scope's servableFromBlock and maxServableToBlock. throughBlock is a legacy safe compatibility bound; use tierCertifiedThroughBlock only when inspecting the actual tier certificate. A Wallet caller may also send the live head as to_block; when it is above the current serving ceiling, compare rangeCoverage.requestedToBlock with the clamped rangeCoverage.completeThroughBlock. Expect 422 full_range_selector_not_supported for an uncertified selector-position pair and 503 event_key_index_coverage_unavailable only when no complete prefix covers the requested lower bound or coverage is unavailable.
Use freshnessStatus, sourceHighWaterBlock, sourceContiguousLowWaterBlock, sourceContiguousHighWaterBlock, lagBlocks, openEnded, and liveMaintenance to explain the tier state, not to widen the composite serving interval. A contiguous low-water above the physical low-water means the bounded raw prefix contains a gap; a contiguous high-water below the physical high-water means an earlier tail block is still in flight.
starkscan --output-format json contract-events "$MARKET_ADDRESS" \
--topic 0="$EVENT_SELECTOR" \
--topic 4="$POOL_A" \
--topic 4="$POOL_B" \
--from-block 1000000 \
--to-block 1000150 \
--limit 100For Voyager /events migrations, replace page/lastPage loops with cursor pagination. keys maps to topic0..topic3, name maps to eventName when attributed, and transactionHash maps to txHash:
starkscan --output-format json contract-events "$MARKET_ADDRESS" \
--from-block "$FROM_BLOCK" \
--to-block "$TO_BLOCK" \
--limit 100 \
| jq '.data as $page | {
items: [$page.items[] | {
name: .eventName,
keys,
data,
blockNumber,
transactionHash: .txHash,
transactionNumber: .txIndex,
number: .logIndex,
timestamp: (.timestampIso | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601),
timestampIso
}],
nextCursor: $page.nextCursor
}'Treat eventName as display/routing attribution. Keep protocol-critical decoding on raw topic* and data[].
Batch transaction hydration
starkscan --output-format json tx-details \
0xabc... \
0xdef... \
--log-limit-per-tx 32Use tx-details when you already have an ordered tx hash list and want bounded Starkscan transaction previews in one batch. Check logsTruncated and tokenTransfersTruncated before treating child arrays as exhaustive.
Logs are included by default for this convenience command; pass --no-include-logs when you only need compact preview rows.
Smoke-test the CLI path
Run the core read commands against your host before handing the CLI to an agent — a clean status plus a known block, tx, and search confirms the binary, host, and key are wired:
starkscan status
starkscan block <head>
starkscan tx <sample>
starkscan search <sample>When to choose another surface
- Use the SDK for app code.
- Use the REST API for raw HTTP contract debugging.
- Stay in the explorer app when the job is visual investigation instead of automation.
API key usage
Run starkscan api-key-usage --output-format json with your configured workspace API key
to read its last 24 hours of recorded HTTP usage. Requires read or prove scope and does
not depend on --chain. Configured server keys and OAuth tokens cannot read this
account snapshot.
The same response includes proofUsage for this key's mainnet proofs today
(UTC). Use proofUsage.succeededToday for successful completions, including
jobs submitted before midnight. failedToday, unavailableToday, and
unknownDeliveryToday are separate terminal outcomes; queued and running
show current unfinished work. These counters come from the durable job ledger.
admittedToday is the daily quota usage: every admitted job consumes one unit,
including failed jobs. Polling and idempotent replays do not consume another
unit. dailyLimit reflects the per-key override or relay default, and
remainingToday is the nonnegative difference. Both are null when relay
configuration is unavailable on the API instance. Remaining budget does not
guarantee admission: proving scope, relay availability, and concurrency limits
still apply. windowEnd is the next UTC midnight; observedAt is the snapshot
time. This daily window is separate from the HTTP telemetry's rolling 24 hours.