CEOInterviews API

The largest verified dataset of C-suite interview transcripts on the internet. We track 20,000+ executives (CEO, CFO, COO, founders) at public and private companies spanning the S&P 500, Nasdaq, Russell, AI labs, and emerging markets, plus key politicians and policymakers. Every podcast, conference talk, and interview an executive gives is captured and turned into structured, queryable data: full transcripts, speaker-attributed dialogue, extracted quotes, and rich metadata.

The feed is signal, not noise. Every record passes a multi-stage AI pipeline backed by a human QA team before it reaches the API, so what you query is genuine first-person executive content. No duplicates, no reshares, no clipped highlight reels, no third-party commentary, no name-collision mistakes.

New: the API now also serves Substack newsletter data: daily articles from a curated registry of the most market-relevant finance and tech publications (Ray Dalio, Michael Burry, SemiAnalysis, The Bear Cave, and more), with AI-extracted, ticker-mapped company and executive mentions.

What makes the data different

  • Speaker-attributed. Every appearance ships with enhanced_transcript, a diarized transcript that labels exactly which sentences the executive said versus the host or other panelists.
  • Verified, not just scraped. Combined AI and human review confirms the named executive is actually on camera and speaking firsthand before a record is included.
  • Deduplicated. When one interview is reposted across dozens of channels, we keep only the authoritative source and drop the rest.
  • Accurately dated. appearance_date_v2 resolves when a statement was actually made, which often differs from the upload date.
  • Mapped to tickers and SEC CIKs. Executives join to companies, stock tickers and SEC Central Index Keys (CIK), so you can pull by person, by company name, by ticker, or by CIK, and join straight to EDGAR filings.
Low quality source with red X
CEOInterviews AI Verified with green checkmark

enhanced_transcript: who said what, down to the sentence

Most of our customers, from equity research desks to academic researchers, care most about one field: enhanced_transcript. A raw transcript blurs every speaker into one block of text. Our enhanced transcript is speaker-attributed, so you can isolate exactly what the executive said and drop the interviewer, host, and other panelists.

Each segment carries the resolved speaker_name, a speaker_id that links back to our entity database when the executive is the one talking (null for hosts and others), the timestamp, and the cleaned content.

import requests

HEADERS = {"X-API-Key": "YOUR_API_KEY"}

# Pull an Amazon appearance and keep only the sentences Andrew Jassy said
resp = requests.get(
    "https://ceointerviews.ai/api/get_feed/",
    params={"entity_name": "Andrew Jassy", "page_size": 1},
    headers=HEADERS,
)
item = resp.json()["results"][0]

ceo_only = [seg for seg in item["enhanced_transcript"] if seg["speaker_id"] == item["entity_id"]]
for seg in ceo_only:
    print(f'[{seg["timestamp"]}] {seg["content"]}')

Example enhanced_transcript from the response:

"enhanced_transcript": [
	{"speaker_name": "Liz", "speaker_id": None, "timestamp": "00:02:48", "content": "What have you seen from your overall customer at Amazon?"},
	{"speaker_name": "Andrew Jassy", "speaker_id": 22, "timestamp": "00:02:52", "content": "Consumers are still quite resilient. We see customers spending. For many months now, customers are aware that there is some uncertainty. They are being careful about how much they spend..."},
	{"speaker_name": "Liz", "speaker_id": None, "timestamp": "00:03:51", "content": "There is a report that Amazon is building a phone that could be heavily embedded with Alexa."},
	{"speaker_name": "Andrew Jassy", "speaker_id": 22, "timestamp": "00:04:00", "content": "Liz, I'm not going to comment on those rumors."}
]

The raw, SRT-style transcript ships in the same response when you want the verbatim source text. Both fields come back from /api/get_feed/ for every appearance.

Pull first‑person, AI and human verified remarks on a topic from specific leaders.

import requests

HEADERS = {"X-API-Key": "YOUR_API_KEY"}

leaders = ["Jerome Powell", "Jamie Dimon"]
for name in leaders:
    # Directly fetch conversations about inflation for each leader
    resp = requests.get(
        "https://ceointerviews.ai/api/get_feed/",
        params={"entity_name": name, "keyword": "inflation", "page_size": 3},
        headers=HEADERS,
    )
    for it in resp.json()["results"]:
        # Entity identity is included in each conversation
        print(f"{it['entity_name']}, {it.get('entity_title', '')} ({it.get('institution', '')})")

        # Transcript metadata and excerpt
        print(it.get("item_title", ""), it.get("publish_date", ""))
        print(it.get("transcript", "")[:400])
        print()

Example output:

Jerome Powell, Chair (Federal Reserve)
FOMC Press Conference 2025-09-18T18:30:00+00:00
[excerpt] Inflation has eased but remains elevated; we’ll keep policy restrictive until we’re confident it’s moving sustainably to 2 percent.

Jamie Dimon, CEO (JPMorgan Chase)
CNBC interview: Inflation, Rates, Growth 2025-07-10T13:05:00+00:00
[excerpt] We’re preparing for rates to be higher for longer; consumers are still spending, but excess savings are running down and risks are building.

Every transcript contains transparent why‑it‑passed metadata for compliance‑grade analysis and model training.

NEW: Substack newsletter data, mapped to the executives and tickers you track

Executives talk on podcasts. Investors, founders, and the sharpest independent analysts write. Increasingly, they write on Substack. Alongside our verified interview transcripts, the API now serves a structured feed of Substack newsletter articles from a curated registry of the most market-relevant publications: Ray Dalio's Principled Perspectives, Michael Burry's Cassandra Unchained, SemiAnalysis, The Bear Cave, Net Interest, Import AI, The Pomp Letter, Chamath Palihapitiya, Reid Hoffman, and thousands more across equities, credit, macro, semiconductors, AI, and crypto.

This is not RSS scraping. Every article runs through the same entity-resolution machinery as our transcripts, so newsletter content arrives already joined to the executives, companies, and stock tickers you track, queryable through one endpoint, /api/get_substack_posts/, with the same API key you already use.

What makes the newsletter data different

  • Curated, ranked registry. Publications are scored and ranked for market relevance: founder-written letters, professional research shops, and the long tail of niche sector specialists. The most market-relevant publications are polled many times a day, so new articles land in the API within hours of publishing.
  • Ticker-mapped mentions. An AI pass reads every article and extracts which public companies, tickers, and named executives it substantively covers, resolved against our entity database. Ask for "every newsletter article discussing NVDA this week" the same way you ask for interview transcripts.
  • Author and subject resolution. When a tracked executive writes the newsletter (Dalio, Burry, Hoffman) or is the clear subject of the article, the record is anchored to their entity_id, the same ID you use in /api/get_feed/.
  • Verbatim, addressable excerpts. Key passages about linked companies and executives are extracted as quote objects, verified verbatim against the article body.
  • Full article text. Free posts ship with complete cleaned body text. Paywalled posts include the publisher's preview and are flagged is_preview_only so your pipeline can tell them apart.

Why it matters: newsletter authors publish their theses between the disclosure cycle, often weeks before the same argument shows up in sell-side notes or the financial press. Combined with our interview transcripts, you can watch an idea move from an executive's mouth to the analyst community to the market, all keyed to the same entity and company IDs.

import requests

HEADERS = {"X-API-Key": "YOUR_API_KEY"}

# Every newsletter article substantively covering Nvidia, newest first
resp = requests.get(
    "https://ceointerviews.ai/api/get_substack_posts/",
    params={"company_name": "NVDA", "page_size": 5},
    headers=HEADERS,
)
for article in resp.json()["results"]:
    pub = article["publication"]
    tickers = [m["ticker"] for m in article["mentions"] if m["ticker"]]
    print(f'{pub["name"]}: {article["item_title"]}  {tickers}')

