Starkscan

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

RouteUse whenAdds
POST /v1/{chain}/address/summariesyou need ordered aggregate address facts for navigation, hydration, or preflight checksactivity count, latest activity, class hash, account hint, deployment tx/deployer when indexed
POST /v1/{chain}/address/intelligenceyou also need classification fields for wallet, paymaster, or migration backendslabel, 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 0x addresses and returns 400 for malformed input.
  • 429 means the route-class budget is exhausted; honor Retry-After.
  • 503 means a bounded serving query timed out; honor Retry-After when present. These batch timeout responses currently use Retry-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 \
  0x259fec57cd26d27385cd8948d3693bbf26bed68ad54d7bdd1fdb901774ff0e8

For 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.txt

Use address-summaries when you want the lighter aggregate view:

starkscan --output-format json address-summaries \
  0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a \
  0x259fec57cd26d27385cd8948d3693bbf26bed68ad54d7bdd1fdb901774ff0e8

Field semantics

FieldMeaning
contractVersionBatch-level activity truth and correlation contract, currently starkscan.address_activity_truth.v1.
sourceContractVersionBatch-level version of the bounded indexed evidence sources used by the response.
isDeployedStarkscan has indexed deployment or class evidence for the address.
classHashCompatibility value: currentClassHash when a trusted current-class observation exists, otherwise deploymentClassHash.
currentClassHashNewest trusted indexed runtime class observation. It is current at classHashAsOfBlock, not a claim about later blocks.
deploymentClassHashOriginal 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.
classHashSourceEvidence source that supplied classHash, such as finalized state-diff evidence or an exact-block on-chain ABI observation.
classHashAsOfBlock / classHashAsOfBlockHashExact canonical block identity for classHash. Read these together before treating the value as current enough for your use case.
classHashFinalityfinalized only when the source certifies finality; null for an exact-block observation that does not assert finalized status.
classLabelNullable 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.
classLabelSourceProvenance for classLabel, currently official_class_registry or null.
isAccountBest indexed account-contract hint. null means unknown, not false.
createdOnIsoCanonical indexed deployment time when available. It is null together with the other deployment fields when authoritative deployment evidence is unavailable.
deployedAtTxHash / deployedByAddressDeployment 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 null as unknown. Do not convert it to false.
  • Never coerce totalActivityCount=null to 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 label provenance.
  • Do not treat hasReceivedFunds=false as proof of zero current balance; use token holdings or exact token balance-of when balances matter.
  • Do not treat classLabel as a unique address name. It describes the reviewed class family behind the indexed classHash, while label remains the curated/token address label.
  • Do not compare classHash blindly with RPC at latest. Compare it with starknet_getClassHashAt at classHashAsOfBlock; then use the gap from your current head to decide whether the observation is fresh enough.
  • Do not substitute deploymentClassHash for currentClassHash after an upgrade. The compatibility classHash already chooses the newest trusted observation by evidence block, with finalized evidence winning deterministic same-block ties.
  • Treat deploymentClassHash: null as “deployment class not authoritatively indexed,” not as proof that the address is undeployed. Equality with currentClassHash is meaningful only when deploymentClassHash is non-null.

Deployment provenance coverage

deploymentProvenance.status is the authority for deployment attribution:

  • known means a canonical creation state update and exact transaction/constructor trace agree. deployedAtTxHash is populated; deployedByAddress can still be null when the deployment has no external deployer.
  • not_applicable means canonical evidence proves a deployment form with no external deployer.
  • unavailable means 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

  1. Validate and deduplicate the address list in your backend.
  2. Keep each batch at or below 128 addresses.
  3. Call address/intelligence for the rich first pass.
  4. Store source, activityCoverage, activityCountExact, and nullable fields so downstream jobs can distinguish unknown from false.
  5. 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.

On this page