Building a Morning Briefing Agent with the News Search API

Sarah ChoyPublié le 2 mai 20268 min de lecture
Traduction pas encore disponible. Affichage de la version anglaise.
Building a Morning Briefing Agent with the News Search API

Every founder, PM, and analyst wants the same thing at 8am: a clean digest of what changed overnight. With a News Search API, an LLM, and an HTTP-cron platform, you can ship one in an afternoon.

L'essentiel

  • Architecture: cron → News Search → URL Extract for promising stories → LLM summary → Slack/email post.
  • Tune freshness with <code>start_date</code> = today − 1; tune locale with <code>country_code</code>.
  • Chunk briefings by topic with parallel News Search queries; the LLM merges and de-duplicates.
  • Total cost is ~15 credits per topic per day, plus LLM tokens. A 5-topic briefing is &lt; $0.10/day at list price.

The shape of a useful briefing

A morning briefing agent should answer one question: \"what changed overnight that I need to know about?\" The bar is harder than it sounds. A dump of headlines fails — it's the same as RSS and gets muted within a week. The output that survives is a 5-bullet digest with links, organised by topic, in the user's voice.

That decomposes into a small pipeline:

  • Fetch recent news across N topics — News Search API.
  • Extract the body of any link the model wants to quote — URL Extract API.
  • Summarise + cluster with an LLM — your model of choice.
  • Post to Slack / email / Notion — your existing comms channel.
  • Schedule with a cron — Vercel Cron, GitHub Actions, n8n, etc.

Step 1: Pick your topics

Keep it to 3–6 topics. Briefings with 12 topics are scrolled past. Examples:

  • For a B2B SaaS founder: \"AI funding rounds\", \"OpenAI / Anthropic news\", \"competitor moves\".
  • For a financial analyst: \"FOMC and Treasury\", \"semiconductor supply chain\", \"specific tickers\".
  • For a healthcare PM: \"FDA approvals\", \"clinical-trial readouts\", \"reimbursement changes\".

Step 2: Fetch the raw signal

Run one News Search call per topic in parallel. Use start_date to cap freshness:

from datetime import date, timedelta
import asyncio, aiohttp

KEY = "pk_yourkey"
TOPICS = [
    "AI agent infrastructure funding",
    "OpenAI Anthropic Google new releases",
    "RAG and LLM tool calling research",
]

async def fetch_topic(session, q):
    yesterday = (date.today() - timedelta(days=1)).isoformat()
    async with session.post(
        "https://www.apipick.com/api/search/news",
        headers={"x-api-key": KEY},
        json={"query": q, "start_date": yesterday},
    ) as r:
        return q, await r.json()

async def fetch_all():
    async with aiohttp.ClientSession() as s:
        return await asyncio.gather(*[fetch_topic(s, q) for q in TOPICS])

Each call returns up to 5 ranked headlines (max 10 with num_results). For a 3-topic briefing that's 3 × 15 = 45 credits per run. At the $5 / 5,000-credits rate, $0.045/day. Daily cost is dominated by the LLM, not the news API.

Step 3: Selectively extract bodies

You don't need the full content of every story — just the ones the model wants to quote in detail. A simple heuristic: extract the top 2 stories per topic. With API Pick that's a single batch call:

import requests

urls = [r["url"] for topic, payload in results for r in payload["results"][:2]]

extracted = requests.post(
    "https://www.apipick.com/api/extract",
    headers={"x-api-key": KEY},
    json={"urls": urls, "extract_effort": "auto"},
).json()

At 2 credits per URL, the extract step adds ~12 credits/day for a 3-topic briefing.

Step 4: The summariser prompt

The prompt is where the briefing's voice lives. A starter:

You are an assistant that writes a morning briefing in <Sarah's> voice:
direct, no fluff, no marketing language.

Input: a JSON list of {topic, headlines, extracted_bodies}.

Output rules:
- 1 short paragraph per topic, max 60 words.
- Each paragraph ends with up to 3 inline source links.
- If a topic has fewer than 2 substantive stories overnight, omit it.
- If the entire briefing has fewer than 2 substantive topics, output the
  literal token SKIP and nothing else.
- Never editorialise. Quote facts and figures verbatim from the sources.

Output format: Slack-flavoured markdown.

The \"SKIP if low-signal\" instruction is the single highest-leverage rule. It's why your briefing won't get muted.

Step 5: Post and schedule

For a Python cron, the entire script is < 80 lines. The Slack post:

if briefing.strip() == "SKIP":
    return
requests.post(
    SLACK_WEBHOOK_URL,
    json={"text": briefing, "username": "Morning Briefing", "icon_emoji": ":sunrise:"},
)

Schedule with Vercel Cron (in vercel.json), GitHub Actions, AWS EventBridge, or n8n. Run at 7:45am in your timezone — the goal is for it to be waiting when you sit down at 8.

Doing it in n8n if you prefer no-code

  • Schedule trigger — daily, 7:45 user-tz.
  • HTTP Request nodes (one per topic), POST /api/search/news with start_date from yesterday.
  • Merge node combines the topic results.
  • HTTP Request node calls /api/extract with top URLs.
  • OpenAI / Anthropic node runs the summariser prompt.
  • If node checks the output isn't SKIP.
  • Slack node posts the briefing.

What to watch for in production

  • Topic drift. \"AI agents\" is too broad after 6 months — the API's index grows; your briefing stays specific. Tighten queries quarterly.
  • Repetition across days. Pass the prior day's URLs to the model with \"don't re-cover stories from this list\" if the same story keeps appearing.
  • Quiet weekends. The SKIP rule already handles this; just don't pin your daily check-in habit to the briefing.

Iterate, don't ship-and-forget

Read the briefing every morning for a week. Note where the model lied, miscategorised, or missed something. Update the prompt. After a week of iteration the briefing becomes a habit — and you've built a working agent with about 80 lines of code and three API calls.

Questions fréquentes

Why not just use Google News or an RSS aggregator?

Both work — and both leave you doing the boring part: clustering, deduplicating, summarising, and writing the actual briefing. An agent does that part with an LLM. RSS gives you headlines; an agent gives you a paragraph that says what matters and links to sources.

How fresh is the News Search API?

The API indexes major outlets in near-real-time. For an 8am briefing covering the prior 24 hours, set start_date to yesterday. For breaking-news bots that run hourly, set start_date to today and re-run the agent with deduplication against your last run.

What if the briefing has nothing new to say?

Build that into the prompt: 'If fewer than 3 substantive stories changed overnight, return SKIP.' Your cron job should respect SKIP and not post a low-signal briefing. Briefing-fatigue is the fastest way to get a Slack channel muted.

Can I run this without n8n?

Yes. The same flow runs as a 30-line Python script on a cron — see the example below. n8n is convenient for visual debugging and Slack integration, but it's not required.

How do I prevent the same story being summarised across topics?

Pass the model the URLs from prior queries in the same run with the instruction: 'do not re-mention any URL already covered.' Or run a single multi-topic search and let the model partition. Both work; the second is cheaper.

APIs utilisées dans cet article

Écrit par
Sarah Choy
CEO, API Pick

Sarah Choy est CEO d'API Pick. Elle écrit sur la création d'APIs prêtes pour la production destinées aux agents IA et aux workflows LLM.