Scenario
Earnings announcements create predictable attention spikes — analysts, investors, and media focus on specific companies and sectors on known dates. This job pulls the upcoming earnings calendar, identifies companies relevant to your audience, then generates a content plan timed to each earnings window: pre-earnings thought pieces, real-time commentary angles, and post-earnings analysis frameworks. Flow: Alpha VantageGET ?function=EARNINGS_CALENDAR → Filter relevant companies → Mavera POST /mave/chat + POST /generations → Earnings-timed content plan
Code
import os, requests, time, csv, io
AV_KEY = os.environ["ALPHA_VANTAGE_KEY"]
AV_BASE = "https://www.alphavantage.co/query"
MV = os.environ["MAVERA_API_KEY"]
MV_BASE = "https://app.mavera.io/api/v1"
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
AUDIENCE_SECTORS = ["Technology", "Communication Services", "Consumer Discretionary"]
BRAND = "B2B marketing platform. Audience: Marketing leaders at enterprise companies. Tone: analytical, forward-looking."
# 1. Fetch earnings calendar (returns CSV)
r = requests.get(AV_BASE, params={
"function": "EARNINGS_CALENDAR", "horizon": "3month", "apikey": AV_KEY,
})
r.raise_for_status()
reader = csv.DictReader(io.StringIO(r.text))
all_earnings = [row for row in reader]
print(f"Total earnings events: {len(all_earnings)}")
# 2. Filter to relevant companies
relevant = [e for e in all_earnings
if any(s.lower() in (e.get("name","") + e.get("symbol","")).lower() for s in ["AAPL","MSFT","GOOGL","META","AMZN","SHOP","HBS","CRM","ADBE","TWLO"])
or float(e.get("estimate","0") or "0") > 1.0]
relevant.sort(key=lambda x: x.get("reportDate",""))
print(f"Relevant earnings: {len(relevant)}")
# 3. Build earnings timeline
timeline = "\n".join(
f"- {e.get('reportDate','')} | {e.get('symbol','')} ({e.get('name','')}) | "
f"Est EPS: ${e.get('estimate','N/A')} | Fiscal: {e.get('fiscalDateEnding','')}"
for e in relevant[:20]
)
# 4. Mave content planning
plan = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
"message": f"Content strategist specializing in earnings-cycle timing.\n\n"
f"BRAND: {BRAND}\n\n"
f"UPCOMING EARNINGS:\n{timeline}\n\n"
"For the top 8 most impactful earnings events, create a content timing plan:\n\n"
"PRE-EARNINGS (3-5 days before):\n- Thought piece angle that positions us as analysts\n"
"EARNINGS DAY:\n- Real-time commentary template (LinkedIn post format)\n"
"POST-EARNINGS (1-2 days after):\n- Analysis framework content piece\n\n"
"Include: publish date, format, headline, key hook, why our audience cares."
}).json()
print(f"\n{plan.get('content', '')[:2000]}")
# 5. Generate first content piece
if relevant:
first = relevant[0]
gen = requests.post(f"{MV_BASE}/generations", headers=MV_H, json={
"prompt": f"Write a pre-earnings thought piece (600 words) for marketing leaders.\n\n"
f"COMPANY: {first.get('name','')} ({first.get('symbol','')})\n"
f"REPORT DATE: {first.get('reportDate','')}\n"
f"EPS ESTIMATE: ${first.get('estimate','N/A')}\n"
f"BRAND: {BRAND}\n\n"
"Angle: What this company's earnings signal about marketing technology spend.\n"
"Include: What to watch, implications for marketing budgets, our unique take.\n"
"Tone: analytical, not financial advice. End with a question for engagement.",
}).json()
print(f"\n{'='*60}\nPRE-EARNINGS PIECE: {first.get('symbol','')}\n{'='*60}")
print(gen.get("output", gen.get("content", ""))[:1000])
const AV_KEY = process.env.ALPHA_VANTAGE_KEY;
const AV_BASE = "https://www.alphavantage.co/query";
const MV = process.env.MAVERA_API_KEY;
const MV_BASE = "https://app.mavera.io/api/v1";
const MV_H = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };
const BRAND = "B2B marketing platform. Audience: Marketing leaders. Tone: analytical, forward-looking.";
// 1. Earnings calendar (CSV)
const csvText = await (await fetch(
`${AV_BASE}?function=EARNINGS_CALENDAR&horizon=3month&apikey=${AV_KEY}`)).text();
const lines = csvText.trim().split("\n");
const headers = lines[0].split(",");
const allEarnings = lines.slice(1).map(line => {
const vals = line.split(",");
return Object.fromEntries(headers.map((h, i) => [h, vals[i] || ""]));
});
console.log(`Total earnings events: ${allEarnings.length}`);
// 2. Filter relevant
const watchlist = ["AAPL","MSFT","GOOGL","META","AMZN","SHOP","CRM","ADBE","TWLO"];
const relevant = allEarnings
.filter(e => watchlist.some(s => (e.symbol||"").includes(s)) || parseFloat(e.estimate||"0") > 1.0)
.sort((a, b) => (a.reportDate||"").localeCompare(b.reportDate||""));
console.log(`Relevant earnings: ${relevant.length}`);
// 3. Timeline
const timeline = relevant.slice(0, 20).map(e =>
`- ${e.reportDate} | ${e.symbol} (${e.name}) | Est: $${e.estimate || "N/A"}`).join("\n");
// 4. Content plan
const plan = await fetch(`${MV_BASE}/mave/chat`, { method: "POST", headers: MV_H,
body: JSON.stringify({ message: `Earnings-cycle content strategist.\n\nBRAND: ${BRAND}\n\nEARNINGS:\n${timeline}\n\nTop 8 events: PRE (thought piece), DAY (LinkedIn template), POST (analysis). Include date, format, headline, hook.` }),
}).then(r => r.json());
console.log((plan.content || "").slice(0, 2000));
// 5. Generate first piece
if (relevant.length) {
const first = relevant[0];
const gen = await fetch(`${MV_BASE}/generations`, { method: "POST", headers: MV_H,
body: JSON.stringify({ prompt: `Pre-earnings thought piece (600 words) for marketing leaders.\n\nCOMPANY: ${first.name} (${first.symbol})\nDATE: ${first.reportDate}\nEST: $${first.estimate||"N/A"}\n\nAngle: What earnings signal about martech spend.\nTone: analytical, not financial advice.` }),
}).then(r => r.json());
console.log(`\n${"=".repeat(60)}\nPRE-EARNINGS: ${first.symbol}`);
console.log((gen.output || gen.content || "").slice(0, 1000));
}
Example Output
Total earnings events: 2,847
Relevant earnings: 23
1. AAPL (2026-04-24) — PRE-EARNINGS PIECE:
"What Apple's Q2 Tells Us About the Future of Marketing Spend"
Format: Blog (1,500 words) | Publish: Apr 21
Hook: Services revenue growth rate = proxy for digital ad spend health
2. META (2026-04-30) — EARNINGS DAY:
"Meta Earnings Live: 3 Numbers Marketing Leaders Should Watch"
Format: LinkedIn post | Publish: Apr 30 4pm ET
Hook: ARPU trend, Reels monetization, AI ad targeting changes
PRE-EARNINGS PIECE: AAPL
============================================================
# What Apple's Q2 Earnings Tell Us About Marketing Technology Spend
Every quarter, Apple's earnings call contains a signal most marketers
miss: the Services revenue growth rate. At $23.1B last quarter (+11%
YoY), Services — which includes App Store, iCloud, Apple TV+, and
Search Ads — is now Apple's second-largest segment...
Error Handling
CSV parsing
CSV parsing
Earnings calendar returns CSV, not JSON. The code parses it with
csv.DictReader (Python) or manual split (JS). Handle empty rows and missing fields.Rate-limit notes
Rate-limit notes
Alpha Vantage returns HTTP 200 with a
"Note" field when rate-limited. Check for "Note" in response before parsing data.Date accuracy
Date accuracy
Earnings dates can shift. Re-fetch weekly. Some dates show as estimated — filter on
reportDate presence.