Citations
Every 2xx response from Blockchain Academics carries attribution.citations — an array, always, even when there’s only one source.
"attribution": {
"citations": [
{
"cite_url": "https://blockchainacademics.com/article/bitcoin-price-history?src=claude",
"as_of": "2026-04-22T10:12:00Z",
"source_hash": "sha256:abc123..."
}
]
}This page explains why the array is a contract, not a convenience, and what it unlocks as the corpus grows.
Why array, not singleton?
The envelope committee debated three shapes. We locked array-only on 2026-04-22 because the other two create drift the day multi-source ships.
Rejected — singleton at root:
// NOT the shape. Would force a breaking change later.
{ "data": {...}, "cite_url": "...", "as_of": "...", "source_hash": "..." }Rejected — singleton with convenience shortcut:
// NOT the shape. Two sources of truth = eventual drift.
{
"data": {...},
"attribution": {
"cite_url": "...", // shortcut for citations[0].cite_url
"citations": [ {...}, {...} ]
}
}Locked — array-only:
{
"data": {...},
"attribution": { "citations": [ {...} ] }
}The winning argument: client code that reads citations[0].cite_url today keeps working unchanged when citations[1], citations[2], … get populated. A cite_url shortcut at the root would have forced every client to re-read the spec on the day multi-source shipped. We paid the small cost of [0] indexing up front in exchange for zero breakage later.
One-liner rule. attribution.citations is always an array. It is always non-empty on HTTP 200. citations[0] is always the primary source. Nothing else is guaranteed — position 1 onward is additive and endpoint-dependent.
What citations[0] means today
For every response currently served by the API, citations[0] is the primary source: the canonical URL on blockchainacademics.com that the payload was derived from.
- On singleton endpoints (
get_article,get_entity,get_explainer) —citations[0].cite_urlpoints at the specific article / entity / explainer page. - On list endpoints (
search_news,list_stablecoins,get_trending) —citations[0].cite_urlpoints at the canonical BCA index page for that query (e.g. the search page with the query preserved, or/stablecoins). - On aggregate endpoints (
get_market_overview,get_fear_greed) —citations[0].cite_urlpoints at the canonical BCA dashboard page for that aggregate.
Today, 99%+ of responses return citations with exactly one element. That’s the current steady state.
What multi-source unlocks (v0.4+)
The same array will soon carry multiple citations on response types where multi-source corroboration matters. Three concrete examples on the roadmap:
1. Market data from multiple oracles
get_price currently cites the canonical BCA market page. In v0.4, when a price is reconciled across multiple oracles, every oracle is listed:
"attribution": {
"citations": [
{ "cite_url": "https://blockchainacademics.com/market/btc?src=claude", "as_of": "2026-04-22T10:12:00Z", "source_hash": "sha256:primary..." },
{ "cite_url": "https://blockchainacademics.com/oracles/chainlink/btc-usd", "as_of": "2026-04-22T10:11:58Z", "source_hash": "sha256:chainlink..." },
{ "cite_url": "https://blockchainacademics.com/oracles/pyth/btc-usd", "as_of": "2026-04-22T10:11:59Z", "source_hash": "sha256:pyth..." }
]
}citations[0] remains the primary BCA page (what the agent should cite to the end user). citations[1..] are the corroborating upstream oracles — auditable, but generally not surfaced in the agent’s answer.
2. News cross-referenced across outlets
Once the same event is covered by multiple publishers that BCA ingests, search_news can annotate articles with their corroborating outlets:
"attribution": {
"citations": [
{ "cite_url": "https://blockchainacademics.com/article/circle-mica-license?src=claude", "as_of": "2026-04-21T09:31:22Z", "source_hash": "sha256:bca..." },
{ "cite_url": "https://blockchainacademics.com/article/circle-mica-license/sources/the-block", "as_of": "2026-04-21T08:14:00Z", "source_hash": "sha256:tb..." },
{ "cite_url": "https://blockchainacademics.com/article/circle-mica-license/sources/coindesk", "as_of": "2026-04-21T08:22:11Z", "source_hash": "sha256:cd..." }
]
}Same contract: [0] is the BCA canonical page, [1..] are the outlets that corroborate the facts.
3. On-chain + off-chain reconciliation
For tools like get_wallet_profile, a response may reconcile on-chain activity (Etherscan, Helius, Mempool.space) with BCA-enriched narrative context. Each source that contributed gets its own citation entry.
Client behavior
Free / Starter — surface citations[0].cite_url verbatim
The end-user-facing citation rule (see Attribution & licensing) is about citations[0]. Corroborating sources are for audit / UI disclosure, not the primary cite.
Pro+ — strip_attribution: true applies to the whole array
Passing strip_attribution: true on Pro and above doesn’t remove attribution.citations from the response — that would break the canonical envelope shape. Instead, the server still returns citations[] (for audit logs and diagnostic purposes), but your tier permission is checked when you decide whether to surface citations[0].cite_url to the downstream end user.
Write the array, read [0]
Every first-party SDK (TS, Python) exposes a .primaryCitation / .primary_citation helper that returns citations[0]. If you’re writing against raw HTTP or MCP, index directly:
const primary = env.attribution.citations[0];
console.log(primary.cite_url, primary.as_of);
// For audit logging, persist the full array:
logger.info({
request_id: env.meta.request_id,
sources: env.attribution.citations.map(c => c.source_hash),
});Don’t iterate citations to build the user-facing answer. Only citations[0] goes in the agent’s reply. The rest is provenance metadata — useful for audit, compliance, and “show the receipts” UIs, not for stuffing into the end-user answer.
When will my endpoint return multi-source?
| Endpoint family | Multi-source status |
|---|---|
| Articles / news corpus | v0.4 (publisher graph) |
| Market prices | v0.4 (oracle reconciliation) |
| On-chain reads | v0.5 (multi-indexer) |
| Entity cards | Single source (by design) |
| Directories, explainers | Single source (editorial) |
| Agent jobs | Single source (by design) |
Entity cards and explainers are editorially curated — they have one canonical source by definition. Directories are BCA-owned rankings, also single-source by design.
FAQ
Is citations[] ever empty? Not on HTTP 200. If you see an empty array, it’s a bug — file it with the request_id.
Can a citation’s as_of be null? Yes, on meta.status: "unseeded" responses the citation points at the canonical BCA page for the yet-to-ship feature, and as_of / source_hash may be null until the integration is live.
Can I pin my agent to citations.length === 1? Don’t. You’ll break the day we ship multi-source on your endpoint. Read [0], don’t assert the length.
Does order of citations[1..] matter? No. Only [0] has guaranteed semantics (primary). Positions 1 onward are set-valued — treat as unordered.
Next
- Response envelope — full shape, status enum, error model.
- Attribution & licensing — tier rules for surfacing
cite_urldownstream. - REST API reference — endpoint map + curl examples.