Agent recipe

Monitor brand mentions on the web and TikTok

Search the web and TikTok for your brand, then read the comments under the posts that mention it: a daily brand check an agent can run on its own.

Brand monitoring is a loop over the places people talk about you. This recipe covers two of them: the open web, through a web search capability, and TikTok, where it finds the videos that mention your brand and reads the comments under them. Run it daily and let the agent flag what is new or negative.

Each step lists the cheapest tools that serve it, with each one's price and health. Their input fields can differ from one source to the next, so read a tool's schema with GET /v1/tools/{id} before you call it, or hand the tools to a model as functions and let it fill them in.

Steps

  1. Search the web for mentions

    Web search · Web search

    Run a web search for the brand name with words such as review, vs or alternative, and keep the results that are new since the last run.

    Example input
    {
      "query": "\"Notion\" review"
    }

    No tool in the catalog serves this step right now. The rest of the recipe still runs; check back for this one.

  2. Find TikTok videos about the brand

    Video search · TikTok

    Search TikTok videos by the brand name and its product names to catch the posts people are watching.

    Example input
    {
      "keyword": "notion app"
    }

    No tool in the catalog serves this step right now. The rest of the recipe still runs; check back for this one.

  3. Read the reactions

    Video comments · TikTok

    Pull the comments under the videos that mention the brand and let the agent sort them into praise, complaints and questions that need an answer.

    Example input
    {
      "video_id": "VIDEO_ID_FROM_STEP_2"
    }

    No tool in the catalog serves this step right now. The rest of the recipe still runs; check back for this one.

Run the whole recipe

curl
# Needs curl and jq. Step 1 is shown; repeat it with each step's query.
TOOL_ID=$(curl -s https://api.orcarouter.ai/v1/tools/discover \
  -H "Authorization: Bearer $ORCAROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"q": "web search", "limit": 1}' | jq -r '.data.results[0].id')

# The inputs the tool takes
curl -s "https://api.orcarouter.ai/v1/tools/$TOOL_ID" \
  -H "Authorization: Bearer $ORCAROUTER_API_KEY" | jq '.data.input_schema'

# Run it with those inputs
curl -s "https://api.orcarouter.ai/v1/tools/$TOOL_ID/run" \
  -H "Authorization: Bearer $ORCAROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input": {"query": "\"Notion\" review"}}'
Python
# pip install requests openai
import json
import os

import requests
from openai import OpenAI

BASE = "https://api.orcarouter.ai"
KEY = os.environ["ORCAROUTER_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}

# One discover query per step of the recipe.
STEPS = ["web search", "tiktok video search", "tiktok video comments"]
TASK = (
    "Find this week's mentions of Notion on the web and on TikTok, "
    "and summarise what people say about it."
)


def discover(query, limit=2):
    r = requests.post(f"{BASE}/v1/tools/discover", json={"q": query, "limit": limit}, headers=HEADERS, timeout=30)
    r.raise_for_status()
    return [tool["id"] for tool in r.json()["data"]["results"]]


def run(name, tool_input):
    r = requests.post(f"{BASE}/v1/tools/{name}/run", json={"input": tool_input}, headers=HEADERS, timeout=120)
    return r.text  # the tool's answer, or its error, goes back to the model


ids = [tool_id for query in STEPS for tool_id in discover(query)]
fns = requests.get(
    f"{BASE}/v1/tools/functions",
    params={"ids": ",".join(ids), "format": "openai"},
    headers=HEADERS,
    timeout=30,
)
fns.raise_for_status()
tools = fns.json()["data"]["tools"]

llm = OpenAI(base_url=f"{BASE}/v1", api_key=KEY)
messages = [{"role": "user", "content": TASK}]
for _ in range(10):
    msg = llm.chat.completions.create(model="openai/gpt-5-mini", messages=messages, tools=tools).choices[0].message
    messages.append(msg)
    if not msg.tool_calls:
        print(msg.content)
        break
    for call in msg.tool_calls:
        result = run(call.function.name, json.loads(call.function.arguments or "{}"))
        messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
TypeScript
// npm install openai
import OpenAI from "openai";
import type { ChatCompletionMessageParam } from "openai/resources/chat/completions";

const BASE = "https://api.orcarouter.ai";
const KEY = process.env.ORCAROUTER_API_KEY!;
const headers = { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" };

// One discover query per step of the recipe.
const STEPS = ["web search", "tiktok video search", "tiktok video comments"];
const TASK =
  "Find this week's mentions of Notion on the web and on TikTok, " +
  "and summarise what people say about it.";

async function discover(q: string, limit = 2): Promise<string[]> {
  const res = await fetch(`${BASE}/v1/tools/discover`, {
    method: "POST",
    headers,
    body: JSON.stringify({ q, limit }),
  });
  if (!res.ok) throw new Error(`discover: HTTP ${res.status}`);
  const { data } = await res.json();
  return data.results.map((tool: { id: string }) => tool.id);
}

async function run(name: string, input: unknown): Promise<string> {
  const res = await fetch(`${BASE}/v1/tools/${name}/run`, {
    method: "POST",
    headers,
    body: JSON.stringify({ input }),
  });
  return res.text(); // the tool's answer, or its error, goes back to the model
}

async function main() {
  const ids = (await Promise.all(STEPS.map((q) => discover(q)))).flat();
  const fns = await fetch(
    `${BASE}/v1/tools/functions?format=openai&ids=${encodeURIComponent(ids.join(","))}`,
    { headers },
  );
  if (!fns.ok) throw new Error(`functions: HTTP ${fns.status}`);
  const { data } = await fns.json();

  const llm = new OpenAI({ baseURL: `${BASE}/v1`, apiKey: KEY });
  const messages: ChatCompletionMessageParam[] = [{ role: "user", content: TASK }];
  for (let turn = 0; turn < 10; turn++) {
    const reply = await llm.chat.completions.create({ model: "openai/gpt-5-mini", messages, tools: data.tools });
    const msg = reply.choices[0].message;
    messages.push(msg);
    if (!msg.tool_calls?.length) {
      console.log(msg.content);
      return;
    }
    for (const call of msg.tool_calls) {
      const fn = call.type === "function" ? call.function : undefined;
      const result = fn ? await run(fn.name, JSON.parse(fn.arguments || "{}")) : "unsupported tool call";
      messages.push({ role: "tool", tool_call_id: call.id, content: result });
    }
  }
}

main();
© 2026 OrcaRouter

For Providers

Run an inference platform? Get your models on OrcaRouter.

providers@orcarouter.ai

Join our community

Discordsupport@orcarouter.aiXLinkedInGitHubYouTube