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,
    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.
classHashIndexed 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.
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 indexed. null means Starkscan does not have that provenance in the serving table.
label / protocolNullable curated or indexed attribution hints for display and routing. Coverage is partial.
labelSourceProvenance for label, such as indexed_protocol_registry, indexed_token_metadata, or curated_known_token_metadata. null means no label was resolved.
typeLabelNullable account/contract type label such as Account contract or Contract, derived from indexed account-kind evidence. This is not a curated name tag.
typeLabelSourceProvenance for typeLabel, currently indexed_account_kind or null.
hasReceivedFundsThe address appears as a recipient in indexed token-transfer rows. It is not a balance check.
latestActivityBlockHighest proved indexed activity block. A non-null value always has a positive count and never exceeds activityCoverage.throughBlock.
totalActivityCountExhaustive count, a positive lower bound, or null. Numeric zero is valid only with exact exhaustive coverage.
activityCountExacttrue 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.
activityCoverageTyped status, reasonCode, evidence source, indexed range, and canonical source watermark.
sourceMachine-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 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 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 treat classHash as 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

  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