ConceptsCitations

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_url points at the specific article / entity / explainer page.
  • On list endpoints (search_news, list_stablecoins, get_trending) — citations[0].cite_url points 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_url points 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 familyMulti-source status
Articles / news corpusv0.4 (publisher graph)
Market pricesv0.4 (oracle reconciliation)
On-chain readsv0.5 (multi-indexer)
Entity cardsSingle source (by design)
Directories, explainersSingle source (editorial)
Agent jobsSingle 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