Workflow

Monthly Agent Search Budget Tracking

Track and forecast your AI agent search API costs monthly. Monitor credit usage, set budget alerts, and optimize search spend.

Overview

AI agents that use search APIs can rack up costs quickly if usage is not monitored. This workflow runs on the first of each month, queries your Scavio usage data, calculates the previous month's spend by agent or project, compares against budget, and forecasts next month's costs based on the usage trend. It sends a budget report and alerts if any project exceeded its allocation. At $0.005 per credit, this workflow helps you keep agent search costs under control.

Trigger

Cron 1st of month 9 AM UTC

Schedule

Monthly 1st 9 AM

Workflow Steps

1

Load Budget Configuration

Read per-project budget allocations and alert thresholds from a configuration file.

2

Aggregate Usage by Project

Read usage logs from the past month and group credit consumption by project or agent ID.

3

Calculate Spend and Compare Budget

Multiply credits by $0.005 to get dollar spend. Compare each project against its monthly budget.

4

Forecast Next Month

Use the 3-month trend to project next month's usage and flag projects likely to exceed budget.

5

Generate Budget Report

Create a structured report with per-project spend, budget utilization, and forecast.

6

Send Alerts

Notify project owners via Slack or email if they exceeded budget or are trending over.

Python Implementation

Python
import json, os
from pathlib import Path
from datetime import date, timedelta

COST_PER_CREDIT = 0.005
BUDGET_FILE = Path("search_budgets.json")
USAGE_LOG = Path("search_usage.jsonl")
REPORTS_DIR = Path("budget_reports")
REPORTS_DIR.mkdir(exist_ok=True)

def load_usage(month_str: str) -> dict:
    """Load usage from JSONL log, filtered to the given month."""
    usage = {}
    if not USAGE_LOG.exists():
        return usage
    for line in USAGE_LOG.read_text().strip().split("\n"):
        if not line:
            continue
        entry = json.loads(line)
        if entry.get("date", "").startswith(month_str):
            project = entry.get("project", "default")
            usage.setdefault(project, 0)
            usage[project] += entry.get("credits", 0)
    return usage

def load_history(months: int = 3) -> list:
    """Load usage for the last N months for forecasting."""
    history = []
    today = date.today()
    for i in range(1, months + 1):
        d = today.replace(day=1) - timedelta(days=30 * i)
        month_str = d.strftime("%Y-%m")
        history.append(load_usage(month_str))
    return history

def forecast(history: list, project: str) -> float:
    values = [h.get(project, 0) for h in history if project in h]
    if not values:
        return 0
    return sum(values) / len(values)

def run():
    budgets = json.loads(BUDGET_FILE.read_text())
    last_month = (date.today().replace(day=1) - timedelta(days=1)).strftime("%Y-%m")
    usage = load_usage(last_month)
    history = load_history(3)
    report = {"month": last_month, "projects": []}
    alerts = []

    for project, budget_credits in budgets.items():
        credits_used = usage.get(project, 0)
        spend = credits_used * COST_PER_CREDIT
        budget_dollars = budget_credits * COST_PER_CREDIT
        utilization = credits_used / max(budget_credits, 1) * 100
        forecasted = forecast(history, project)
        forecasted_spend = forecasted * COST_PER_CREDIT

        entry = {
            "project": project,
            "credits_used": credits_used,
            "spend_usd": round(spend, 2),
            "budget_usd": round(budget_dollars, 2),
            "utilization_pct": round(utilization, 1),
            "forecast_credits": round(forecasted),
            "forecast_usd": round(forecasted_spend, 2),
        }
        report["projects"].append(entry)

        if utilization > 100:
            alerts.append(f"OVER BUDGET: {project} used {utilization:.0f}% of budget")
        if forecasted > budget_credits * 1.2:
            alerts.append(f"FORECAST ALERT: {project} trending ${forecasted_spend:.2f} vs ${budget_dollars:.2f} budget")

    out = REPORTS_DIR / f"budget_{last_month}.json"
    out.write_text(json.dumps(report, indent=2))
    print(f"Budget report for {last_month}:")
    for p in report["projects"]:
        print(f"  {p['project']}: ${p['spend_usd']} / ${p['budget_usd']} ({p['utilization_pct']}%)")
    for a in alerts:
        print(f"  ALERT: {a}")