Example output:

SemiAnalysis: Cerebras's Next Generation CS-4: Fast Just Got Faster  ['NVDA', 'AMD', 'TSM']
Fabricated Knowledge: The State of the Semiconductor Cycle  ['NVDA', 'MU', 'AVGO']
The Chip Letter: Blackwell, Rubin and the Inference Buildout  ['NVDA', 'TSM']

Full parameter and response documentation: GET /api/get_substack_posts/. Substack access is governed by your API plan or enterprise data license; contact us if your key does not yet include it.

Authentication

The API is plain HTTP. Every call is a GET with your API key in the X-API-Key header and filters passed as query params; responses come back as JSON. Any HTTP client works, the examples here use Python requests. Subscribe to the API plan to get a key.

pip install requests
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://ceointerviews.ai"
HEADERS = {"X-API-Key": API_KEY}

# Every endpoint follows the same shape
resp = requests.get(
    f"{BASE_URL}/api/get_feed/",
    params={"entity_name": "elon musk", "page_size": 10},
    headers=HEADERS,
)
resp.raise_for_status()
data = resp.json()          # {"results": [...], "page_has_next": ..., "page_num": ...}
results = data["results"]

Get API access now


Quick Start: High‑quality transcripts for an entity

Fetch an entity's conversations and read the transcript plus AI reasons/scores that justify quality.

# 1) Fetch high‑quality conversations directly using entity_name
resp = requests.get(
    f"{BASE_URL}/api/get_feed/",
    params={"entity_name": "elon musk", "page_size": 10},
    headers=HEADERS,
)
feed = resp.json()["results"]

# 2) Inspect transcript and AI review metadata
item = feed[0]
print(f"Transcript Title: {item['item_title']}")
print(f"Length of transcript: {len(item['transcript'])} words")

# Quality reasons/scores live in the extra dict (we expose many; two important ones below)
extra = item.get("extra", {})
print(f"Transcript detection reason: {extra.get('transcript_first_person')}")
print(f"Transcript detection score: {extra.get('transcript_first_person_score')}")

Example output:

Transcript Title: Elon Musk on Q4 Autonomy Progress: 2025 Earnings Call
Length of transcript: 23489 words
Transcript detection reason: First-person speech confirmed via pronoun usage and diarization; original audio, no dubbing
Transcript detection score: 0.97

Core Concepts

The CEOInterviews API is built around several key resources:

Entities

An Entity represents an influential individual such as a CEO, politician, or executive. Each entity has an ID, name, title, and associated organization information.

Feed Items (transcripts of public appearances and metadata)

Transcribed interviews, podcasts, and appearances where entities have spoken. Each feed item includes a title, the raw transcript, the speaker-attributed enhanced_transcript, attached Quote objects extracted from the transcript, and rich metadata such as publish dates, source links, and quality review scores.

Quotes

Notable statements extracted from feed items. These can be filtered by attributes like "controversial" or "financial policy." Each Quote is attached to both an Entity and a Feed Item.

Companies

Organizations associated with entities, including both public companies (with tickers) and private institutions. Each Company has a list of Entities linked to it, usually the C-suite. Companies that file with the SEC also carry their 10-digit SEC CIK in the cik field.

Common Workflows

Company Conversations
# Fetch conversations from Microsoft executives directly
resp = requests.get(
    f"{BASE_URL}/api/get_feed/",
    params={"company_name": "MSFT", "page_size": 25},
    headers=HEADERS,
)
for convo in resp.json()["results"]:
    print(f"Video/Transcript Title: {convo['item_title']}")
    print(f"Microsoft Executive Name: {convo.get('entity_name')} ({convo.get('entity_title')})")
    print("---")

Example output:

Video/Transcript Title: Satya Nadella on AI Cloud Economics and Azure Earnings Highlights
Microsoft Executive Name: Satya Nadella (Chairman & CEO)
---
Video/Transcript Title: Amy Hood Breaks Down AI CapEx and Margins Q&A Session
Microsoft Executive Name: Amy Hood (EVP & CFO)
---
Video/Transcript Title: Kevin Scott on Copilot Roadmap and Inference Efficiency
Microsoft Executive Name: Kevin Scott (CTO & EVP, AI)
---

Note: Each conversation object returned by get_feed contains not only conversation/transcript data, but also the associated entity metadata, such as entity_name, entity_title, and institution, making it easy to display context alongside conversation content.

Quotes

Search quotes for an entity and stack filters like is_controversial and keyword search.

# Get controversial quotes from Elon Musk about bitcoin
resp = requests.get(
    f"{BASE_URL}/api/get_quotes/",
    params={
        "entity_name": "elon musk",
        "keyword": "bitcoin",
        "is_controversial": "true",
        "page_size": 25,
    },
    headers=HEADERS,
)
for q in resp.json()["results"]:
    print(f"{q['text'][:80]}...")
Unscripted commentary only (event_type)

Every conversation carries an event_type. Pass a comma-separated list to keep only podcasts and conference sessions, or list the other four values to exclude earnings calls.

# Podcasts and conference sessions from Nvidia executives, newest first
resp = requests.get(
    f"{BASE_URL}/api/get_feed/",
    params={"company_name": "NVDA", "event_type": "podcast,conference", "page_size": 25},
    headers=HEADERS,
)
for convo in resp.json()["results"]:
    print(f"{convo['event_type']:16} {convo['publish_date'][:10]}  {convo['item_title']}")

Endpoints

GET
/api/get_feed/

Returns feed data for "conversations" (such as podcasts or interviews) for an entity, company, or keyword. All parameters are optional. If no filters are provided, returns all conversations ordered by recency.

Parameter Type Description
entity_name string Optional. Search by entity name (e.g. "elon musk", "jerome powell")
company_name string Optional. Search by company name or ticker (e.g. "tesla", "TSLA", "JPMorgan")
keyword string Optional. Search conversation data by keywords. Returns conversations where your keyword has been spoken in the dialogue or where the keyword is in the title. Results are relevance ranked, and only conversations that actually contain the keyword are returned, so a keyword with no matches returns an empty list rather than loosely related rows. Relevance ranking is depth limited to 5,000 conversations per query. To walk a larger match set exhaustively, page through it in date windows with filter_before_dt and filter_after_dt, which bound the ranking rather than truncating it.
entity_id integer Optional. Fetch all recent conversations of a specific entity by ID. Get this ID from /api/get_entities. Alternative to entity_name (takes precedence if both provided).
company_id integer Optional. Filter for conversations where the key speaker is an executive or leader from the company at company_id. Get this ID using /api/get_companies. Alternative to company_name (takes precedence if both provided).
ticker string Optional. Strict filter by exact stock ticker, e.g. CAT, BRK.B. Unlike company_name it never falls back to a partial name match; unknown tickers return 404. company_id takes precedence if both provided.
cik string Optional. Strict filter by SEC Central Index Key, with or without leading zeros, e.g. 0000320193 or 320193. Pass the institution_cik from a feed item or the cik from /api/get_companies. Unknown CIKs return 404. Anything that is not a number returns 400, including null, so check for a missing CIK before you send it. Companies that do not file with the SEC have no CIK and cannot be queried this way. company_id takes precedence if both provided.
filter_before_dt string Optional. Only return conversations published on or before this date. ISO 8601 format (e.g. 2025-06-01 or 2025-06-01T00:00:00+00:00).
filter_after_dt string Optional. Only return conversations published on or after this date. ISO 8601 format. Combine with filter_before_dt to query a closed date window.
filter_updated_after_dt string Optional. Only return conversations whose update_time is at or after this instant. ISO 8601 format. Built for incremental syncs: watermark on the max update_time you've seen, then poll with this parameter to pick up new rows and re-saved rows (engagement refreshes, transcript edits, speaker re-attribution) in one pass. Combine with include_deleted=true to also observe source-deleted tombstones.
include_deleted boolean Optional. Default false. When true, conversations whose source video/podcast has since been removed from the source platform are included instead of filtered out; such rows carry is_deleted_on_source: true and act as soft-delete tombstones (the transcript remains in our archive). Use with filter_updated_after_dt so your sync sees deletions rather than rows silently disappearing.
event_type string Optional. Only return conversations of these kinds. Comma-separated subset of earnings_call, conference, podcast, news_appearance, other. For example event_type=podcast,conference keeps unscripted executive commentary, and listing the other four excludes earnings calls. Unknown values return 400.
page_num integer Optional. Page number for pagination (default: 1)
page_size integer Optional. Number of results per page (default: 10, max: 500).
before_feed_item_id integer Optional. For keyset-style pagination. Only return feed items with IDs less than this value. Use last_seen_id from the previous response. Cannot be combined with keyword.

