Felo API PlatformFelo API Platform

Content

Ship a daily AI news digest your team actually reads

Get a sourced roundup, add what practitioners are posting on X, pull one video transcript, then compose the issue in Markdown and archive it in a LiveDoc.

Build time25 minutesLevelIntermediateUpdated2026-10-29
Who it's forMarketing & growthCreatorsProduct marketers

Copy the prompt

Replace the bracketed fields, then paste it into Claude Code, Codex, or any AI with terminal access. It installs the Felo skill, asks before spending credits, and runs the workflow.

Build a daily industry brief for [industry or topic].

Time window: last 24 hours, timezone [timezone]. Audience: [readers].
Watchlist (optional): X [accounts or topics], YouTube [channels], Reddit [communities].

Pick the 5-8 items that matter. For each: what happened, why it matters, the source link, and whether it is an announcement, a result, or an opinion.

Sections:
1. Top story.
2. 5-8 items with a source link each.
3. What people are saying on X, with handles and dates.
4. One video quote with a timestamp.
5. What to watch next.

Rules:
- Link every item. Group duplicate coverage and keep the best source.
- Separate announcements from independent results; label vendor claims.
- Report only metrics the source returns. Missing data is "Not available", never zero.
- If nothing significant happened, say so instead of padding the issue.
- Before spending credits, show the API calls you plan to make and wait for my approval.
- Do not schedule, publish, or send anything.
- Write the result to ./daily-brief.md and summarize it in chat.

The copy also includes the install steps and safety rules.

What you get

Example output from a run. Not a live generation.

Example issue (excerpt)

AI industry brief — 2026-10-30

Top story

A major lab published a smaller model with tool use at the same benchmark score as its flagship. Vendor claim; independent results are still pending.

Items

  1. Small model, same benchmark — vendor benchmark, not yet replicated. [source]
  2. Agent framework release — new tracing and retry controls. [source]

What people are saying

@example_dev: "The win is latency, not the score." — 2026-10-30 08:12 JST

One video quote

"We stopped measuring tokens and started measuring resolved tickets." — [12:40]

What to watch next

Independent evals for tool use, and whether the price holds after launch week.

The exact calls

For developers: the same workflow as copy-paste code, in the order it runs.