run()

JavaScript Implementation

JavaScript
const fs = await import('fs');

const COST_PER_CREDIT = 0.005;
const budgets = JSON.parse(fs.readFileSync('search_budgets.json', 'utf8'));
const USAGE_LOG = 'search_usage.jsonl';
const REPORTS_DIR = 'budget_reports';
try { fs.mkdirSync(REPORTS_DIR); } catch {}

function loadUsage(monthStr) {
  const usage = {};
  try {
    const lines = fs.readFileSync(USAGE_LOG, 'utf8').trim().split('\n');
    for (const line of lines) {
      if (!line) continue;
      const entry = JSON.parse(line);
      if ((entry.date||'').startsWith(monthStr)) {
        const project = entry.project || 'default';
        usage[project] = (usage[project]||0) + (entry.credits||0);
      }
    }
  } catch {}
  return usage;
}

function getLastMonth() {
  const d = new Date();
  d.setDate(0);
  return d.toISOString().slice(0,7);
}

function loadHistory(months) {
  const history = [];
  const now = new Date();
  for (let i = 1; i <= months; i++) {
    const d = new Date(now.getFullYear(), now.getMonth()-i, 1);
    history.push(loadUsage(d.toISOString().slice(0,7)));
  }
  return history;
}

const lastMonth = getLastMonth();
const usage = loadUsage(lastMonth);
const history = loadHistory(3);

const report = {month:lastMonth, projects:[]};
const alerts = [];

for (const [project, budgetCredits] of Object.entries(budgets)) {
  const creditsUsed = usage[project]||0;
  const spend = creditsUsed * COST_PER_CREDIT;
  const budgetUsd = budgetCredits * COST_PER_CREDIT;
  const utilization = creditsUsed / Math.max(budgetCredits,1) * 100;
  const histVals = history.map(h=>h[project]||0).filter(v=>v>0);
  const forecasted = histVals.length ? histVals.reduce((s,v)=>s+v,0)/histVals.length : 0;
  report.projects.push({project, creditsUsed, spendUsd:Math.round(spend*100)/100, budgetUsd:Math.round(budgetUsd*100)/100, utilizationPct:Math.round(utilization*10)/10, forecastCredits:Math.round(forecasted), forecastUsd:Math.round(forecasted*COST_PER_CREDIT*100)/100});
  if (utilization > 100) alerts.push('OVER BUDGET: '+project+' used '+Math.round(utilization)+'%');
  if (forecasted > budgetCredits * 1.2) alerts.push('FORECAST: '+project+' trending $'+(forecasted*COST_PER_CREDIT).toFixed(2)+' vs $'+budgetUsd.toFixed(2));
}

fs.writeFileSync(REPORTS_DIR+'/budget_'+lastMonth+'.json', JSON.stringify(report, null, 2));
console.log('Budget report for '+lastMonth+':');
report.projects.forEach(p => console.log('  '+p.project+': $'+p.spendUsd+' / $'+p.budgetUsd+' ('+p.utilizationPct+'%)'));
alerts.forEach(a => console.log('  ALERT: '+a));

Platforms Used

Google

Web search with knowledge graph, PAA, and AI overviews

Frequently Asked Questions

AI agents that use search APIs can rack up costs quickly if usage is not monitored. This workflow runs on the first of each month, queries your Scavio usage data, calculates the previous month's spend by agent or project, compares against budget, and forecasts next month's costs based on the usage trend. It sends a budget report and alerts if any project exceeded its allocation. At $0.005 per credit, this workflow helps you keep agent search costs under control.

This workflow uses a cron 1st of month 9 am utc. Monthly 1st 9 AM.

This workflow uses the following Scavio platforms: google. Each platform is called via the same unified API endpoint.

Yes. Scavio's free tier includes 250 credits per month with no credit card required. That is enough to test and validate this workflow before scaling it.

Monthly Agent Search Budget Tracking

Track and forecast your AI agent search API costs monthly. Monitor credit usage, set budget alerts, and optimize search spend.