BTC: ETH:
Ian's Intel

Ian's Intel API

Programmatic, read-only access to the same curated crypto intelligence that publishes to the Ian's Intel channel — filtered news with original-source attribution, structured ETF flow data, weekly briefs, and the raw news firehose.

  • Base URL: https://iansintel.com/v1
  • Format: JSON over HTTPS. GET-only (read-only).
  • Auth: API key via Authorization: Bearer header.
  • Machine spec: /v1/openapi.json (OpenAPI 3.1 — point your tooling here).

Free while in preview. The API is currently free and full-featured. Please use a sensible request rate; heavy or commercial use may move to a paid tier in future — we'll give notice.


Quickstart

curl -H "Authorization: Bearer iik_live_YOUR_KEY" \
  "https://iansintel.com/v1/posts?limit=2"
{
  "data": [
    {
      "uid": "cp_1291",
      "id": 1291,
      "source": "Telegram",
      "username": "iansintel",
      "body": "COINBASE'S BASE NETWORK MOVES AWAY FROM OPTIMISM STACK TO CREATE THEIR OWN",
      "url": "https://t.me/iansintel/7812",
      "original_source_url": "https://base.org/blog/...",
      "created_at": "2026-02-18T17:14:02.105Z"
    }
  ],
  "pagination": { "next_cursor": "1290", "has_more": true },
  "meta": { "api_version": "v1", "request_id": "req_…", "tier": "free" }
}

Authentication

Every endpoint except /health and /openapi.json requires an API key:

Authorization: Bearer iik_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keys are issued by Ian's Intel — contact us to request one. Keep your key secret; treat it like a password. If a key is exposed, ask us to revoke and reissue it.

Missing or invalid keys return 401:

{ "error": { "code": "unauthorized", "message": "Invalid or revoked API key." }, "meta": { … } }

Rate limits

  • ~120 requests/minute per key. Exceeding it returns 429 with a Retry-After: 60 header.
  • Watch the RateLimit-Remaining response header to pace yourself.
  • The API is a live-updating feed — poll politely (every few seconds at most). For most uses, paginating on new data with since/cursor is far more efficient than re-fetching.

Response envelope

Every response shares one shape:

FieldDescription
dataThe result — an array (list endpoints) or object (single-resource endpoints).
pagination{ next_cursor, has_more } on paginated list endpoints; null otherwise.
meta{ api_version, request_id, tier, … }. Include request_id when contacting support. ETF responses add units.

Errors replace data with error:

{ "error": { "code": "not_found", "message": "Post not found." }, "meta": { … } }
HTTPcodeMeaning
400bad_requestMalformed parameter (e.g. non-numeric id).
401unauthorizedMissing, invalid, or revoked key.
402quota_exceeded(Reserved for future paid quotas.)
403forbidden_tierYour key's tier can't access this endpoint.
404not_foundNo such resource.
429rate_limitedSlow down; retry after Retry-After seconds.
500internalSomething went wrong on our side — retry, then contact us with the request_id.

Pagination

List endpoints use keyset (cursor) pagination, newest first:

  1. Make a request (optionally with limit, default 50, max 100).
  2. If pagination.has_more is true, pass pagination.next_cursor back as the cursor parameter to get the next (older) page.
  3. Stop when has_more is false.
# page 1
curl -H "Authorization: Bearer $KEY" "https://iansintel.com/v1/posts?limit=50"
# page 2 — use next_cursor from page 1
curl -H "Authorization: Bearer $KEY" "https://iansintel.com/v1/posts?limit=50&cursor=1290"

Rows are never skipped or duplicated across pages. Every item carries a stable uid (e.g. cp_1291) — use it to de-duplicate or reference items across sessions. To pull only new items since your last sync, keep the highest id/uid you've seen and pass since (a timestamp) or walk cursor until you reach it.


Endpoints

GET /v1/posts — curated feed

The filtered, aggregated news feed (with original-source links). This is the flagship dataset.

ParamTypeNotes
limitint1–100, default 50
cursorstringkeyset cursor from pagination.next_cursor
sourcestringfilter by source label (e.g. Telegram, Farside)
sinceISO 8601only items created at/after this time
include_bodybooldefault true; set false to omit body
include_rawbooldefault false; set true to include the raw source payload

Post fields: uid, id, source, username, body, url (Telegram permalink), original_source_url (original article/tweet), created_at.

GET /v1/posts/{id} — single post

Returns one post by numeric id. include_raw supported. 404 if not found.

GET /v1/etf-flows — US spot-ETF daily flows

Structured per-asset daily flow numbers. All values are raw USD dollars (meta.units: "usd") — e.g. 628069580 = $628.07M.

ParamTypeNotes
assetstringCSV of BTC,ETH,SOL,HYPE (default: all)
from, todate (YYYY-MM-DD)date range on flow_date
limitint1–500, default 100

Flow fields: uid (e.g. etf_BTC_2026-02-18), asset, flow_date, net_inflow, cum_net_inflow, net_assets, value_traded, updated_at.

{
  "data": [
    { "uid": "etf_BTC_2026-02-18", "asset": "BTC", "flow_date": "2026-02-18",
      "net_inflow": -133300000, "cum_net_inflow": 41250000000,
      "net_assets": 128400000000, "value_traded": 2100000000, "updated_at": "2026-02-19T04:45:27.6Z" }
  ],
  "pagination": null,
  "meta": { "api_version": "v1", "request_id": "req_…", "tier": "free", "units": "usd" }
}

GET /v1/etf-flows/latest

The most recent flow_date per asset — the "today's numbers" call. Optional asset filter.

GET /v1/briefs — weekly briefs (list)

Metadata for the weekly intelligence briefs (no body). Paginated. Brief fields: uid (e.g. wb_12), id, week_start, week_end, post_count, created_at.

GET /v1/briefs/{id}

The full brief, including content (Markdown). 404 if not found.

GET /v1/firehose — raw news stream

The unfiltered upstream news firehose. Higher volume and less curated than /v1/posts.

ParamTypeNotes
limit, cursoras above
panestringnews, crypto, wire, blogs, twitter, iansintel
sourcestringsubstring match on source
importantboolonly items flagged important
sinceISO 8601items at/after this time
include_summarybooldefault false; include the AI summary field

Firehose fields: uid (e.g. tm_5678), id, pane, source, source_name, name, username, title, body, summary_ai (if requested), important, url, original_source_url, created_at.

GET /v1/sources — discovery

Returns { curated_sources, firehose_panes, etf_assets } so you can see the valid filter values.

GET /v1/health · GET /v1/openapi.json — open (no key)

Health/version, and the machine-readable OpenAPI spec.


Using it with an LLM / agent

The API is designed for AI agents. Point any OpenAPI-aware tool at https://iansintel.com/v1/openapi.json, and use the stable uids to reference items across turns. Keep responses token-light with include_body=false / include_raw=false (the default) until you need the full text.

Stability

v1 is stable. We may add fields or endpoints without notice; we won't remove or change existing ones without shipping a new version (v2). Check meta.api_version.

Questions or a key request: t.me/iansintel.