← Back to blog

Give Your LLM Agent Web Superpowers with FetchAPI Function Calling

An LLM on its own is a very smart colleague locked in a windowless room. It can reason beautifully, but it can't watch a YouTube video, read a competitor's pricing page, or look up what a link actually says before clicking it. Function calling (a.k.a. tool use) is the door out of that room — and the quality of the tools you hand your agent determines how useful it becomes.

This tutorial shows you how to turn the four FetchAPI endpoints into native agent tools using OpenAI-style function calling. By the end you'll have a working agent loop that can transcribe videos, read any web page as markdown, extract link metadata, and pull video stats — all from one API key, with no HTML parsing or scraping infrastructure.

Why FetchAPI fits function calling so well

Function calling works best when each tool has a narrow, predictable output. You don't want a tool that returns raw HTML (thousands of tokens of noise) or a tool that behaves differently on every site. You want small, structured JSON your model can reason over cheaply.

That's exactly what FetchAPI returns:

Agent capability Endpoint What the model gets
Read a web page GET /v1/markdownify Clean markdown + word_count
Transcribe a video GET /v1/transcript Timestamped segments
Preview a link GET /v1/ogsnap Title, description, image
Get video metadata GET /v1/info Title, channel, views, duration

Every endpoint is a plain GET with a url parameter, returns compact JSON, and needs no signup on the free tier — which means you can prototype an agent tool in seconds.

Step 1: Know what each tool returns

Before writing schemas, it helps to see the actual responses. Each of these is a single curl away.

Transcribe a video:

curl "https://fetchapi.tech/v1/transcript?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ"
{
  "video_id": "dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
  "channel": "Rick Astley",
  "duration_seconds": 213,
  "transcript": [
    { "start": 21.8, "end": 25.95, "text": "We're no strangers to love...", "start_formatted": "0:21" }
  ]
}

Read a page as markdown:

curl "https://fetchapi.tech/v1/markdownify?url=https://example.com"
{
  "content": "This domain is for use in documentation examples...",
  "title": "",
  "url": "https://example.com",
  "word_count": 25,
  "char_count": 156
}

Preview a link:

curl "https://fetchapi.tech/v1/ogsnap?url=https://example.com"
{ "url": "https://example.com", "title": "Example Domain", "description": "", "image": "", "og": {}, "twitter": {}, "jsonld": [] }

Get video metadata: GET /v1/info?url=... returns the same header fields as the transcript response minus the segments — perfect for a cheap "should I even read this?" check.

Step 2: Define the tool schemas

Hand these four schemas to your model. Descriptions matter: they're how the model decides when to call each tool.

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_video_transcript",
            "description": "Get the full timestamped transcript of a YouTube video. Use when the user asks about what is said in a video.",
            "parameters": {
                "type": "object",
                "properties": {"url": {"type": "string", "description": "YouTube video URL"}},
                "required": ["url"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "read_webpage",
            "description": "Fetch any web page as clean markdown. Use to read articles, docs, or blog posts.",
            "parameters": {
                "type": "object",
                "properties": {"url": {"type": "string"}},
                "required": ["url"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "get_link_preview",
            "description": "Get the title, description, and image for a URL. Use to triage links before reading them fully.",
            "parameters": {
                "type": "object",
                "properties": {"url": {"type": "string"}},
                "required": ["url"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "get_video_info",
            "description": "Get metadata (title, channel, views, duration) for a YouTube video.",
            "parameters": {
                "type": "object",
                "properties": {"url": {"type": "string"}},
                "required": ["url"],
            },
        },
    },
]

Step 3: Implement the dispatch layer

Each tool is a thin wrapper around one HTTP call. Keep them dumb and predictable:

import requests

BASE = "https://fetchapi.tech/v1"

def _get(path: str, url: str) -> dict:
    r = requests.get(f"{BASE}/{path}", params={"url": url}, timeout=20)
    r.raise_for_status()
    return r.json()

def get_video_transcript(url: str, **_):
    data = _get("transcript", url)
    text = " ".join(seg["text"] for seg in data.get("transcript", []))
    return {"title": data.get("title"), "transcript": text[:12000]}

def read_webpage(url: str, **_):
    data = _get("markdownify", url)
    return {"title": data.get("title"), "content": data["content"][:12000],
            "word_count": data.get("word_count")}

def get_link_preview(url: str, **_):
    data = _get("ogsnap", url)
    return {"title": data.get("title"), "description": data.get("description"),
            "image": data.get("image")}

def get_video_info(url: str, **_):
    return _get("info", url)

DISPATCH = {
    "get_video_transcript": get_video_transcript,
    "read_webpage": read_webpage,
    "get_link_preview": get_link_preview,
    "get_video_info": get_video_info,
}

Note the truncation on content and transcript. Tools should return enough to answer the question, not the entire internet. A 90-minute video is ~15,000 words; blindly stuffing that into context burns tokens and buries the signal. Truncating, or chunking and retrieving, keeps the agent fast and cheap.

Step 4: Close the loop

The classic function-calling loop is small: ask the model, run any tools it requests, append the results, ask again. Repeat until it answers.

import json
from openai import OpenAI

client = OpenAI()

def run_agent(user_message: str, model: str = "gpt-4o-mini"):
    messages = [{"role": "user", "content": user_message}]

    while True:
        resp = client.chat.completions.create(
            model=model, messages=messages, tools=TOOLS, tool_choice="auto"
        )
        msg = resp.choices[0].message
        messages.append(msg)

        if not msg.tool_calls:
            return msg.content

        for call in msg.tool_calls:
            fn = DISPATCH[call.function.name]
            args = json.loads(call.function.arguments)
            try:
                result = fn(**args)
                payload = json.dumps(result)
            except Exception as e:
                payload = json.dumps({"error": str(e)})
            messages.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": payload,
            })

print(run_agent(
    "Summarize this video and tell me if its author has a blog worth reading: "
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
))

Run that and you'll watch the agent call get_video_info, then get_video_transcript, then reason over the results — a real research loop, not a prompt template.

A concrete workflow: link triage

The most valuable pattern is cheap tool first, expensive tool second. When a user drops a list of links, call get_link_preview (OGSnap) on all of them. It's tiny and fast. The model reads the titles and descriptions, decides which two or three are actually relevant, and only then calls read_webpage (Markdownify) or get_video_transcript on those.

This one ordering rule cuts token spend dramatically and makes the agent feel decisive instead of noisy. It's the difference between an assistant that reads everything and one that reads the right thing.

Production tips

Wrap-Up

Function calling turns a chat model into an agent — but only if its tools return clean, structured, right-sized data. FetchAPI's Transcript, Markdownify, OGSnap, and Info endpoints are purpose-built for exactly that: one GET, compact JSON, no scraping stack to maintain.

Start with a single tool (read_webpage is the highest-leverage), get the loop working, then add the rest. Try it now:

curl "https://fetchapi.tech/v1/markdownify?url=https://example.com"

Then browse the full API docs and give your agent the web.