Docs navigation

REST API reference

Every MCP tool is a thin wrapper around a REST endpoint on api.blockchainacademics.com. If you would rather call HTTP directly (a non-MCP integration, a server-side pipeline, an internal job runner), the same API key and the same canonical envelope apply.

Base URL

https://api.blockchainacademics.com

The MCP servers and the CLI read BCA_API_BASE to point at another host (an allowlist: production, https://staging-api.blockchainacademics.com, and localhost); a custom HTTP client sets its own base URL. See Environment variables.

Authentication

Every request carries the API key in a header:

X-API-Key: bca_live_xxxxxxxxxxxxxxxx

Or, equivalently, using the Authorization convention:

Authorization: Bearer bca_live_xxxxxxxxxxxxxxxx

The server accepts either. Get a key at blockchainacademics.com/crypto-api/signup.

Response envelope

Every 2xx response returns the canonical three-key envelope:

json
{
  "data": { "...": "endpoint-specific payload" },
  "attribution": {
    "citations": [
      {
        "cite_url": "https://blockchainacademics.com/...",
        "as_of": "2026-04-22T10:12:00Z",
        "source_hash": "sha256:abc123..."
      }
    ]
  },
  "meta": {
    "status": "complete",
    "request_id": "req_01HABCDEF0123456789ABCDEFG",
    "pageInfo": {
      "hasNextPage": false,
      "hasPreviousPage": false,
      "startCursor": null,
      "endCursor": null
    }
  }
}

Full field-by-field breakdown: Response envelope. Citation semantics: Citations.

Response headers

Every response carries:

X-Request-ID: req_01HABCDEF0123456789ABCDEFG
X-RateLimit-Limit: 1200
X-RateLimit-Remaining: 1187
X-RateLimit-Reset: 1713787200

X-Request-ID mirrors meta.request_id. Log it with every call. X-RateLimit-Reset is Unix epoch seconds.

Core endpoint map

Endpoint groupPathWho uses it
Articles / corpus/v1/articles/...search_news, get_article, get_as_of_snapshot
Entities/v1/entities/...get_entity, list_entity_mentions
Topics/v1/topicslist_topics
Academy/v1/academy/...get_explainer
Market/v1/market/...get_price, get_ohlc, get_market_overview, get_pair_data
On-chain/v1/onchain/...get_wallet_profile, get_tx, get_token_holders
Sentiment/v1/sentiment/...get_sentiment, get_social_pulse, get_fear_greed
Proprietary indicators/v1/indicators/...get_coverage_index, get_narrative_strength, …
Agent jobs/v1/agents/...generate_due_diligence, translate_contract, get_agent_job
Directories/v1/directories/...list_stablecoins, list_yields, list_vcs, list_jobs, get_job, …
Fundamentals/v1/fundamentals/...get_tokenomics, get_audit_reports, compare_protocols
Chain-specific/v1/chains/...get_solana_ecosystem, get_l2_comparison
Regulatory/v1/regulatory/...get_regulatory_status, track_sec_filings, get_mica_status
Security/v1/security/...scan_contract, check_phishing_domain, get_bug_bounty_programs
History time-series/v1/history/...get_history_prices, get_history_sentiment, …
Services (revenue, POST)/v1/services/...book_kol_campaign, request_custom_research, submit_listing
Grants/v1/grants/...search_grants, get_grant
Studio (leads)/v1/studio/...Internal: powers the studio's contact form

For exact parameters, request bodies, and response shapes of every endpoint, see the live Swagger. This page intentionally does not duplicate it: the OpenAPI JSON is the source of truth, and a mirror drifts.

Example: search_news over HTTP

bash
curl -s "https://api.blockchainacademics.com/v1/articles/search?q=circle+mica&limit=5" \
  -H "X-API-Key: $BCA_API_KEY"

Response:

json
{
  "data": {
    "items": [
      {
        "slug": "circle-mica-license",
        "title": "Circle secures full MiCA license",
        "published_at": "2026-04-18T14:02:17Z",
        "summary": "Circle became the first USD stablecoin issuer…",
        "entities": ["circle", "mica", "european-union"]
      }
    ],
    "total": 1
  },
  "attribution": {
    "citations": [
      {
        "cite_url": "https://blockchainacademics.com/article/circle-mica-license?src=custom&utm_medium=http&utm_campaign=search_news",
        "as_of": "2026-04-21T09:31:22Z",
        "source_hash": "sha256:a9f1b7de2c4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1"
      }
    ]
  },
  "meta": {
    "status": "complete",
    "request_id": "req_01HABCDEF0123456789ABCDEFG",
    "pageInfo": {
      "hasNextPage": false,
      "hasPreviousPage": false,
      "startCursor": null,
      "endCursor": null
    }
  }
}

Example: list with pagination

Collection endpoints paginate via meta.pageInfo, in the Linear / GraphQL cursor style.

bash
curl -s "https://api.blockchainacademics.com/v1/articles/search?q=ethereum&limit=2" \
  -H "X-API-Key: $BCA_API_KEY"
json
{
  "data": {
    "items": [
      { "slug": "eth-pectra-mainnet", "title": "Pectra goes live on Ethereum mainnet", "published_at": "2026-04-20T12:00:00Z" },
      { "slug": "eth-staking-rate",   "title": "ETH staking yield falls below 3%",     "published_at": "2026-04-19T08:31:00Z" }
    ],
    "total": 147
  },
  "attribution": {
    "citations": [
      {
        "cite_url": "https://blockchainacademics.com/search?q=ethereum&src=custom&utm_medium=http&utm_campaign=search_news",
        "as_of": "2026-04-22T10:12:00Z",
        "source_hash": "sha256:b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3"
      }
    ]
  },
  "meta": {
    "status": "complete",
    "request_id": "req_01HABCDEF0123456789ABCDEFK",
    "pageInfo": {
      "hasNextPage": true,
      "hasPreviousPage": false,
      "startCursor": "c_01HABCDEF000000000000AAAA",
      "endCursor":   "c_01HABCDEF000000000000BBBB"
    }
  }
}

To fetch the next page, pass the endCursor as after:

bash
curl -s "https://api.blockchainacademics.com/v1/articles/search?q=ethereum&limit=2&after=c_01HABCDEF000000000000BBBB" \
  -H "X-API-Key: $BCA_API_KEY"

Cursor format is server-internal: never parse or construct it client-side.

Example: degraded response (partial)

json
{
  "data": {
    "candles": [
      { "t": "2026-04-22T09:00:00Z", "o": 67200.5, "h": 67450.0, "l": 67100.0, "c": 67380.2 },
      { "t": "2026-04-22T10:00:00Z", "o": 67380.2, "h": null,    "l": null,    "c": null }
    ]
  },
  "attribution": {
    "citations": [
      {
        "cite_url": "https://blockchainacademics.com/market/btc?src=custom&utm_medium=http&utm_campaign=get_ohlc",
        "as_of": "2026-04-22T10:12:00Z",
        "source_hash": "sha256:b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3"
      }
    ]
  },
  "meta": {
    "status": "partial",
    "request_id": "req_01HABCDEF0123456789ABCDEFI",
    "pageInfo": {
      "hasNextPage": false,
      "hasPreviousPage": false,
      "startCursor": null,
      "endCursor": null
    },
    "diagnostic": {
      "reason": "Upstream returned 502 on 1 of 2 candles.",
      "vendor": "coingecko",
      "upstream_status": 502
    }
  }
}

Errors

Errors return HTTP 4xx/5xx and an error body: they do not reuse the envelope shape.

json
{
  "error": {
    "code": "BCA_BAD_REQUEST",
    "message": "`limit` must be between 1 and 200.",
    "request_id": "req_01HABCDEF0123456789ABCDEFG"
  }
}
HTTPerror.codeMeaning
400BCA_BAD_REQUESTValidation failure.
401BCA_AUTHMissing / invalid key.
403BCA_TIER_LOCKEDCaller below required tier for the tool.
404BCA_NOT_FOUNDEntity / article / slug not in corpus.
429BCA_RATE_LIMITRate-limited. Honor Retry-After header.
5xxBCA_UPSTREAMBackend failure. Retry with backoff.

Every error body carries request_id. It matches the X-Request-ID response header. Include it in any support ticket.

Integration-state responses are not errors. If a tool's upstream is not wired in yet, the response is HTTP 200 with meta.status: "unseeded" and a meta.diagnostic block: see Envelope → Status decision tree.

Pagination

List endpoints accept:

ParamDefaultMaxNotes
limit10 to 50200Per-endpoint max documented in Swagger.
afternonenoneOpaque cursor from the previous page's endCursor.
beforenonenoneOpaque cursor for backward pagination (where enabled).

Inspect meta.pageInfo on every response to decide whether to keep walking. Do not assume data.items.length < limit means you are done: some endpoints return up to limit per page even when more exist.

Rate limits

Rate limits are per key, not per IP. Live state lives in headers, not the body:

X-RateLimit-Limit: 1200
X-RateLimit-Remaining: 1187
X-RateLimit-Reset: 1713787200

Each plan has a per-second rate limit and a monthly call quota, both listed on Pricing; over the limit you get HTTP 429 with Retry-After (see Rate-limit response). Agent loops with retries should cache. See Tiers & quotas for what changes between tiers.

Webhooks (v0.4)

Webhook delivery exists for monitor_keyword (its required webhook_url argument: HTTPS only, public hosts only, validated before the request leaves) and is a Pro feature alongside agent-job completion; see Pricing. Payloads reuse the canonical envelope shape, including meta.request_id for idempotency, and are signed with HMAC-SHA256 for verification through the X-BCA-Signature header. The completion payload looks like this; the final field list is documented here when the spec is locked:

json
{
  "event": "job.completed",
  "job_id": "job_a3f2c891",
  "tool": "generate_due_diligence",
  "result_url": "https://api.blockchainacademics.com/v1/agents/jobs/job_a3f2c891",
  "completed_at": "2026-04-20T17:36:42Z"
}

Failed deliveries are retried with exponential backoff over 24 hours.

Next