Starkscan

Privacy Pool data API

Read finalized public-flow amounts without inferring private ownership.

Privacy Pool data API

Starkscan exposes beta Privacy Pool routes for public activity, note evidence, prepared metrics, and finalized public-flow amounts. They do not expose note ownership, link a deposit to a withdrawal, calculate an anonymity set, claim a user's balance, or report a pool custody balance.

Use the external API host and a Starkscan read key. Do not use the explorer's same-origin /v1/* lane from an external integration.

export STARKSCAN_BASE_URL=https://api.starkscan.co
export STARKSCAN_API_KEY=<your-read-key>
export STARKSCAN_CHAIN=SN_MAIN

The supported external contract

NeedCallUse it for
Readiness and freshnessGET /v1/{chain}/privacy-pool/statusDecide whether indexed and decoded public facts are ready before publishing metrics.
Daily activity bucketsGET /v1/{chain}/privacy-pool/metric-bucketsBounded daily deposits, withdrawals, and note activity for 1–90 days.
Prepared chart seriesGET /v1/{chain}/privacy-pool/metrics/seriesViewing-key, tracked-supply, and fee series with explicit range and granularity.
Aggregate activityGET /v1/{chain}/privacy-pool/analyticsPrepared public activity and observable-flow summaries, including explicit unavailable states.
Public event evidenceGET /v1/{chain}/privacy-pool/eventsCursor-paginated decoded events plus raw keys and data.
Note-state evidenceGET /v1/{chain}/privacy-pool/commitments, GET /v1/{chain}/privacy-pool/nullifiersPublic commitment and nullifier facts without inferring ownership or spend links.
Current public-flow snapshotGET /v1/{chain}/privacy-pool/tvlExact per-token finalized public-flow amounts at one Starkscan indexed-finality snapshot.
Hourly prepared pointsGET /v1/{chain}/privacy-pool/tvl/seriesExisting prepared UTC-hour public-flow points; not a certified continuous history.

These routes are bounded indexed or materialized reads: they do not scan full event history, call Starknet RPC, call another explorer, or fetch a price on the request path. For activity and evidence recipes, response gating, and cursor handling, see Privacy Pool metrics and note evidence.

Current public-flow snapshot

curl --fail-with-body \
  -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
  "$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/privacy-pool/tvl"

This is an illustrative response with one asset shown. The live schema is in the public OpenAPI contract.

{
  "schemaVersion": "1",
  "chainId": "SN_MAIN",
  "scope": "strk20_privacy_pool",
  "status": "complete",
  "accountingMethod": "finalized_public_flow_ledger_v1",
  "asOf": {
    "blockNumber": 12345678,
    "blockHash": "0x...",
    "blockTimestamp": "2026-07-27T00:00:00Z",
    "materializedAt": "2026-07-27T00:01:00Z"
  },
  "coverage": {
    "status": "complete",
    "finalizedOnly": true,
    "finalityBasis": "starkscan_indexed_finalized_tier",
    "asOfL1Accepted": false,
    "missingAmountEventCount": 0,
    "decodedMaterializationFresh": true
  },
  "assets": [{
    "status": "complete",
    "reasonCode": "finalized_public_flow_ledger",
    "token": { "address": "0x...", "symbol": "USDC", "decimals": 6 },
    "protectedAmountRaw": "175093155774",
    "protectedAmount": "175093.155774",
    "missingAmountEventCount": 0
  }]
}

The accounting rule per token is:

protectedAmountRaw = depositAmountRaw - withdrawalAmountRaw

protectedAmountRaw is the schema-v1 field name for the authoritative base-10 finalized public-flow amount. Keep it as an arbitrary-precision integer end to end; never parse it as a JavaScript number. protectedAmount is only a convenience decimal rendering. Neither field is a wallet balance, pool custody balance, or claim of TVL.

Schema v1 may include legacy valuation, price, valueUsd, and totalUsd compatibility fields. They are not a supported pricing service or accounting input for a new integration. Use token address, decimals, and raw public-flow amounts as the integration inputs.

Publish an automated snapshot only when top-level status and coverage.status are complete, coverage.missingAmountEventCount is 0, coverage.decodedMaterializationFresh is true, and every consumed asset is complete with no missing amount events.

finalizedOnly: true means Starkscan's depth-confirmed indexed-finalized tier. It is not by itself L1 settlement. Require coverage.asOfL1Accepted === true when an L1-accepted condition is necessary.

Hourly prepared points

FROM='<RFC3339 UTC-hour timestamp>'
TO='<RFC3339 UTC-hour timestamp>'

curl --fail-with-body --get \
  -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
  --data-urlencode "from=$FROM" \
  --data-urlencode "to=$TO" \
  --data-urlencode 'granularity=hour' \
  --data-urlencode 'limit=24' \
  "$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/privacy-pool/tvl/series"

