Classify Addresses In Bulk
Use address summaries and address intelligence for ordered, indexed wallet and contract classification.
Classify addresses in bulk
Use this guide when you already have a bounded list of wallets or contracts and need one request to answer:
- is this address deployed?
- is it likely an account or contract?
- what class hash or deployment evidence is indexed?
- does Starkscan have a readable label or protocol attribution?
- has the address ever received indexed token transfers?
- when was the latest indexed activity?
These routes are designed for wallet, paymaster, migration, and account-intelligence backends. They use indexed read models only. They do not call Starknet RPC, run deployment repair, scan raw activity, run sanctions/risk screening, or perform heuristic mixer-proximity analysis on the request path.
Pick the light or rich route
| Route | Use when | Adds |
|---|---|---|
POST /v1/{chain}/address/summaries | you need ordered aggregate address facts for navigation, hydration, or preflight checks | activity count, latest activity, class hash, account hint, deployment tx/deployer when indexed |
POST /v1/{chain}/address/intelligence | you also need classification fields for wallet, paymaster, or migration backends | label, protocol, deployed flag, inbound-funds flag, provenance source |
Both routes are advanced-utility routes and require a utility or batch-scope API key. Standard read keys can return 403 on these batch helpers.
Contract
- Body key is
addresses. - Maximum batch size is 128 addresses.
- Results preserve the request order after validation.
- The HTTP API preserves duplicate inputs and cardinality. SDK helpers reject canonical duplicate addresses before a request is sent.
- The API validates Starknet felt-style
0xaddresses and returns400for malformed input. 429means the route-class budget is exhausted; honorRetry-After.503means a bounded serving query timed out; honorRetry-Afterwhen present. These batch timeout responses currently useRetry-After: 2.
HTTP
export STARKSCAN_API_KEY="YOUR_STARKSCAN_API_KEY"
export STARKSCAN_CHAIN="${STARKSCAN_CHAIN:-SN_MAIN}"
STARKSCAN_BASE_URL="${STARKSCAN_BASE_URL:-https://api.starkscan.co}"
curl -X POST \
-H "Content-Type: application/json" \
-H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
-d '{"addresses":["0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a","0x259fec57cd26d27385cd8948d3693bbf26bed68ad54d7bdd1fdb901774ff0e8"]}' \
"$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/address/intelligence"TypeScript SDK
import { createStarkscanClient } from '@starkscan/sdk';
const starkscan = createStarkscanClient({
apiKey: process.env.STARKSCAN_API_KEY,
chainId: process.env.STARKSCAN_CHAIN || 'SN_MAIN',
});
const addresses = [
'0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a',
'0x259fec57cd26d27385cd8948d3693bbf26bed68ad54d7bdd1fdb901774ff0e8',
];
const intelligence = await starkscan.addressIntelligence(addresses);
console.log(intelligence.contractVersion);
console.log(intelligence.sourceContractVersion);
for (const item of intelligence.items) {
console.log({
address: item.address,
label: item.label,
labelSource: item.labelSource,
typeLabel: item.typeLabel,
typeLabelSource: item.typeLabelSource,
protocol: item.protocol?.name ?? null,
isDeployed: item.isDeployed,
classHash: item.classHash,
classLabel: item.classLabel,
classLabelSource: item.classLabelSource,
createdOnIso: item.createdOnIso,
deployedAtTxHash: item.deployedAtTxHash,
deployedByAddress: item.deployedByAddress,
hasReceivedFunds: item.hasReceivedFunds,
latestActivityBlock: item.latestActivityBlock,
totalActivityCount: item.totalActivityCount,
activityCountExact: item.activityCountExact,
activityCoverage: item.activityCoverage,
source: item.source,
});
}CLI
starkscan --output-format json address-intelligence \
0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a \
0x259fec57cd26d27385cd8948d3693bbf26bed68ad54d7bdd1fdb901774ff0e8For larger local lists, put one address per line. Blank lines and lines starting with # are ignored before validation:
starkscan --output-format json address-intelligence --file addresses.txtUse address-summaries when you want the lighter aggregate view:
starkscan --output-format json address-summaries \
0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a \
0x259fec57cd26d27385cd8948d3693bbf26bed68ad54d7bdd1fdb901774ff0e8Field semantics
| Field | Meaning |
|---|---|
contractVersion | Batch-level activity truth and correlation contract, currently starkscan.address_activity_truth.v1. |
sourceContractVersion | Batch-level version of the bounded indexed evidence sources used by the response. |
isDeployed | Starkscan has indexed deployment or class evidence for the address. |
classHash | Indexed deployment/read-model class hash when deployment/class metadata is available. It may not be the current runtime class after account or contract upgrades; use RPC starknet_getClassHashAt when current class state matters. |
classLabel | Nullable class-family label when classHash matches a reviewed official class registry, such as an account or standard-contract family. This is separate from label and is not a curated address name tag. |
classLabelSource | Provenance for classLabel, currently official_class_registry or null. |
isAccount | Best indexed account-contract hint. null means unknown, not false. |
createdOnIso | Canonical indexed deployment time when available. It is null together with the other deployment fields when authoritative deployment evidence is unavailable. |
deployedAtTxHash / deployedByAddress | Deployment provenance when indexed. null means Starkscan does not have that provenance in the serving table. |
label / protocol | Nullable curated or indexed attribution hints for display and routing. Coverage is partial. |
labelSource | Provenance for label, such as indexed_protocol_registry, indexed_token_metadata, or curated_known_token_metadata. null means no label was resolved. |
typeLabel | Nullable account/contract type label such as Account contract or Contract, derived from indexed account-kind evidence. This is not a curated name tag. |
typeLabelSource | Provenance for typeLabel, currently indexed_account_kind or null. |
hasReceivedFunds | The address appears as a recipient in indexed token-transfer rows. It is not a balance check. |
latestActivityBlock | Highest proved indexed activity block. A non-null value always has a positive count and never exceeds activityCoverage.throughBlock. |
totalActivityCount | Exhaustive count, a positive lower bound, or null. Numeric zero is valid only with exact exhaustive coverage. |
activityCountExact | true only for an exhaustive certified source range. false or null means the count is non-exact: it may be a positive lower bound or null. Only true makes zero trustworthy. |
activityCoverage | Typed status, reasonCode, evidence source, indexed range, and canonical source watermark. |
source | Machine-readable provenance for the classification item, separate from labelSource. |
Data honesty rules
- Use
nullas unknown. Do not convert it to false. - Never coerce
totalActivityCount=nullto zero. The current success-only sender, trace-backed contract-call, and canonical finalized contract-event evidence reports a conservative lower bound while the exhaustive aggregate is not materialized. - Accounts include successful finalized account-originating transactions. Contracts, including token contracts, use the newest successful trace-backed finalized call or canonical finalized emitter event. Both are bounded indexed reads. Reorgable head rows are not promoted, and the route never calls RPC to fill a response.
- Do not treat missing labels as proof that an address is not a protocol or contract.
- Do not treat account type/template labels as equivalent to curated entity names; class-hash labels, when present, must be stored separately from counterparty
labelprovenance. - Do not treat
hasReceivedFunds=falseas proof of zero current balance; use token holdings or exact tokenbalance-ofwhen balances matter. - Do not treat
classLabelas a unique address name. It describes the reviewed class family behind the indexedclassHash, whilelabelremains the curated/token address label. - Do not treat
classHashas a current-state proof after upgrades. It is indexed read-model metadata, not a request-path RPC lookup. - Do not treat this route as compliance screening. It returns factual indexed classification and attribution only, not risk scores, sanctions screening, or mixer-proximity heuristics.
- Response addresses are compact lowercase felts. Canonicalize inputs by lowercasing the hex body and removing redundant leading zeroes, then correlate by position. Equivalent padded inputs preserve response order and cardinality.
Activity examples
{"latestActivityBlock":123,"totalActivityCount":1,"activityCountExact":false,"activityCoverage":{"status":"lower_bound","reasonCode":"success_only_total_not_materialized"}}The example proves at least one successful activity fact; 1 is not an
exhaustive total. When activityCountExact=false, present a positive number as
an explicit lower bound (for example, 1+ or "activity observed"), not as a
complete account or contract count. Unknown, stale, or unavailable activity uses
totalActivityCount:null. The current projection does not claim exhaustive
zero. A future certified genuine zero may be emitted only as
totalActivityCount:0, activityCountExact:true, and
activityCoverage.status:"exhaustive". A funded counterfactual address may
therefore have hasReceivedFunds:true, isDeployed:false, and a null activity
count without contradiction.
Unavailable reasons distinguish source failures: watermark_unavailable means
the canonical finalized watermark could not be established, while
activity_evidence_unavailable means the bounded evidence query failed, timed
out, or returned an invalid backing block hash, and
projection_watermark_unavailable means the relevant account-sender or
contract-call materialization has no usable through-block watermark. These are
retryable data-availability states; none proves zero activity.
Migrate numeric-count consumers
Older consumers may have treated totalActivityCount as an always-present
number. SDK 0.3.0 is the first package target for number | null and contract
version starkscan.address_activity_truth.v1. Branch on activityCoverage.status and
activityCountExact; do not use totalActivityCount ?? 0. If you need a
boolean activity hint, use latestActivityBlock !== null or a positive count,
and preserve null as unknown. Pin and validate both batch-level version fields
so an unsupported future contract fails visibly.
Production pattern
- Validate and deduplicate the address list in your backend.
- Keep each batch at or below 128 addresses.
- Call
address/intelligencefor the rich first pass. - Store
source,activityCoverage,activityCountExact, and nullable fields so downstream jobs can distinguish unknown from false. - For detailed wallet views, follow up with
address/{address}/activity,address/{address}/transactions, or token holdings on only the addresses a user opens.
For a complete multi-wallet starter across REST, SDK, and CLI, use Monitor 10 wallets.