Wallet Graph Response Contract v1
GET /api/wallet?address=<0x-or-ens> returns a WalletGraph document for the read-only Ethereum wallet explorer. The contract is normalized by api/wallet-contract.js before the route sends JSON.
Top-level fields
Required stable metadata:
| Field | Type | Notes |
|---|
contractVersion | "walletGraph.v1" | Stable version tag — never remove or rename |
address | string | Resolved Ethereum address. ENS input resolves to 0x when a provider is configured. |
chain | "ethereum" | Currently Ethereum only |
provider | string | Primary wallet activity provider, e.g. etherscan, alchemy_only, or demo. Falls back to "unknown" when not derivable. |
source | string | Normalized source class: live, real, partial, or mock |
sources | object | Provider map for backwards compatibility. Current fields: walletActivity, prices |
dataQuality | object | Normalized quality object |
isFallback | boolean | Top-level alias for dataQuality.isFallback |
transactionSample | object | Sample metadata for loaded normal transactions |
apiErrors | array | User-safe provider/config warnings. No provider keys, URLs, or secrets. |
nodes | array | Graph nodes |
edges | array | Graph edges |
Existing wallet metrics remain available for compatibility: ens, ownedENSNames, totalValueUSD, totalValueEstimated, ethBalance, firstSeen, lastActive, txCount, overallRiskScore, dataConfidence, dataSource, transactions, and fingerprintScore.
Data quality
dataQuality preserves legacy booleans and adds explicit flags:
{
"isFallback": false,
"isDemo": false,
"isPartial": true,
"warnings": [],
"flags": {
"partial": true,
"sampled": false,
"fallback": false,
"demo": false,
"providerErrors": true
},
"providerErrors": [],
"updatedAt": "2026-05-01T00:00:00.000Z"
}
| Flag | Meaning |
|---|
partial | Route sampled data or a provider/config warning means the graph may be incomplete |
sampled | transactionSample.isSampled is true |
fallback | Fallback pricing or demo/fallback data is being served |
demo | Explicit mock/demo wallet data |
providerErrors | apiErrors contains partial or error severities |
updatedAt | Included only when derivable from loaded transaction sample freshness |
Transaction sample
transactionSample describes loaded normal transactions, not global wallet totals:
| Field | Description |
|---|
loadedCount | Number of normal transactions loaded into this response |
sampleLimit | Configured sample limit, or null when no sampling limit applies |
isSampled | true when the response hit the configured sample limit |
firstLoadedTxAt | ISO timestamp of earliest loaded transaction, or null |
lastLoadedTxAt | ISO timestamp of latest loaded transaction, or null |
totalKnown | Currently null — the route does not claim a provider total it does not have |
Nodes
Each node is normalized to include:
| Field | Type | Notes |
|---|
id | string | Stable graph-local identifier, normalized to string |
label | string | Sanitized display label via sanitizeLabel |
type | string | One of: wallet, token, defi, nft, counterparty, anomaly |
volumeUSD | number | Uses 0 when unavailable |
interactions | number | Uses 0 when unavailable |
Optional fields that may be present: fullAddress, color, volumeEstimated, riskScore, balanceUSD, priceUSD, firstSeen, lastActive, protocolAttributionConfidence, timeline, topCounterparties, delta7d, anomalies, opportunities.
Node type values are constrained to the six values listed above. Do not add new node types without updating this contract.
Edges
Each edge is normalized to include:
| Field | Type | Notes |
|---|
source | string | Source node id |
target | string | Target node id |
weightUSD | number | USD-like edge weight used by the current graph |
weight | number | Numeric alias, derived from weightUSD when no explicit weight exists |
txCount | number | Numeric interaction count |
Current edge relationships: wallet-to-token, token-to-protocol, and token-to-counterparty, derived from loaded Ethereum wallet activity.
Serialization guardrails
_observabilityMeta is stripped before the response is sent and must not appear in the response body.
- No provider API key or secret material may appear in any serialized field.
apiErrors[].message is sanitized via sanitizeApiErrorMessage before the route returns.
- Node
label values are sanitized via sanitizeLabel — phishing/spam symbols are redacted.
Non-goals
- No Solana holder analytics are claimed or implied.
- No new provider data is invented.
- No UI layout, loading screen, typography, or graph rendering behavior is part of this contract.
- Do not add new top-level fields to the wallet response without updating this document.