Responses include transcript text and AI review metadata (e.g. transcript_first_person, transcript_first_person_score under review/extra).

With the power of the /api/get_feed API, you can search all of Elon Musk's recent podcast appearances or Jerome Powell's interviews by first fetching their entity_id from the /api/get_entities endpoint and then using it here. Paginate through the entire feed and use as needed. Each conversation object contains the entire transcript of the convo, the quotes extracted from it, and other important metadata like publish_date.

Simple usage

Get Donald Trump's conversation feed and page through it.

# Directly fetch Trump's conversations using entity_name
resp = requests.get(
    f"{BASE_URL}/api/get_feed/",
    params={"entity_name": "donald trump"},
    headers=HEADERS,
).json()

if resp["page_has_next"]:
    page_2 = requests.get(
        f"{BASE_URL}/api/get_feed/",
        params={"entity_name": "donald trump", "page_num": 2},
        headers=HEADERS,
    ).json()

Get Donald Trump's conversations where "israel" is mentioned.

resp = requests.get(
    f"{BASE_URL}/api/get_feed/",
    params={"entity_name": "donald trump", "keyword": "israel"},
    headers=HEADERS,
).json()
print(f"Num results: {len(resp['results'])}")
Response Format

Every endpoint returns a JSON object: a top-level schema_version (currently 1.5.0; we bump it whenever the API changes substantially, so pin or log it in your sync), the matching rows under results, plus pagination fields page_has_previous, page_has_next, and page_num. get_feed and get_quotes also include last_seen_id for keyset pagination, and get_quotes adds num_results.

