Authentication
All API requests require an API key passed via the X-API-Key header or api_key query parameter.
X-API-Key: YOUR_API_KEY
- Subscribe to a plan on earningscalls.dev
- Your API key is shown after checkout and sent to your email
- Log in to your Dashboard to view or regenerate your key
Also available via RapidAPI with RapidAPI headers.
Base URL
https://earningscalls.dev/api/v1
All endpoints are prefixed with /api/v1. Responses are JSON with consistent pagination.
RapidAPI users: use https://earnings-call-transcripts1.p.rapidapi.com/api/v1 with RapidAPI headers instead.
Rate Limits
Managing Your Subscription
How you change tier or cancel depends on where you signed up:
If you subscribed on earningscalls.dev
- Open your Dashboard to view your API key, regenerate it, see your usage, or cancel your plan.
- Billing runs through Paddle. Invoices arrive automatically with every payment and are issued in the name of Dreaverr Digital Solutions LLP (the legal entity behind earningscalls.dev). Update your business name, address or VAT/tax ID from the "Update billing details" link inside any Paddle email.
- To switch tier (Pro ↔ Ultra ↔ Enterprise): cancel the current plan from your Dashboard first, then subscribe to the new tier on the pricing section. The new tier becomes active immediately; the old plan keeps running in parallel until the end of its billing period — no double charge, just a short overlap.
If you subscribed on RapidAPI
- Sign in to your RapidAPI account and open the API page.
- Use RapidAPI's "Subscribe" or "Switch Plan" button to change tier, or "Cancel Subscription" to end it. Plan changes typically take effect at the next billing cycle.
- Billing and invoices come from RapidAPI directly — not from us. If you need a different billing address or tax ID, update it in your RapidAPI account settings.
Stuck? Email [email protected] with your invoice number or RapidAPI username and we'll sort it out.
Error Handling
The API uses standard HTTP status codes. Error responses include a message:
{
"error": "Forbidden",
"message": "Full transcripts require a Pro or Enterprise plan"
}
200 Success400 Bad Request - Invalid parameters401 Unauthorized - Missing or invalid API key403 Forbidden - Insufficient tier for this endpoint404 Not Found - Resource doesn't exist429 Rate Limited - Daily quota exceeded500 Server Error - Something went wrong on our endRecipes
Practical patterns for common workflows. Pick the one closest to your use case — they all use the same authentication and base URL from the Getting Started sections above.
Search Syntax
The q parameter accepts Google-style operators. PostgreSQL handles stemming automatically, so guidance matches guidance, guidances, guided.
# Implicit AND between words (both must appear)
GET /api/v1/search?q=agentic+AI
# Exact phrase — words must appear in this order
GET /api/v1/search?q=%22raised+guidance%22
# Boolean OR
GET /api/v1/search?q=agentic+OR+autonomous
# Negation (exclude word)
GET /api/v1/search?q=agentic+-human
# Combine — phrase + negation
GET /api/v1/search?q=%22raised+guidance%22+-macro
Get the latest call for a ticker
Two endpoints depending on what you need. /companies/ticker/:ticker/latest returns just the most recent call metadata. /companies/ticker/:ticker returns the full call history.
curl "https://earningscalls.dev/api/v1/companies/ticker/NVDA/latest" \
-H "X-API-Key: $EARNINGSCALLS_API_KEY"
import requests, os
H = {"X-API-Key": os.environ["EARNINGSCALLS_API_KEY"]}
r = requests.get(
"https://earningscalls.dev/api/v1/companies/ticker/NVDA",
headers=H,
)
data = r.json()["data"]
print(f"{data['company_name']} — {len(data['earnings_calls'])} calls available")
for call in data["earnings_calls"][:5]:
print(f" {call['event_date_time'][:10]} {call['transcript_title']}")
Find what a CEO / CFO / analyst said
The type=speakers + speaker_type filters return only segments spoken by a specific role across the corpus. Combine with ticker to scope to one company.
GET /api/v1/search
?q=%22raised+guidance%22
&type=speakers
&speaker_type=Executives
&ticker=NVDA
&limit=20
Valid speaker_type values: Executives, Analysts, Operator, Attendees, Shareholders. Partial-match, so Exec also works.
Cross-company aggregate — how many of [N tickers] mentioned X
The /search/by_ticker endpoint runs one SQL query that groups results per ticker. Pass a comma-separated tickers list to scope to a known universe (Fortune 500, S&P 500, Mag 7).
GET /api/v1/search/by_ticker
?q=agentic+AI
&tickers=AAPL,MSFT,NVDA,GOOGL,META,AMZN,TSLA,JPM,V,...
&date_from=2026-01-01
&date_to=2026-04-30
&limit=500
# response
{
"tickers_scoped": 500,
"tickers_with_mentions": 184,
"total_calls_matched": 192,
"results": [
{ "ticker": "NOW", "company_name": "ServiceNow", "sector": "Technology",
"calls_matched": 1, "last_match_date": "2026-04-23",
"earnings_ids": ["..."] },
...
]
}
Returns up to 500 tickers ranked by calls_matched. One request instead of 500 — built for cross-sectional NLP analyses.
Incremental sync (cursor-based polling)
For daily ETL jobs that pick up new calls without duplicates. The /transcripts/recent endpoint returns a next_after_id cursor — pass it back in subsequent requests.
import requests, json, pathlib
STATE = pathlib.Path("./.last_id.json")
H = {"X-API-Key": os.environ["EARNINGSCALLS_API_KEY"]}
# Load last seen cursor
last = json.loads(STATE.read_text()) if STATE.exists() else {}
after_id = last.get("after_id", 0)
while True:
r = requests.get(
"https://earningscalls.dev/api/v1/transcripts/recent",
params={"after_id": after_id, "limit": 100},
headers=H,
).json()
for call in r["data"]:
process(call) # → push to your DB / vector store / queue
if not r["pagination"]["has_more"]:
break
after_id = r["pagination"]["next_after_id"]
STATE.write_text(json.dumps({"after_id": after_id}))
Idempotent — safe to re-run. The cursor advances only on successful pages, so a crash mid-sync resumes from the right place.
Compare a company's last N quarters
Use get_company_info's earnings_calls array (sorted newest first) to get the last N call IDs, then fetch summaries in parallel.
import requests, os
from concurrent.futures import ThreadPoolExecutor
H = {"X-API-Key": os.environ["EARNINGSCALLS_API_KEY"]}
BASE = "https://earningscalls.dev/api/v1"
# 1. Get all calls for ticker (sorted desc)
calls = requests.get(f"{BASE}/companies/ticker/NVDA", headers=H).json()
last4 = calls["data"]["earnings_calls"][:4]
# 2. Fetch summaries in parallel
def summary(call):
r = requests.get(f"{BASE}/transcripts/{call['id']}/summary", headers=H)
return r.json()
with ThreadPoolExecutor(max_workers=4) as ex:
summaries = list(ex.map(summary, last4))
for c, s in zip(last4, summaries):
print(f"\n=== {c['event_date_time'][:10]} ===")
print(s.get("data", {}).get("summary", "")[:300])
RAG ingest — speaker-segmented chunks
Speaker segments map 1:1 to embedding chunks. No splitting heuristics needed. The pattern below ingests 100 newest calls — repeat with cursor-based polling for ongoing sync.
import requests, os
from openai import OpenAI
H = {"X-API-Key": os.environ["EARNINGSCALLS_API_KEY"]}
BASE = "https://earningscalls.dev/api/v1"
client = OpenAI()
calls = requests.get(f"{BASE}/transcripts/recent?limit=100", headers=H).json()["data"]
for call in calls:
segs = requests.get(
f"{BASE}/speakers/{call['earnings_call_id']}",
headers=H,
).json()["data"]
for seg in segs:
emb = client.embeddings.create(
model="text-embedding-3-small",
input=seg["text_content"],
).data[0].embedding
upsert_to_vector_db(
id=f"{call['earnings_call_id']}-{seg['component_order']}",
vector=emb,
metadata={
"ticker": call["company_ticker"],
"company": call["company_name"],
"date": call["event_date_time"],
"speaker": seg["speaker_name"],
"role": seg["speaker_type"], # Executives / Analysts / Operator
"sector": call["sector"],
},
text=seg["text_content"],
)
Connect Claude Desktop via MCP
Skip writing API client code entirely — connect via our MCP server and ask Claude in natural language. Generate a personal connector URL from your dashboard, then paste into claude_desktop_config.json:
{
"mcpServers": {
"earningscalls": {
"url": "https://earningscalls.dev/u/mct_xxx_your_token_xxx/mcp"
}
}
}
13 tools available: search_transcripts, count_mentions_by_ticker, get_latest_call, get_speakers, get_call_summary, list_earnings, and 7 more. Full setup guide →