Show the exact API calls
  1. Get the sourced roundup

    Chat searches the web, ranks the results, writes the answer, and returns the resources it used. Ask for a narrow window so the digest is about the last day, not the last year, and keep the top resources for citations. The helper below sends the key once and throws on a non-2xx response.

    digest.ts
    const BASE = "https://openapi.felo.ai";
    const headers = {
      Authorization: `Bearer ${process.env.FELO_API_KEY}`,
      "Content-Type": "application/json",
    };
    
    async function felo<T>(path: string, body?: unknown): Promise<T> {
      const res = await fetch(`${BASE}${path}`, {
        method: body ? "POST" : "GET",
        headers,
        body: body ? JSON.stringify(body) : undefined,
      });
      if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
      return res.json() as Promise<T>;
    }
    
    type ChatData = {
      data: {
        answer: string;
        resources: { link: string; title: string; snippet: string }[];
      };
    };
    
    const roundup = await felo<ChatData>("/v2/chat", {
      query: "Biggest AI news stories in the last 24 hours",
    });
    
    const sources = roundup.data.resources.slice(0, 5);

    Example output

    {
      "answer": "The main stories today are …",
      "sources": [
        { "link": "https://example.com/story", "title": "…", "snippet": "…" }
      ]
    }
  2. Add what practitioners are posting

    Press coverage repeats the announcement; X shows whether anyone can get it to work. Search the same 24-hour window, then filter on engagement so three useful posts survive instead of twenty replies. Keep the handle and timestamp — they are part of the citation.

    digest.ts
    type XData = {
      data: {
        tweets: {
          content: string;
          author: { username: string };
          created_at: string;
          metrics: { retweet_count: number; favorite_count: number };
        }[];
        next_cursor: string | null;
        has_next: boolean;
      };
    };
    
    const since = Math.floor((Date.now() - 24 * 60 * 60 * 1000) / 1000);
    
    const social = await felo<XData>("/v2/x/tweet/search", {
      query: "AI agents",
      limit: 20,
      since_time: since,
    });
    
    const posts = social.data.tweets
      .filter((tweet) => tweet.metrics.favorite_count >= 50)
      .slice(0, 3);

    Example output

    { "data": { "tweets": [
      {
        "content": "…",
        "author": { "username": "…" },
        "created_at": "2026-10-29T02:14:00Z",
        "metrics": { "retweet_count": 12, "favorite_count": 180 }
      }
    ] } }
  3. Pull one video transcript

    A single talk or demo is often the most substantive item of the day. Fetch its subtitles with timestamps, then flatten them into one paragraph — the digest only needs a short excerpt, and with_time=true gives you timestamps to jump back to.

    digest.ts
    type SubtitleData = {
      data: {
        title: string;
        contents: { text: string; start: number; duration: number }[];
      };
    };
    
    const videoCode = "dQw4w9WgXcQ"; // replace with today's video id
    
    const video = await felo<SubtitleData>(
      `/v2/youtube/subtitling?video_code=${videoCode}&language=en&with_time=true`,
    );
    
    const transcript = video.data.contents.map((line) => line.text).join(" ");

    Example output

    {
      "title": "Example Video Title",
      "contents": [
        { "text": "Subtitle text", "start": 0.32, "duration": 14.26 }
      ]
    }
  4. Compose the issue in Markdown

    This step is plain code, not an API call: assemble the roundup, the X posts, the transcript excerpt, and the source list into one Markdown string. Keep the sources at the bottom and a link beside every claim — a digest without citations is just another summary.

    digest.ts
    const date = new Date().toISOString().slice(0, 10);
    
    const issue = [
      `# AI digest — ${date}`,
      "",
      "## The roundup",
      roundup.data.answer,
      "",
      "## What practitioners are posting",
      ...posts.map((post) => `- @${post.author.username}: ${post.content}`),
      "",
      "## From the video",
      transcript.slice(0, 1200),
      "",
      "## Sources",
      ...sources.map((source) => `- [${source.title}](${source.link})`),
    ].join("\n");
    
    console.log(issue);
  5. Archive the issue in a LiveDoc

    Create one archive LiveDoc and add each issue as a document resource, so the file stays in your repo while the searchable copy lives in the platform. Later questions — "when did we last cover this?" — run semantic retrieval over every issue instead of opening dated files.

    digest.ts
    type LiveDocData = { data: { short_id: string } };
    
    const archive = await felo<LiveDocData>("/v2/livedocs", {
      name: "AI digest archive",
      description: "One document resource per daily issue",
    });
    
    await felo(`/v2/livedocs/${archive.data.short_id}/resources/doc`, {
      title: `AI digest — ${date}`,
      content: issue,
    });
    
    type Retrieved = { data: { title: string; content: string; score: number }[] };
    
    const past = await felo<Retrieved>(
      `/v2/livedocs/${archive.data.short_id}/resources/retrieve`,
      { query: "what did we say about agent frameworks last month" },
    ).then((res) => res.data.filter((hit) => hit.score >= 0.7));

    Example output

    [
      { "title": "AI digest — 2026-10-01", "content": "…", "score": 0.88 }
    ]

What's included

  • A sourced roundup with dated links
  • Practitioner posts from X with handles
  • One YouTube transcript excerpt with a timestamp
  • The issue archived in a LiveDoc so past issues are searchable

What it doesn't do

  • No paywalled news or private Slack/Discord sources
  • X coverage is incomplete; it is a signal, not a survey
  • One video per issue, and only when subtitles are available
  • It does not schedule or publish the issue; that is your agent's job
  • No invented engagement numbers or quotes

Questions

Can I use it for an industry other than AI?

Yes. Replace the industry, timezone, watchlist, and audience placeholders. The same prompt works for any beat with public coverage.

Can it run every day?

The prompt runs once. To publish daily, set the schedule in an agent or cron job that executes the same workflow and archives each issue.

Does it read every video on my watchlist?

No. It picks one video and uses its transcript when subtitles exist. A title or description is never treated as proof of the content.

How much does an issue cost?

Each search, extraction, and transcript spends usage-based credits; current rates are on the pricing page. The prompt asks for approval before spending.

Will it miss stories?

Possibly. Coverage depends on what the sources return, and the issue states its gaps instead of pretending to be complete.

How do I avoid repeating yesterday's news?

Run it against the same LiveDoc archive and ask it to compare the previous issue before selecting today's items.

Related workflows

Make it yours

The same recipe, adapted to the way you actually ship.

Run it before the team wakes up

Wrap the steps in a function and call it from cron once a day. Write each issue to a dated file in your repo, but create the archive LiveDoc only once and reuse its `short_id` — otherwise every run starts a new, empty archive.

Change the beat

The same five steps work for any niche: swap the Chat query and the X query for your vertical, and keep the transcript only when the day's video is actually on topic. A narrow beat is what makes a digest worth subscribing to.

Publish where the team already reads

Send `issue` to Slack, email, or your CMS and treat the LiveDoc as the source of truth. The composed Markdown is plain text, so every destination takes it without conversion.

The reference pages behind this recipe, and where to go next.