# resp.json() returns a dict:
{
	"results": [
		{
			"item_title": "Trump points finger at Newsom for CA wildfires: 'He is the blame for this'",
			"transcript": """[\"1\\n00:00:0,733 --> 00:00:4,870\\nPAST THE BURNED OUT HOME AFTER\", \"2\\n00:00:2,702 --> 00:00:4,870\\n \", \"3\\n00:00:2,769 --> 00:00:6,739\\nBURNED OUT HOMES. THIS DISASTER\""",
			"enhanced_transcript": [
				{"speaker_name": "Reporter", "speaker_id": None, "timestamp": "00:00:02", "start_seconds": 2, "content": "Mr. President, what is your reaction to the wildfires devastating California right now?"},
				{"speaker_name": "Donald Trump", "speaker_id": 5099, "timestamp": "00:02:41", "start_seconds": 161, "content": "He is the blame for this. They were warned, the water was there, and the state refused to use it."},
			],
			"language": "en",
			"word_count": 1893,
			"categories": ["California politics", "wildfires"],
			"is_explicit": False,
			"event_type": "news_appearance",
			"participants": [
				{"name": "Donald Trump", "entity_id": 5099, "is_primary": True, "is_speaker_in_transcript": True},
				{"name": "Reporter", "entity_id": None, "is_primary": False, "is_speaker_in_transcript": True},
			],
			"source_url": "https://www.youtube.com/watch?v=P5iLxW9AoMU",
			"entity_name": "Donald Trump",
			"institution": "Trump Media & Technology Group",
			"entity_title": "45th U.S. President",
			"thumbnail_image_url": "https://i.ytimg.com/vi_webp/P5iLxW9AoMU/maxresdefault.webp",
			"is_politician": True,
			"is_company_leader": False,
			"publish_date": "2025-01-09T07:48:59+00:00",
			"entity_img": "https://ceointerviews.ai/static/images/entity_pfps/5099.png",
			"feed_item_id": 58827,
			"entity_id": 5099,
			"company_id": 1289,
			"institution_ticker": "DJT",
			"institution_cik": "0001849635",
			"share_link": "https://ceointerviews.ai/interview/1163320/",
			"appearance_date_v2": "2025-01-08",
			"server_created_at": "2025-01-10T04:22:11+00:00",
			"update_time": "2025-02-03T09:15:47+00:00",
			"is_deleted_on_source": False,
			"quotes": [
				{
					"quote_pk": 91230,
					"quote_text": "He is the blame for this...",
					"source_url": "https://www.youtube.com/watch?v=P5iLxW9AoMU",
					"source_title": "Trump points finger at Newsom for CA wildfires",
					"is_notable": True,
					"is_controversial": True,
					"is_financial_policy": False,
					"source_created_at": "2025-01-09T07:48:59+00:00",
					"timestamp_from_tx": "00:02:41",
					"timestamp_seconds": 161,
					"timestamp_end_from_tx": "00:03:05",
					"timestamp_end_seconds": 185,
					"topics": ["wildfires", "California politics"],
					"entities": ["Gavin Newsom"],
					"companies": [],
					"quote_url": "/quote/trump-newsom-wildfires-91230/",
					"interview_url": "/interview/91007/",
				},
			],
			"extra": {
				"transcript_first_person": "First-person speech confirmed via diarization",
				"transcript_first_person_score": 0.97,
				"view_count": 182034,
				"like_count": 4101,
				"duration_secs": 312,
				"channel_name": "Fox News",
			},

		},
		# ... more results here ...
		# ...
	],
	"schema_version": "1.5.0",
	"page_has_previous": False,
	"page_has_next": False,
	"page_num": 1,
	"last_seen_id": 58827,
}
Response Params
Parameter Type Description
feed_item_id integer Unique ID representing this conversation (or feed item).
company_id integer The company ID of the company that the key entity which is associated with this feed item (transcript)
entity_id integer Entity ID of the key entity that is speaking in the conversation.
source_url string Original URL of the underlying conversation. Can be a Youtube or Podcast link.
item_title string Title of the conversation, this can be a YouTube video title or podcast episode title.
transcript string The raw string transcript of the conversation. Extracted from the underlying podcast or video. Often SRT formatted (numbered blocks with HH:MM:SS,mmm --> HH:MM:SS,mmm timing lines).
enhanced_transcript array AI-enhanced, speaker-attributed transcript. An ordered list of segment objects, each with speaker_name (the resolved speaker, such as the linked entity, host, interviewer, analyst, or co-panelist), speaker_id (the CEOInterviews entity_id when that segment is spoken by the linked entity, otherwise null), timestamp (the HH:MM:SS start time of the segment), start_seconds (the same start time as a numeric offset in seconds from the start of the media, null if unparseable), and content (the cleaned, consolidated text of that speaker turn). Consecutive captions from the same speaker are merged into a single segment, so the speaker diarization and the dialogue read cleanly.

Host vs. guest / "exec-only" filtering: segments where speaker_id == entity_id are spoken by the verified tracked executive (the person being interviewed); segments with speaker_id: null are hosts, interviewers, co-panelists, narrators, or ad reads. Filtering to speaker_id == entity_id isolates exactly what the executive said.
quotes array Quote objects extracted from this conversation. Each contains quote_pk, quote_text, source_url, source_title, is_notable, is_controversial, is_financial_policy, source_created_at, timestamp_from_tx, timestamp_seconds (numeric seconds-from-start variant of timestamp_from_tx, null if unparseable), timestamp_end_from_tx / timestamp_end_seconds (offset of the last caption segment in the quote, so the quote spans start..end; null on quotes extracted before September 2026), topics, entities, companies, quote_url, and interview_url (the parent interview's full speaker-attributed transcript page). The same quotes are queryable directly via /api/get_quotes using feed_item_id.
language string Language code of the conversation's transcript when explicitly recorded (e.g. en), otherwise null. Most rows are null today; treat null as unknown, not non-English. The corpus is predominantly English and non-English content is gated/translated at ingest.
word_count integer Approximate spoken-word count of the transcript, so you can sanity-check a row without parsing every segment. Counted from the speaker-attributed enhanced_transcript when present, otherwise from the raw transcript with SRT numbering/timing lines stripped.
categories array Topic and company tags for the conversation, rolled up from its extracted quotes' topics and companies (deduped, normalized, sorted). E.g. ["interest rates", "monetary policy", "Tesla, Inc."]. Empty array = quotes were extracted but carried no tags; null = tagging has not run for this row yet.
is_explicit boolean True when the transcript contains strong profanity (the podcast-industry "explicit" content flag). Computed by a conservative word-boundary regex over the English-enforced enhanced transcript — business vocabulary can't false-positive. null = not yet computed (e.g. no enhanced transcript).
event_type string What kind of event the recording is. One of earnings_call, conference (industry conferences, analyst days, keynotes, fireside chats), podcast, news_appearance (TV and news interviews), or other (commencement speeches, testimony, shareholder meetings, town halls, company-produced content, and anything else). Assigned to every conversation at ingest and backfilled across the archive; null only where no enhanced transcript exists yet. The classifier's 0 to 1 confidence is returned in extra.event_type_confidence. Filter with the event_type parameter.
participants array Episode-level credits: every unique person in the conversation, deduped. Each entry has name (resolved entity name, or the verbatim diarized label such as "Host"/"Interviewer" when unresolved), entity_id (the CEOInterviews id when the person is a tracked executive, otherwise null), is_primary (true for the verified tracked executive this record is about), and is_speaker_in_transcript (whether they appear in enhanced_transcript). Includes co-appearing tracked executives from the same source video (panels/joint interviews) with resolved entity_ids, even when they anchor their own separate feed items. Order: primary first, then co-tracked executives, then remaining speakers by first appearance.
thumbnail_image_url string Main image URL representing this conversation, can be a YouTube thumbnail.
extra object Additional metadata, including quality control fields that explain why this item passed AI quality filters, plus source engagement stats. Common keys: transcript_first_person, transcript_first_person_score, combined_classifier_reason, combined_classifier_score, appearance_date_confidence, appearance_date_granularity, appearance_date_source, duration_secs, view_count, like_count, channel_name, channel_url, channel_subscriber_count. Keys vary by source platform; treat all as optional.
entity_name string Normalized display name of the key entity speaking in the conversation.
institution string Display name of the company or organization the key entity belongs to.
institution_ticker string Stock ticker of the entity's institution if it is publicly listed, otherwise null.
institution_cik string SEC Central Index Key (10 digits, zero-padded) of the entity's institution, or null when it does not file with the SEC. Same value as the company's cik in /api/get_companies (schema 1.4.0).
entity_title string The title (job title and institution) of the key entity that is speaking in the conversation.
is_politician boolean Boolean for is the key entity in this conversation a politician.
is_company_leader boolean Boolean for is the key entity in this conversation a company leader (defined as CEO, President, or Board).
entity_img string URL of the entity's profile picture.
publish_date string ISO 8601 timestamp of when the video/podcast was published on the source platform (e.g., YouTube upload date).
appearance_date_v2 string ISO 8601 date (YYYY-MM-DD) representing when the entity actually appeared or spoke, which may differ from the publish date. For example, a video uploaded on 2025-01-15 may contain an interview recorded on 2025-01-10. This field is AI-inferred from transcript content, video metadata, and web search. Returns null if not determined. Use this for accurate temporal analysis of when statements were made.
server_created_at string ISO 8601 timestamp of when CEOInterviews first scraped and ingested this conversation into our database. This is a server-side bookkeeping timestamp. For source-platform timing use publish_date (when the media was published) and appearance_date_v2 (when the entity actually spoke). Use this field to gauge how recently a record entered our system.
update_time string ISO 8601 timestamp of the last time this record was re-saved on our servers. Independent of server_created_at (first ingest, never changes). It moves whenever the record changes: engagement refreshes (view_count, like_count), transcript edits, speaker re-attribution, and enrichment passes that add new fields to existing records. This makes it the modified-at watermark for incremental syncs: poll with filter_updated_after_dt set to the max update_time you have already stored. Because enrichment passes also move it, treat it as a record-change timestamp, not a pure engagement-metrics refresh time.
share_link string Permalink to the hosted transcript page on ceointerviews.ai for this conversation.
is_deleted_on_source boolean True if the underlying video/podcast has since been removed from the source platform. Deleted items are excluded from feed responses by default; pass include_deleted=true to receive them as soft-delete tombstones (the transcript remains in our archive).
head_image / head_image_type string Display image URL for the item and its kind (video or image). Prefer thumbnail_image_url for thumbnails.
type_str string Internal record type discriminator. Always "Post" for feed items.
description string Source-provided description of the video/podcast when available, otherwise null.
last_seen_id integer Top-level response field (sibling of results, not inside each item). The ID of the last feed item on this page. Pass it as before_feed_item_id on your next request for keyset pagination.
thumbnail_advanced_review_v2, transcript_advanced_review_v2 boolean Quality-gate flags. The thumbnail review confirms the named executive is actually shown on screen, and the transcript review confirms the executive is the one speaking firsthand. Both are true on every feed item, because the feed only returns records that have cleared both the AI pipeline and human QA. They are surfaced so you have an explicit verification marker on each row.
is_speaking_thumbnail_review, is_advanced_evaluated boolean Deprecated. Always null. Kept only so the response shape stays backward compatible.
How to get all Conversations from the DB

Similar to the example above of paginating through all Entities in the DB you can do the same with Conversation objects.

all_convos = []
for page_num in range(1, 100):
    resp = requests.get(
        f"{BASE_URL}/api/get_feed/",
        params={"page_num": page_num, "page_size": 500},
        headers=HEADERS,
    ).json()
    all_convos.extend(resp["results"])
    if not resp["page_has_next"]:
        break

for convo in all_convos[:5]:
    print(f"Title: {convo['item_title']} publish date {convo['publish_date']}")
GET
/api/get_companies/

Search company data by keyword, ticker or SEC CIK. Returns comprehensive company information including all index classifications (S&P 500, NASDAQ, startup status, geographic location, etc.). All parameters are optional. If no filters are provided, returns all companies ordered by number of conversations.

Parameter Type Description
keyword string Optional. Search by company name or ticker. Exact name/ticker matches are ranked first, then partial name matches. If omitted, returns all companies ordered by number of associated conversations. Note: keyword searches return all matches in a single response and pagination is disabled.
ticker string Optional. Exact stock ticker lookup, e.g. CAT, BRK.B. Returns only that company; unknown tickers return 404.
cik string Optional. Exact SEC Central Index Key lookup, with or without leading zeros, e.g. 0000320193 or 320193. Returns only that company; unknown CIKs return 404 and non-numeric values return 400.
is_public_company boolean Optional. Filter by public status. True returns companies in the S&P 500, S&P 1500, NASDAQ 100 or Russell 3000, or listed on NASDAQ; false returns companies not in those sets.
is_snp500 boolean Optional. Filter by S&P 500 membership.
is_nasdaq boolean Optional. Filter by NASDAQ listing.
is_snp1500 boolean Optional. Filter by S&P 1500 membership.
is_nasdaq100 boolean Optional. Filter by NASDAQ 100 membership.
is_ai_startup boolean Optional. Filter for AI startups.
is_top_startup boolean Optional. Filter for top startups.
is_usa_based boolean Optional. Filter for USA-based companies.
is_china_based boolean Optional. Filter for China-based companies.
is_europe_based boolean Optional. Filter for Europe-based companies.
is_russell3000 boolean Optional. Filter by Russell 3000 membership.
page_num integer Optional. Page number for pagination (default: 1)
page_size integer Optional. Number of results per page (default: 10, max: 500).
Simple usage

Look up a company by name, ticker or SEC CIK.

resp = requests.get(
    f"{BASE_URL}/api/get_companies/",
    params={"keyword": "tesla"},
    headers=HEADERS,
).json()
assert resp["results"][0]["ticker"] == "TSLA"
Response Format

Every endpoint returns a JSON object: a top-level schema_version (currently 1.5.0; we bump it whenever the API changes substantially, so pin or log it in your sync), the matching rows under results, plus pagination fields page_has_previous, page_has_next, and page_num. get_feed and get_quotes also include last_seen_id for keyset pagination, and get_quotes adds num_results.

# resp.json() returns a dict:
{
	"results": [
		{
			"ticker": "TSLA",
			"cik": "0001318605",
			"name": "Tesla, Inc.",
			"normalized_name": "Tesla",
			"logo_url": "https://ceointerviews.ai/static/images/company_logos/TSLA.png",
			"company_id": 51,
			"is_snp500": True,
			"is_nasdaq": True,
			"is_snp1500": True,
			"is_nasdaq100": True,
			"is_ai_startup": False,
			"is_top_startup": False,
			"is_usa_based": True,
			"is_china_based": False,
			"is_europe_based": False,
			"is_russell3000": True
		},
		# ... more results here ...
		# ...
	],
	"page_has_previous": False,
	"page_has_next": False,
	"page_num": 1,
}
Response Params
Parameter Type Description
ticker string Stock ticker for the company if it's publicly listed. Private companies, non-corporate institutions, or other entities will not have this value set.
cik string SEC Central Index Key: the 10-digit, zero-padded ID the SEC assigns to every EDGAR filer (e.g. 0001318605 for Tesla). Use it to join our data to SEC filings and other CIK-keyed datasets. null when the company does not file with the SEC, such as private companies and most non-US local listings. We follow the SEC's current mapping, so a spin-off or holding-company reorganization that creates a new registrant updates this value.
name string Official name of the institution or company.
normalized_name string Instead of the official name, such as "Adobe Inc." this field will contain the simplified name, such as "Adobe".
logo_url string Logo URL for the institution or company.
company_id integer Unique ID for this institution or company. Save this ID to use later for fetching conversation data for executives or leaders at this company at /api/get_feed
is_snp500 boolean Whether the company is part of the S&P 500 index.
is_nasdaq boolean Whether the company's shares (or ADRs) are listed on the NASDAQ exchange, per the SEC's exchange data. Covers all NASDAQ listings, not just the NASDAQ 100.
is_snp1500 boolean Whether the company is part of the S&P 1500 index.
is_nasdaq100 boolean Whether the company is currently a NASDAQ 100 constituent.
is_ai_startup boolean Whether the company is classified as an AI startup.
is_top_startup boolean Whether the company is classified as a top startup.
is_usa_based boolean Whether the company is based in the USA.
is_china_based boolean Whether the company is based in China.
is_europe_based boolean Whether the company is based in Europe.
is_russell3000 boolean Whether the company is currently a Russell 3000 constituent.
GET
/api/get_entities/

Entity is a key concept in the CEOInterviews API. It represents a powerful individual, politician, CEO, or company executive. This endpoint returns Entity metadata based on search params.

Search for entities via keyword. Keywords are fuzzy-matched across the entity's name, title, company name, and stock ticker, and you can combine terms in any order. All parameters are optional. If no filters are provided, returns all entities ordered by number of conversations.

id's returned in the response here are important. You will use them to fetch conversation dialogue data later.

Parameter Type Description
keyword string Optional. Fuzzy search across the entity's name, title, company name, and stock ticker. Supports partial names, tickers, and multi-term queries in any order. Not case sensitive. If omitted, returns all entities ordered by number of associated conversations.

Examples: ["Tim Cook", "Elon", "AAPL", "CEO Tesla", "devinder kumar amd", "federal reserve", "coinbase"]
company_id integer Optional. Filter entities by company ID. Get this ID using /api/get_companies.
ticker string Optional. Strict filter by exact stock ticker, e.g. CAT, BRK.B. Returns the executives of that one company, like company_id. Unknown tickers return 404. Use this rather than keyword when you have tickers, since keyword is a fuzzy name search.
gender string Optional. Filter entities by gender. Values: M (Male), F (Female), O (Other). Not case sensitive.
is_company_leader boolean Optional. True returns only company leaders — CEOs, founders, and chairs. False returns everyone else (politicians, hosts, analysts, non-leader executives). Combine with page_size=500 and paginate to pull the full CEO universe.
is_public_company boolean Optional. Filter entities by whether their associated company is public. True returns entities attached to companies in the S&P 500, S&P 1500, NASDAQ 100 or Russell 3000, or listed on NASDAQ; false returns entities not in those sets.
is_snp500 boolean Optional. Filter by associated company's S&P 500 membership.
is_nasdaq boolean Optional. Filter by associated company's NASDAQ listing.
is_snp1500 boolean Optional. Filter by associated company's S&P 1500 membership.
is_nasdaq100 boolean Optional. Filter by associated company's NASDAQ 100 membership.
is_ai_startup boolean Optional. Filter for entities at AI startups.
is_top_startup boolean Optional. Filter for entities at top startups.
is_usa_based boolean Optional. Filter for entities at USA-based companies.
is_china_based boolean Optional. Filter for entities at China-based companies.
is_europe_based boolean Optional. Filter for entities at Europe-based companies.
is_russell3000 boolean Optional. Filter by associated company's Russell 3000 membership.
page_num integer Optional. Page number for pagination (default: 1)
page_size integer Optional. Number of results per page (default: 10, max: 500).
Simple usage

Fetch Donald Trump's entity, or a list of McDonald's C-suite executives. A tiny helper keeps the repeated calls readable.

def get_entities(**params):
    return requests.get(
        f"{BASE_URL}/api/get_entities/", params=params, headers=HEADERS
    ).json()

trump = get_entities(keyword="donald trump")
mcdonalds_csuite_execs = get_entities(keyword="mcdonalds")

This API function returns a list of results. Sometimes you need to narrow down to the precise correct entities.

# Fetch Malaysian politicians, then filter down for the Prime Minister.
malay_politicians = get_entities(keyword="malaysia")["results"]
prime_minister = [e for e in malay_politicians if "prime minister" in e["title"].lower()]

# Get Mark Zuckerberg
meta_resp = get_entities(keyword="meta")
meta_execs = meta_resp["results"]
mark_zuckerberg = [e for e in meta_execs if "zuckerberg" in e["simple_name"].lower()]

# Paginate Meta executives
if meta_resp["page_has_next"]:
    page_2_meta = get_entities(keyword="meta", page_num=2)
Response Params
Parameter Type Description
id integer Unique identifier for the entity.
name string Full name of the entity.
simple_name string Normalized name without titles, suffixes, or credentials.
title string Job title or position of the entity.
institution string Company or organization the entity is associated with.
description string Brief description of the entity.
gender string Gender of the entity (M/F/O) for Male/Female/Other.
is_top_influencer boolean Whether the entity is classified as a top influencer.
is_politician boolean Whether the entity is a politician.
is_company_leader boolean Whether the entity is a company leader (CEO, President, etc.).
profile_pic_url string URL to the entity's profile picture.
linkedin_url string LinkedIn profile URL of the entity when known, otherwise null. Useful as an external join key for matching against your own people directory without fuzzy name matching.
twitter_url string X.com (Twitter) profile URL of the entity when known, otherwise null. Useful as an external join key alongside linkedin_url.
company object Company info if the Entity is associated with a Company:
  • id (integer): Company ID
  • ticker (string): Stock ticker symbol
  • cik (string or null): SEC Central Index Key, 10 digits zero-padded; null when the company does not file with the SEC
  • full_name (string): Full company name
  • logo_url (string): URL to company logo
  • is_snp500 (boolean): Whether company is in S&P 500
  • is_nasdaq (boolean): Whether company is listed on the NASDAQ exchange (any NASDAQ listing, not just the NASDAQ 100)
  • is_snp1500 (boolean): Whether company is in S&P 1500
  • is_nasdaq100 (boolean): Whether company is in NASDAQ 100
  • is_ai_startup (boolean): Whether company is an AI startup
  • is_top_startup (boolean): Whether company is a top startup
  • is_usa_based (boolean): Whether company is based in USA
  • is_china_based (boolean): Whether company is based in China
  • is_europe_based (boolean): Whether company is based in Europe
  • is_russell3000 (boolean): Whether company is in the Russell 3000
Response Format

Every endpoint returns a JSON object: a top-level schema_version (currently 1.5.0; we bump it whenever the API changes substantially, so pin or log it in your sync), the matching rows under results, plus pagination fields page_has_previous, page_has_next, and page_num. get_feed and get_quotes also include last_seen_id for keyset pagination, and get_quotes adds num_results.

# Shape returned by every endpoint (data = resp.json())
{
    "schema_version": "1.5.0", # bumped on substantial API changes
    "results": [...],          # list of matching rows
    "page_has_previous": bool,
    "page_has_next": bool,
    "page_num": int,
    # get_feed and get_quotes also include "last_seen_id" (int)
    # get_quotes also includes "num_results" (int)
}

Example response.

# resp.json() returns a dict:
{
	"results": [
		{
			"id": 120427,
			"name": "David O. Sacks",
			"simple_name": "David Sacks",
			"title": "Founder of Craft Ventures",
			"institution": "Craft Ventures",
			"description": None,
			"gender": "M",
			"is_politician": False,
			"is_company_leader": False,
			"profile_pic_url": "https://ceointerviews.ai/static/images/entity_pfps/120427.png",
			"linkedin_url": "https://www.linkedin.com/in/davidoliversacks/",
			"twitter_url": "https://x.com/DavidSacks",
			"company": {
				"id": 670,
				"ticker": "None-Craft Ventures",
				"cik": None,
				"full_name": "Craft Ventures",
				"logo_url": "/static/images/company_logos/None-Craft Ventures.png",
				"is_snp500": False,
				"is_nasdaq": False,
				"is_snp1500": False,
				"is_nasdaq100": False,
				"is_ai_startup": False,
				"is_top_startup": True,
				"is_usa_based": True,
				"is_china_based": False,
				"is_europe_based": False,
				"is_russell3000": False
			}
		}
		# ... more results here ...
		# ...
	],
	"page_has_previous": False,
	"page_has_next": False,
	"page_num": 1,
}
How to get all Entities from the DB

As a paid API customer you may be interested in saving all our entity data in your server for later use, e.g. to extract transcript data from the entities you care about.

You can do this by removing the keyword param and paginating through the entire db. See the following example code.

all_entities = []
for page_num in range(1, 500):
    resp = requests.get(
        f"{BASE_URL}/api/get_entities/",
        params={"page_num": page_num, "page_size": 100},
        headers=HEADERS,
    ).json()
    all_entities.extend(resp["results"])
    if not resp["page_has_next"]:
        break

# Fetch some example feed items for the first 5 entities
for entity in all_entities[:5]:
    feed = requests.get(
        f"{BASE_URL}/api/get_feed/",
        params={"entity_id": entity["id"]},
        headers=HEADERS,
    ).json()
    print(f"Entity: {entity['name']} has {len(feed['results'])} posts")
GET
/api/get_quotes/

Get notable quotes from entities with various filtering options. This endpoint allows you to access key statements made by executives, politicians, and other influential figures. All parameters are optional. If no filters are provided, returns all quotes ordered by recency.

Parameter Type Description
entity_name string Optional. Search by entity name (e.g. "elon musk", "jerome powell"). Automatically resolves to entity_id internally. Recommended for AI agents.
company_name string Optional. Search by company name or ticker (e.g. "tesla", "TSLA", "JPMorgan"). Automatically resolves to company_id internally. Returns quotes from all entities at this company. Recommended for AI agents.
keyword string Optional. Search quotes by keyword. This searches within the quote text using semantic similarity. Note: keyword searches return the top 50 matches in a single response and pagination is disabled (page_has_next is always false). Narrow with entity, company, or date filters to surface more specific matches.
entity_id integer Optional. Filter quotes by entity ID. Get this ID from /api/get_entities. Alternative to entity_name (takes precedence if both provided).
company_id integer Optional. Filter quotes by company ID. Returns quotes from all entities associated with this company. Get this ID from /api/get_companies. Alternative to company_name (takes precedence if both provided).
ticker string Optional. Strict filter by exact stock ticker, e.g. CAT, BRK.B. Unlike company_name it never falls back to a partial name match; unknown tickers return 404. company_id takes precedence if both provided.
feed_item_id integer Optional. Filter quotes by the feed item it was associated with (podcast/video). Get this ID from /api/get_feed.
filter_before_dt string Optional. Only return quotes from conversations published on or before this date. ISO 8601 format (e.g. 2025-06-01 or 2025-06-01T00:00:00+00:00).
filter_after_dt string Optional. Only return quotes from conversations published on or after this date. ISO 8601 format. Combine with filter_before_dt to query a closed date window.
filter_updated_after_dt string Optional. Only return quotes whose update_time is at or after this instant. ISO 8601 format. Built for incremental syncs: same contract as get_feed. New quotes are extracted in the hours after a conversation is ingested, so a quote can appear days after its conversation's publish_date; watermark on this, not on filter_after_dt.
is_notable boolean Optional. Filter for quotes marked as notable (true/false).
is_controversial boolean Optional. Filter for quotes marked as controversial (true/false).
is_financial_policy boolean Optional. Filter for quotes related to financial policy (true/false).
event_type string Optional. Only return quotes from conversations of these kinds. Comma-separated subset of earnings_call, conference, podcast, news_appearance, other. For example event_type=podcast,conference keeps unscripted executive commentary, and listing the other four excludes earnings calls. Unknown values return 400.
before_quote_id integer Optional. For keyset-style pagination. Only return quotes with IDs less than this value. Use last_seen_id from the previous response.
page_num integer Optional. Page number for pagination (default: 1)
page_size integer Optional. Number of results per page (default: 10, max: 500).
Simple usage
# Get controversial quotes from Elon Musk directly
resp = requests.get(
    f"{BASE_URL}/api/get_quotes/",
    params={"entity_name": "elon musk", "is_controversial": "true"},
    headers=HEADERS,
).json()
quotes = resp["results"]
Response Format

Every endpoint returns a JSON object: a top-level schema_version (currently 1.5.0; we bump it whenever the API changes substantially, so pin or log it in your sync), the matching rows under results, plus pagination fields page_has_previous, page_has_next, and page_num. get_feed and get_quotes also include last_seen_id for keyset pagination, and get_quotes adds num_results.

# resp.json() returns a dict:
{
	"results": [
		{
			"id": 12345,
			"text": "AI is the biggest risk to civilization that I've ever come across.",
			"source_url": "https://www.youtube.com/watch?v=abc123",
			"source_title": "Elon Musk Interview on AI Safety",
			"is_notable": true,
			"is_controversial": true,
			"is_financial_policy": false,
			"topics": ["artificial intelligence", "technology risk", "regulation"],
			"entities": ["OpenAI", "Tesla"],
			"companies": ["Tesla, Inc."],
			"created_at": "2023-05-15T14:32:45+00:00",
			"server_created_at": "2023-05-15T14:32:45+00:00",
			"update_time": "2023-05-15T14:32:45+00:00",
			"timestamp_from_tx": "00:15:23",
			"timestamp_seconds": 923,
			"timestamp_end_from_tx": "00:16:12",
			"timestamp_end_seconds": 972,
			"entity": {
				"id": 5099,
				"name": "Elon Musk",
				"simple_name": "Elon Musk",
				"title": "CEO of Tesla and SpaceX",
				"institution": "Tesla",
				"profile_pic_url": "https://ceointerviews.ai/static/images/entity_pfps/5099.png",
				"is_politician": false,
				"is_company_leader": true,
				"company": {
					"id": 51,
					"ticker": "TSLA",
					"cik": "0001318605",
					"full_name": "Tesla, Inc.",
					"logo_url": "https://ceointerviews.ai/static/images/company_logos/TSLA.png"
				}
			},
			"feed_item": {
				"id": 58827,
				"title": "Elon Musk Interview on AI Safety",
				"source_url": "https://www.youtube.com/watch?v=abc123",
				"source_created_at": "2023-05-15T12:30:00+00:00",
				"server_created_at": "2023-05-16T02:11:09+00:00",
				"thumbnail_url": "https://i.ytimg.com/vi_webp/abc123/maxresdefault.webp",
				"event_type": "podcast"
			}
		},
		# ... more results here ...
		# ...
	],
	"page_has_previous": False,
	"page_has_next": True,
	"page_num": 1,
	"num_results": 10,
	"last_seen_id": 12336,
}
Response Params
Parameter Type Description
id integer Unique identifier for the quote.
text string The actual quote text.
source_url string URL of the source where the quote was found.
source_title string Title of the source content.
is_notable boolean Whether the quote is marked as notable.
is_controversial boolean Whether the quote is marked as controversial.
is_financial_policy boolean Whether the quote is related to financial policy.
topics array List of topics mentioned in the quote.
entities array List of entities mentioned in the quote.
companies array List of companies mentioned in the quote.
created_at string ISO 8601 timestamp when the quote was created in our system.
server_created_at string ISO 8601 timestamp of when this quote was first scraped/ingested into our database server-side. Currently identical to created_at; provided under this name for consistency with the server_created_at field on feed items. The nested feed_item object also carries its own server_created_at (the parent conversation's ingest time).
update_time string ISO 8601 timestamp of the last time this quote record was re-saved on our servers (schema 1.3.0). Equals created_at for quotes that have never been modified. Filterable via filter_updated_after_dt.
timestamp_from_tx string Timestamp within the source content where the quote appears (HH:MM:SS offset into the video/podcast). May be null when the position could not be located.
timestamp_seconds integer The same offset as timestamp_from_tx expressed as numeric seconds from the start of the media, so no clock-string parsing is needed. null when timestamp_from_tx is null or unparseable.
timestamp_end_from_tx string HH:MM:SS offset of the last caption segment in the quote, so the quote spans timestamp_from_tx..timestamp_end_from_tx in the media and in the enhanced transcript. Use it to slice the exact transcript window a quote came from. null on quotes extracted before September 2026.
timestamp_end_seconds integer The same end offset as numeric seconds from the start of the media. null when timestamp_end_from_tx is null or unparseable.
last_seen_id integer Top-level response field (sibling of results, not inside each quote). The ID of the last quote on this page. Pass it as before_quote_id on your next request for keyset pagination.
entity object Information about the entity who made the quote.
feed_item object Information about the feed item (podcast/video) where the quote was found: id, title, source_url, source_created_at, server_created_at, thumbnail_url, and event_type (the kind of event the parent conversation is; filterable with the event_type parameter).
How to get all Quotes from the DB

As a paid API customer you may be interested in retrieving all quotes from our database for your own analysis or application. You can do this by paginating through all quotes without specifying any filters.

all_quotes = []
for page_num in range(1, 500):
    resp = requests.get(
        f"{BASE_URL}/api/get_quotes/",
        params={"page_num": page_num, "page_size": 100},
        headers=HEADERS,
    ).json()
    all_quotes.extend(resp["results"])
    if not resp["page_has_next"]:
        break
GET
/api/get_substack_posts/

Returns Substack newsletter articles from our curated registry of the most market-relevant finance and tech publications, with AI-extracted, ticker-mapped company and executive mentions. All parameters are optional. If no filters are provided, returns all articles ordered by recency. Substack data lives on this dedicated endpoint only: /api/get_feed/ and /api/get_quotes/ continue to return verified interview transcript data exclusively, so existing integrations are unaffected.

Parameter Type Description
company_name string Optional. Company name or ticker (e.g. "nvidia", "NVDA", "JPMorgan"). Returns articles that substantively cover the company (via AI mention extraction) or are anchored to one of its executives.
company_id integer Optional. Same as company_name, by ID from /api/get_companies. Takes precedence if both provided.
ticker string Optional. Strict filter by exact stock ticker, e.g. NVDA, BRK.B. Returns the same articles as company_name for that company, but never falls back to a partial name match; unknown tickers return 404. company_id takes precedence if both provided.
entity_name string Optional. Executive name (e.g. "jensen huang"). Returns articles written by, about, or substantively mentioning the executive.
entity_id integer Optional. Same as entity_name, by ID from /api/get_entities. Takes precedence if both provided.
publication string Optional. Filter by publication name, partial match, case-insensitive (e.g. "SemiAnalysis", "bear cave").
author string Optional. Filter by newsletter author name, partial match, case-insensitive (e.g. "dalio").
keyword string Optional. Full-text search over article titles and body text (websearch syntax: tariffs "supply chain" -china). Results stay ordered by recency. Works standalone or combined with any other filter.
filter_before_dt string Optional. Only return articles published on or before this date. ISO 8601 format.
filter_after_dt string Optional. Only return articles published on or after this date. ISO 8601 format. Combine with filter_before_dt for a closed window.
filter_updated_after_dt string Optional. Only return articles whose update_time is at or after this instant. ISO 8601 format. Built for incremental syncs: watermark on the max update_time you've seen, then poll with this parameter to pick up new articles and re-saved ones (for example, when mention extraction adds ticker and executive links after ingest) without re-downloading the archive.
language string Optional. Language code as reported by Substack (e.g. en, en-gb). Exact match, case-insensitive. The corpus is English-only: articles Substack reports as non-English are not ingested.
min_word_count integer Optional. Only return articles whose stored text has at least this many words. Paywalled articles store the publisher's preview, so their word_count is the preview length. min_word_count=300 drops notes, announcements and stubs.
exclude_preview boolean Optional. true to drop paywalled articles (is_preview_only), for which only the preview text is available.
primary_only boolean Optional. With an entity or company filter: only return articles where that executive/company is the primary subject (a deep dive, earnings review, thesis or profile) rather than one of several topics. Roundups and link digests never carry primary mentions.
tier string Optional. Comma-separated publication tiers to keep, for example tier=1,2,3. Every publication in the registry has a tier from 1 to 5. Tier 1 is the core set, including the letters written by tracked executives and investors. Tiers 4 and 5 are the long tail. We check tiers 1 to 3 for new articles every day, tier 4 every 3 days and tier 5 every 7 days. tier=1,2,3 returns about a third of all articles. Any value outside 1 to 5 returns a 400.
page_num integer Optional. Page number for pagination (default: 1)
page_size integer Optional. Number of results per page (default: 10, max: 500).
before_feed_item_id integer Optional. For keyset-style pagination. Only return articles with IDs less than this value. Use last_seen_id from the previous response.
Simple usage

Everything the newsletter ecosystem wrote about Tesla in the last week:

from datetime import date, timedelta

resp = requests.get(
    f"{BASE_URL}/api/get_substack_posts/",
    params={
        "company_name": "TSLA",
        "filter_after_dt": (date.today() - timedelta(days=7)).isoformat(),
        "page_size": 50,
    },
    headers=HEADERS,
).json()
for a in resp["results"]:
    print(a["publication"]["name"], "|", a["item_title"])

Every article Ray Dalio has published, with full text:

resp = requests.get(
    f"{BASE_URL}/api/get_substack_posts/",
    params={"author": "dalio", "page_size": 25},
    headers=HEADERS,
).json()
for a in resp["results"]:
    print(a["item_title"], f'({a["word_count"]} words)')
    print(a["article_text"][:400])
Response Format

Same envelope as every other endpoint: rows under results plus page_has_previous, page_has_next, page_num, num_results, and last_seen_id for keyset pagination.

# resp.json() returns a dict:
{
	"results": [
		{
			"feed_item_id": 1230617,
			"item_title": "Cerebras's Next Generation CS-4: Fast Just Got Faster",
			"description": "Wafer-scale inference economics, and what it means for the merchant GPU market.",
			"article_text": "Cerebras announced the CS-4 this morning, and the headline number...",
			"is_preview_only": False,
			"word_count": 284,
			"reported_word_count": 284,
			"post_type": "newsletter",
			"language": "en",
			"source_url": "https://newsletter.semianalysis.com/p/cerebras-cs4",
			"publish_date": "2026-08-18T14:02:11+00:00",
			"server_created_at": "2026-08-19T05:41:22+00:00",
			"update_time": "2026-08-19T05:44:07+00:00",
			"like_count": 412,
			"restack_count": 38,
			"cover_image_url": "https://substackcdn.com/image/fetch/....jpg",
			"publication": {
				"name": "SemiAnalysis",
				"url": "https://newsletter.semianalysis.com",
				"author": "Dylan Patel",
				"tier": 1
			},
			"mentions": [
				{"name": "Cerebras", "kind": "company", "ticker": None, "org": None, "centrality": "primary", "company_id": 3417, "entity_id": None},
				{"name": "Nvidia", "kind": "company", "ticker": "NVDA", "org": None, "centrality": "secondary", "company_id": 43, "entity_id": None},
				{"name": "Jensen Huang", "kind": "executive", "ticker": None, "org": "Nvidia", "centrality": "secondary", "company_id": None, "entity_id": 64}
			],
			"quotes": [
				{
					"quote_pk": 991230,
					"quote_text": "The CS-4's SRAM-first architecture sidesteps the HBM supply constraint that has gated every GPU roadmap since 2024.",
					"is_notable": True,
					"entities": [],
					"companies": ["Cerebras"],
					"linked_company_id": 3417,
					"linked_entity_id": None,
					"centrality": "primary"
				}
			],
			"entity": None,
			"entity_role": None
		},
		# ... more results ...
	],
	"page_has_previous": False,
	"page_has_next": True,
	"page_num": 1,
	"num_results": 10,
	"last_seen_id": 1230617,
}
Response Params
Parameter Type Description
feed_item_id integer Unique ID for this article. Shares the ID space with get_feed feed items.
item_title string Article headline.
description string Article subtitle and/or publisher description, when available.
article_text string Cleaned plain-text article body. Complete for free posts; for paywalled posts this is the publisher's preview (see is_preview_only).
is_preview_only boolean True when the article is behind the publication's paywall and article_text contains only the public preview.
word_count integer Word count of article_text.
language string Publication language code (e.g. en, de), when known.
source_url string Canonical URL of the article on Substack.
publish_date string ISO 8601 timestamp of when the article was published. For articles, the publish date IS the statement date; there is no separate appearance date like video content.
server_created_at / update_time string ISO 8601 timestamps of first ingest and last re-save on our servers, same semantics as get_feed.
like_count / restack_count integer Substack engagement counts (reactions and restacks) captured at ingest time.
cover_image_url string Article cover image, when the publisher set one.
publication object The newsletter this article belongs to: name, url, author (the publication's primary writer), and tier, an integer from 1 (the core set) to 5 (the deep long tail). Filter on it with the tier parameter.
mentions array AI-extracted companies and executives the article substantively covers. Each mention has name, kind (company or executive), ticker, org, centrality (primary = the article is about it, secondary = substantively discussed), and, when resolved against our database, company_id / entity_id join keys. Unresolved mentions keep name and ticker with null IDs.
quotes array Verbatim key passages about linked companies/executives, verified word-for-word against the article body. Each has quote_pk, quote_text, is_notable, entities/companies name lists, linked_company_id/linked_entity_id join keys, and centrality.
entity object The tracked executive this article is anchored to, or null. Populated when the newsletter is written by a tracked executive, or when exactly one tracked executive is the article's unambiguous primary subject. Same shape as entity objects elsewhere in the API, with a nested company when applicable.
entity_role string "author" when the anchored executive wrote the article (e.g. Ray Dalio's posts), "subject" when the article is about them, null when no entity is anchored.

cURL and other HTTP clients

The API is language-agnostic. Send your key in the X-API-Key header and pass filters as query params. The examples below use curl; swap in your language's HTTP client the same way.

# Notable quotes about artificial intelligence
curl -G "https://ceointerviews.ai/api/get_quotes/" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "keyword=artificial intelligence" \
  --data-urlencode "is_notable=true" \
  --data-urlencode "page_size=25"

Fetch Elon Musk's conversation feed directly:

curl -G "https://ceointerviews.ai/api/get_feed/" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "entity_name=elon musk" \
  --data-urlencode "page_size=25"

Fetch notable quotes from Elon Musk directly:

curl -G "https://ceointerviews.ai/api/get_quotes/" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "entity_name=elon musk" \
  --data-urlencode "is_notable=true" \
  --data-urlencode "page_size=25"

Or if you need entity metadata first, fetch entity data for Elon Musk:

curl -G "https://ceointerviews.ai/api/get_entities/" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "keyword=elon musk"

Fetch Substack newsletter articles covering Nvidia:

curl -G "https://ceointerviews.ai/api/get_substack_posts/" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "company_name=NVDA" \
  --data-urlencode "page_size=25"

Rate Limits

Free Tier
  • • There is no free tier available, API access is for paid customers only.
API Tier
  • • 1000 requests per minute
  • • 30,000 transcripts (get_feed rows) per month per key, resetting on the day of the month the key was created
  • • Comprehensive access to our DB. We offer API users an endpoint to paginate through all Entity and conversation dialogue data.
  • • Get our API access now at the API Settings Page.
Custom Tier: please schedule a call
  • • Unlimited requests
  • • Custom rate limits based on needs
  • • The CEOInterviews team will manually deliver the data you need to your application or servers.
  • • Discuss pricing in a video call with our founder click here.

Error Handling

The API uses standard HTTP response codes:

  • • 200: Success
  • • 400: Bad Request
  • • 401: Unauthorized
  • • 403: Forbidden (Rate limit exceeded)
  • • 404: Not Found
  • • 500: Internal Server Error

Get API access now