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: Bearerheader. - 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
429with aRetry-After: 60header. - Watch the
RateLimit-Remainingresponse 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/cursoris far more efficient than re-fetching.
Response envelope
Every response shares one shape:
| Field | Description |
|---|---|
data | The 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": { … } }
| HTTP | code | Meaning |
|---|---|---|
| 400 | bad_request | Malformed parameter (e.g. non-numeric id). |
| 401 | unauthorized | Missing, invalid, or revoked key. |
| 402 | quota_exceeded | (Reserved for future paid quotas.) |
| 403 | forbidden_tier | Your key's tier can't access this endpoint. |
| 404 | not_found | No such resource. |
| 429 | rate_limited | Slow down; retry after Retry-After seconds. |
| 500 | internal | Something went wrong on our side — retry, then contact us with the request_id. |
Pagination
List endpoints use keyset (cursor) pagination, newest first:
- Make a request (optionally with
limit, default 50, max 100). - If
pagination.has_moreistrue, passpagination.next_cursorback as thecursorparameter to get the next (older) page. - Stop when
has_moreisfalse.
# 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.
| Param | Type | Notes |
|---|---|---|
limit | int | 1–100, default 50 |
cursor | string | keyset cursor from pagination.next_cursor |
source | string | filter by source label (e.g. Telegram, Farside) |
since | ISO 8601 | only items created at/after this time |
include_body | bool | default true; set false to omit body |
include_raw | bool | default 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.
| Param | Type | Notes |
|---|---|---|
asset | string | CSV of BTC,ETH,SOL,HYPE (default: all) |
from, to | date (YYYY-MM-DD) | date range on flow_date |
limit | int | 1–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.
| Param | Type | Notes |
|---|---|---|
limit, cursor | as above | |
pane | string | news, crypto, wire, blogs, twitter, iansintel |
source | string | substring match on source |
important | bool | only items flagged important |
since | ISO 8601 | items at/after this time |
include_summary | bool | default 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.