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,
currentClassHash: item.currentClassHash,
deploymentClassHash: item.deploymentClassHash,
classHashSource: item.classHashSource,
classHashAsOfBlock: item.classHashAsOfBlock,
classHashAsOfBlockHash: item.classHashAsOfBlockHash,
classHashFinality: item.classHashFinality,
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 | Compatibility value: currentClassHash when a trusted current-class observation exists, otherwise deploymentClassHash. |
currentClassHash | Newest trusted indexed runtime class observation. It is current at classHashAsOfBlock, not a claim about later blocks. |
deploymentClassHash | Original indexed deployment class only when a canonical deployment record supplies it. It is null when that canonical class evidence is unavailable and is never copied from current class or first activity; direct/factory caches are not canonical class evidence. |
classHashSource | Evidence source that supplied classHash, such as finalized state-diff evidence or an exact-block on-chain ABI observation. |
classHashAsOfBlock / classHashAsOfBlockHash | Exact canonical block identity for classHash. Read these together before treating the value as current enough for your use case. |
classHashFinality | finalized only when the source certifies finality; null for an exact-block observation that does not assert finalized status. |
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 canonical evidence is indexed. null means Starkscan does not have that fact; it is not an instruction to infer it. Coverage includes exact evidence already indexed plus a bounded usage-ranked contract cohort, and is not universal or zero-gap history. |
The contract page preserves the same distinction. It renders the exact creation
date, deployer, and transaction when those facts are known, and displays
Unavailable after a typed provenance response settles without a creation
timestamp. It does not relabel unavailable evidence as “not indexed” or infer a
date from first activity.
| 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. It may be non-null while the total remains unavailable, 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 preserves the proved latest block but returns a null total 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 compare
classHashblindly with RPC atlatest. Compare it withstarknet_getClassHashAtatclassHashAsOfBlock; then use the gap from your current head to decide whether the observation is fresh enough. - Do not substitute
deploymentClassHashforcurrentClassHashafter an upgrade. The compatibilityclassHashalready chooses the newest trusted observation by evidence block, with finalized evidence winning deterministic same-block ties. - Treat
deploymentClassHash: nullas “deployment class not authoritatively indexed,” not as proof that the address is undeployed. Equality withcurrentClassHashis meaningful only whendeploymentClassHashis non-null.
Deployment provenance coverage
deploymentProvenance.status is the authority for deployment attribution:
knownmeans a canonical creation state update and exact transaction/constructor trace agree.deployedAtTxHashis populated;deployedByAddresscan still be null when the deployment has no external deployer.not_applicablemeans canonical evidence proves a deployment form with no external deployer.unavailablemeans the creation boundary is known but transaction attribution is not certified. Attribution fields remain null.
Starkscan enriches a sealed, usage-ranked contract cohort off the request path. The cohort ranks unique successful transactions evidenced by either an indexed contract call or a finalized contract event with a successful receipt; duplicate events and call/event overlap count once. It improves common contract-page lookups but does not certify every historical deployment, and contracts without those indexed activity forms are outside the cohort rather than proved inactive. Clients must continue to handle nullable fields for any address and must not use labels, first activity, or nearby transactions as provenance.
- 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":null,"activityCountExact":false,"activityCoverage":{"status":"partial","reasonCode":"success_only_total_not_materialized"}}The example proves at least one successful activity fact, but does not invent a
numeric transaction count from that existence proof. Use latestActivityBlock
to render "activity observed" and keep the count hidden while
activityCountExact=false and 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.