from and to are required RFC3339 UTC-hour timestamps. The range is inclusive, points are oldest first, and a response is capped at 24 hours. Pass nextCursor unchanged with the same range for the next page.

Each items[] entry has a timestamp, an asOf final block identity, a per-token assets[] array, and its own status and missingAmountEventCount. Consume a point only when its status is complete and its missing amount count is 0.

The hourly route is a prepared-point read, not a continuity certificate. It currently has no page-level coverage or freshness watermark; current-snapshot coverage does not certify an hourly page. Availability rule: an empty items[] page or sparse UTC-hour sequence is unavailable history. It is not a zero-value point or complete-range assertion; fail closed. Do not synthesize missing hours from RPC, another explorer, or request-time pricing.

{
  "items": [{
    "timestamp": "2026-07-26T00:00:00.000Z",
    "asOf": { "blockNumber": 12345678, "blockHash": "0x..." },
    "status": "complete",
    "missingAmountEventCount": 0,
    "assets": [{ "token": { "address": "0x..." }, "protectedAmountRaw": "175093155774" }]
  }],
  "nextCursor": "opaque-next-page-token-or-null"
}

Pricing is outside this contract

Pricing and valuation are outside the Privacy Pool API contract. Do not use schema-v1 compatibility fields to make a USD, wallet-balance, custody, or total-value claim. A consumer that needs a valuation must apply its own address-keyed price source to raw public-flow amounts at the relevant snapshot or point timestamp.

Efficient polling

Both routes return ETag and Last-Modified. Save the ETag and send it as If-None-Match; a 304 Not Modified has no body. An ETag only validates a representation; it is not proof that an hourly range is complete or fresh. Respect Cache-Control, rate-limit headers, and Retry-After.

curl --fail-with-body --silent --show-error \
  -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
  -D /tmp/starkscan-privacy-pool-tvl.headers \
  -o /dev/null \
  "$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/privacy-pool/tvl"

etag="$(awk 'BEGIN{IGNORECASE=1} /^etag:/ {sub(/^[^:]+:[[:space:]]*/, ""); sub(/\r$/, ""); print; exit}' /tmp/starkscan-privacy-pool-tvl.headers)"

curl --fail-with-body --output /dev/null --write-out '%{http_code}\n' \
  -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
  -H "If-None-Match: $etag" \
  "$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/privacy-pool/tvl"

Public activity routes and intentional exclusions

The public OpenAPI now includes the dedicated status, analytics, metric-bucket, metric-series, event, commitment, and nullifier routes below. They remain beta: consume their declared status, coverage, visibility, and cursor fields rather than copying assumptions from the website.

CallAppropriate useBoundary
GET /v1/{chain}/privacy-pool/statusHealth and decoded-event freshness.Counters are not ownership, balances, or anonymity k.
GET /v1/{chain}/privacy-pool/eventsCursor-paginated public event feed. Optional query: event, cursor, limit (1–100).Fields can be partial or hidden_by_design; raw keys and data remain audit evidence.
GET /v1/{chain}/privacy-pool/commitmentsPublic commitment facts. Optional query: pool, cursor, limit (1–100).Never infer note ownership or a spend link.
GET /v1/{chain}/privacy-pool/nullifiersPublic nullifier facts. Optional query: pool, cursor, limit (1–100).Never infer which commitment was spent.
GET /v1/{chain}/privacy-pool/analyticsPrepared aggregate counts and observable flows.Analytics is not the canonical public-flow ledger.
GET /v1/{chain}/privacy-pool/metric-bucketsPrepared daily chart buckets. Optional query: limit (1–90).Product metrics, not accounting history.
GET /v1/{chain}/privacy-pool/metrics/seriesPrepared viewing-key, tracked supply, and fee series. Optional query: range, granularity, token.Defaults are product-oriented; specify a token when needed.

GET /v1/{chain}/privacy-pool/dashboard remains an explorer composition route; use the dedicated public routes for durable integrations. Merkle-root facts are not published as an external route while the materialized dataset has no facts.

For events, commitments, nullifiers, and roots, preserve nextCursor exactly; do not construct a cursor from a block number. The events API supports only the server-side event filter. Explorer UI filters for contract, transaction, and block are not server-side API filters.

Integration rules

  • Treat token contract address as identity; a symbol is display metadata.
  • Keep raw amounts as strings and apply token decimals using arbitrary-precision arithmetic.
  • Store response block/hash/timestamp, schema version, and accounting method with each consumed point.
  • Fail closed on degraded, unavailable, empty, or sparse history; do not fill a gap from request-time RPC, another explorer, or a request-time price lookup.
  • Do not label a finalized public-flow amount as a wallet balance, pool custody balance, or TVL.
  • Use the API reference and starkscan-openapi.yaml as the authoritative schema, stability, and error contract for every external endpoint.

On this page