Felo API PlatformFelo API Platform

Research

Turn one question into a sourced research brief

Ask the web, pull the pages behind the answer as Markdown, add what X is saying, then keep the evidence in a LiveDoc you can query again later.

Build time20 minutesLevelIntermediateUpdated2026-10-29
Who it's forFounders & operatorsMarket researchersGTM teams

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 sourced research brief for [question or decision].

Scope: [market, region, language]. Time window: [last 30 days / last 12 months]. Audience: [who will read it]. Depth: [one-page scan / full brief].

Produce a Markdown brief with:
1. A short answer in three bullets.
2. An evidence table: claim, source title, URL, publication date.
3. What the sources disagree on.
4. What is still unknown.
5. A full source list.

Rules:
- Every factual claim needs a source link. Separate facts, opinions, and your inference.
- Never invent quotes, metrics, dates, or sources. Missing data is "Not available", never zero.
- Prefer primary sources. Use X for practitioner signal, not as proof.
- Resolve the time window to explicit start and end dates; state the timezone.
- Before spending credits, show the API calls you plan to make and wait for my approval.
- Do not create a recurring task, send messages, or publish anything.
- Write the result to ./research-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 brief (excerpt)

Will small models replace large ones for support bots?

Short answer

  • Small models are already good enough for classification and first-line answers.
  • The bottleneck is retrieval quality, not model size.
  • Teams that switched report lower cost per ticket, not higher resolution rates.
ClaimSourceDate
Retrieval quality dominates answer qualityhttps://example.com/rag-eval2026-10-12
Cost per resolved ticket fell 38%https://example.com/support-case2026-09-28

What the sources disagree on

Vendor benchmarks show near-parity; independent tests still find a gap on multi-step refunds.

Still unknown

Whether the gap closes with better tool use or requires a larger model.

The exact calls

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

Show the exact API calls
  1. Ask the web a question

    Chat searches the web, ranks the sources, writes the answer, and returns the resources it used. Keep the top three: every later step follows one of those links. The helper below sends the key once and throws on a non-2xx response.

    research.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 }[] };
    };
    
    export async function answer(question: string) {
      const chat = await felo<ChatData>("/v2/chat", { query: question });
      return { answer: chat.data.answer, sources: chat.data.resources.slice(0, 3) };
    }

    Example output

    {
      "answer": "Recent developments include …",
      "sources": [
        { "link": "https://example.com/article", "title": "…" }
      ]
    }
  2. Pull the pages behind the answer

    A snippet is not enough for a brief. Fetch the pages in Markdown with readability enabled, so quotes and headings survive without the navigation clutter. Requesting the same URL again can hit the extractor cache.

    research.ts
    type ExtractData = { data: { content: string } };
    
    const pages = await Promise.all(
      sources.map((source) =>
        felo<ExtractData>("/v2/web/extract", {
          url: source.link,
          output_format: "markdown",
          with_readability: true,
          with_cache: true,
        }).then((page) => ({ ...source, content: page.data.content })),
      ),
    );

    Example output

    // pages[0].content
    "# Example Article\n\nExtracted article content…"
  3. Add what X is saying

    News covers announcements; X covers what people hit in practice. Search the last seven days, then keep the author and timestamp so the brief can attribute every claim. Raise limit for a wider net; each page of results carries a cursor.

    research.ts
    type XData = {
      data: {
        tweets: {
          content: string;
          author: { username: string };
          created_at: string;
        }[];
      };
    };
    
    const since = Math.floor((Date.now() - 7 * 24 * 60 * 60 * 1000) / 1000);
    
    const social = await felo<XData>("/v2/x/tweet/search", {
      query: question,
      limit: 10,
      since_time: since,
    });

    Example output

    { "data": { "tweets": [
      { "content": "…", "author": { "username": "…" }, "created_at": "…" }
    ] } }
  4. File the evidence in a LiveDoc

    Create a LiveDoc and add the sources as URL resources. The API deduplicates what it has already seen and returns a resource id per URL, so the same evidence can be retrieved by any later question instead of being fetched again.

    research.ts
    type LiveDocData = { data: { short_id: string } };
    
    const doc = await felo<LiveDocData>("/v2/livedocs", {
      name: `Research: ${question.slice(0, 60)}`,
      description: "Sources collected while answering the question",
    });
    
    await felo(`/v2/livedocs/${doc.data.short_id}/resources/urls`, {
      urls: sources.map((source) => ({ url: source.link, title: source.title })),
    });
    
    console.log(doc.data.short_id); // keep this for later queries
  5. Ask the evidence again later

    This is the payoff: the next question runs semantic retrieval over the LiveDoc instead of the open web. Pass resource_ids only when you want to search a known subset.

    research.ts
    type Retrieved = {
      data: { title: string; content: string; score: number }[];
    };
    
    async function ask(livedoc: string, query: string) {
      const hits = await felo<Retrieved>(
        `/v2/livedocs/${livedoc}/resources/retrieve`,
        { query },
      );
      return hits.data.filter((hit) => hit.score >= 0.7);
    }

    Example output

    [
      { "title": "…", "content": "…", "score": 0.92 }
    ]

What's included

  • A sourced answer from Chat API, with the pages behind it
  • Full-page Markdown extraction for the strongest sources
  • X posts with author and timestamp for practitioner signal
  • A LiveDoc that keeps the evidence queryable for later questions

What it doesn't do

  • Public sources only; paywalled or login-only pages may fail
  • X coverage is a signal, not a representative survey
  • No interviews, private data, or paid databases
  • It says when the evidence is thin instead of filling gaps
  • One run per prompt; scheduling belongs to your agent or cron

Questions

Where do the sources come from?

Chat API returns the pages it used, Web Fetch turns the strongest ones into Markdown, and X Search adds dated practitioner posts. Every item keeps its URL.

Can I research a market outside tech?

Yes. Replace the scope placeholder with your market. Niche markets may have fewer public sources; the brief marks those gaps instead of guessing.

Does it keep the evidence after the run?

Yes, when the LiveDoc step runs. The returned short_id lets later questions retrieve the same pages instead of fetching them again.

How much does a brief cost?

Billing is usage-based credits; current rates are on the pricing page. The prompt asks for approval before it spends anything.

Can I run it every week?

Yes, but this prompt runs once. Set the schedule in an agent or cron job that can execute the same workflow.

What if a source is paywalled?

It is skipped and labeled unavailable. The brief never fills a paywalled gap with an invented fact or quote.

Related workflows

Make it yours

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

Write the brief to a file

Compose the answer, the page excerpts, and the X quotes into Markdown, then hand that string to your report tool or commit it to your docs repo. Keep the source links beside the claims — the brief is only as useful as its citations.

Run it on a schedule

Wrap `answer()` in a cron job and write each brief to a dated file. The same LiveDoc keeps accumulating sources, so week four answers from the evidence collected in weeks one to three.

Skip the LiveDoc

If you already have a database, store the chat answer and the extracted pages there. The LiveDoc step is for retrieval, not storage by default.

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