The AI Agent FinOps Playbook: Budget Enforcement, Cost Allocation & Spend Analytics for Multi-Agent Systems
Notice: This is an educational guide with illustrative code examples. It does not execute code or install dependencies. All examples use the GreenHelix sandbox (https://sandbox.greenhelix.net) which provides 500 free credits — no API key required to get started.
Referenced credentials (you supply these in your own environment):
GREENHELIX_API_KEY: API authentication for GreenHelix gateway (read/write access to purchased API tools only)AGENT_SIGNING_KEY: Cryptographic signing key for agent identity (Ed25519 key pair for request signing)
When a CrewAI orchestrator spawns five researcher agents, each calling GPT-4o at $0.005 per request, and one agent enters a retry loop that fires 12,000 requests in an hour, who gets the bill? When a LangGraph workflow fans out to eight parallel tool-calling agents across three cloud providers, how does the platform team attribute $2,400 in daily compute back to the workflow that caused it? When a production AutoGen group chat quietly doubles its tool-call volume over three weeks because a prompt change removed a termination condition, who notices before the monthly invoice arrives? These are not hypothetical problems. A March 2026 postmortem from an AI infrastructure startup revealed that a single misconfigured agent loop consumed $47,000 in API credits over a weekend -- with no alert, no budget cap, and no way to attribute the cost to a specific agent. The FinOps Foundation's "FinOps for AI" initiative, launched in January 2026, identified cost governance for autonomous agents as one of the top three unsolved problems in AI infrastructure economics. This guide solves it. Using the GreenHelix A2A Commerce Gateway's 23 billing and webhook tools, you will build a complete FinOps control plane: per-agent wallets with hard budget caps, real-time spend alerts, cost attribution by agent and workflow, volume discount optimization, fleet-wide dashboards, and API key isolation as a cost containment boundary. Every pattern is production-ready, backed by working Python code, and deployable today. Before diving into the full guide, here is the minimum viable FinOps setup: one agent, one wallet, one budget cap, one alert. This takes under two minutes.
## What You'll Learn
- Quick Start
- Chapter 1: The Multi-Agent Cost Problem
- Chapter 2: Per-Agent Wallet Provisioning
- Chapter 3: Budget Caps and Hard Stops
- Chapter 4: Real-Time Spend Alerts with Webhooks
- Chapter 5: Cost Attribution and Category Spend
- Chapter 6: Volume Discounts and Cost Optimization
- Chapter 7: Fleet Dashboards and Leaderboards
- Chapter 8: API Key Isolation and Security
- Chapter 9: Putting It All Together: The FinOps Control Plane
## Full Guide
# The AI Agent FinOps Playbook: Budget Enforcement, Cost Allocation & Spend Analytics for Multi-Agent Systems
When a CrewAI orchestrator spawns five researcher agents, each calling GPT-4o at $0.005 per request, and one agent enters a retry loop that fires 12,000 requests in an hour, who gets the bill? When a LangGraph workflow fans out to eight parallel tool-calling agents across three cloud providers, how does the platform team attribute $2,400 in daily compute back to the workflow that caused it? When a production AutoGen group chat quietly doubles its tool-call volume over three weeks because a prompt change removed a termination condition, who notices before the monthly invoice arrives? These are not hypothetical problems. A March 2026 postmortem from an AI infrastructure startup revealed that a single misconfigured agent loop consumed $47,000 in API credits over a weekend -- with no alert, no budget cap, and no way to attribute the cost to a specific agent. The FinOps Foundation's "FinOps for AI" initiative, launched in January 2026, identified cost governance for autonomous agents as one of the top three unsolved problems in AI infrastructure economics. This guide solves it. Using the GreenHelix A2A Commerce Gateway's 23 billing and webhook tools, you will build a complete FinOps control plane: per-agent wallets with hard budget caps, real-time spend alerts, cost attribution by agent and workflow, volume discount optimization, fleet-wide dashboards, and API key isolation as a cost containment boundary. Every pattern is production-ready, backed by working Python code, and deployable today.
---
## Quick Start
Before diving into the full guide, here is the minimum viable FinOps setup: one agent, one wallet, one budget cap, one alert. This takes under two minutes.
```python
from greenhelix_trading import AgentFinOps
import os
# Initialize the FinOps client for a single agent
finops = AgentFinOps(
api_key=os.environ["GREENHELIX_API_KEY"],
agent_id="research-agent-01",
base_url="https://api.greenhelix.net/v1",
)
# 1. Create an isolated wallet
finops.create_wallet()
# 2. Fund it
finops.deposit(amount=100.00)
# 3. Set a hard daily budget cap
finops.set_budget_cap(daily_limit=25.00, monthly_limit=500.00)
# 4. Register an alert at 75% spend
finops.register_webhook(
url="https://your-app.example.com/alerts/budget",
events=["budget.threshold"],
config={"threshold_pct": 75},
)
# 5. Check balance before any operation
balance = finops.get_balance()
print(f"Agent research-agent-01 ready. Balance: ${balance['balance']}")
That is five API calls. Your agent now has an isolated wallet, a $25/day hard stop, and an alert that fires when 75% of the daily budget is consumed. The rest of this guide builds on this foundation.
Table of Contents
- The Multi-Agent Cost Problem
- Per-Agent Wallet Provisioning
- Budget Caps and Hard Stops
- Real-Time Spend Alerts with Webhooks
- Cost Attribution and Category Spend
- Volume Discounts and Cost Optimization
- Fleet Dashboards and Leaderboards
- API Key Isolation and Security
- Putting It All Together: The FinOps Control Plane
- What to Do Next
Chapter 1: The Multi-Agent Cost Problem
Why Autonomous Agents Create Unbounded Cost
Human engineers have an implicit cost governor: they get tired, they context-switch, they go home at 6 PM. Agents do not. A LangChain agent with access to a tool catalog will call tools as long as its reasoning loop tells it to. A CrewAI crew that delegates subtasks to specialist agents will spawn as many subtasks as the orchestrator deems necessary. An AutoGen group chat will continue conversing until a termination condition is met -- and if that condition has a bug, the conversation runs forever. Each tool call, each LLM inference, each API request costs money. Without explicit cost governance, the spend trajectory of a multi-agent system is bounded only by the rate limit of the underlying API provider.
Three Failure Modes
Every multi-agent cost incident traces back to one of three root causes.
Failure Mode 1: Runaway Loops. An agent enters a retry or reasoning loop that never terminates. The most common trigger is a tool that returns an error, causing the agent to retry indefinitely. A single agent in a retry loop against GPT-4o can consume $50-200/hour depending on context window size. Without a per-agent budget cap, there is no circuit breaker.
Failure Mode 2: Tool-Call Amplification. An orchestrator agent delegates a task to N worker agents, each of which calls M tools, each of which triggers K downstream API calls. The total cost is O(N * M * K), and small changes to any multiplier produce large cost swings. A prompt change that causes each worker to call one additional tool per task can double fleet-wide spend overnight.
Failure Mode 3: No Attribution. All agents share a single API key and a single billing account. When the monthly bill spikes, there is no way to determine which agent, which workflow, or which tool category caused the increase. Without attribution, there is no accountability, and without accountability, there is no optimization.
The Wallet-Per-Agent Architecture
The GreenHelix approach solves all three failure modes with a single architectural pattern: every agent gets its own wallet with its own budget cap. This is the same principle as giving each microservice its own database -- isolation prevents blast radius propagation.
+-------------------+ +-------------------+ +-------------------+
| Agent: researcher | | Agent: summarizer | | Agent: classifier |
| Wallet: $100 | | Wallet: $50 | | Wallet: $75 |
| Cap: $25/day | | Cap: $15/day | | Cap: $20/day |
| Key: ak_res_xxxxx | | Key: ak_sum_xxxxx | | Key: ak_cls_xxxxx |
+--------+----------+ +--------+----------+ +--------+----------+
| | |
+------------+------------+------------+------------+
| |
+-------v-------------------------v-------+
| GreenHelix A2A Commerce Gateway |
| Budget enforcement layer |
| Cost attribution engine |
| Webhook alert system |
+------------------------------------------+
When the researcher agent hits its $25/day cap, it gets a 402 Payment Required response. The summarizer and classifier agents are unaffected. The blast radius of a runaway researcher is exactly $25 -- not the entire fleet budget.
The AgentFinOps Class
This class wraps every GreenHelix billing and webhook tool used in this guide. Define it once; reference it in every subsequent chapter.
import requests
import json
import time
from typing import Optional
class AgentFinOps:
"""FinOps client for the GreenHelix A2A Commerce Gateway.
Wraps the 23 billing and webhook tools into a clean interface
for budget enforcement, cost allocation, and spend analytics.
"""
def __init__(
self,
api_key: str,
agent_id: str,
base_url: str = "https://api.greenhelix.net/v1",
):
self.base_url = base_url
self.agent_id = agent_id
self.session = requests.Session()
self.session.headers.update({
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
})
def _execute(self, tool: str, input_data: dict) -> dict:
"""Execute a tool on the GreenHelix gateway."""
resp = self.session.post(
f"{self.base_url}/v1",
json={"tool": tool, "input": input_data},
)
if resp.status_code == 402:
raise BudgetExhaustedError(
f"Agent {self.agent_id} has exceeded its budget cap. "
f"Response: {resp.text}"
)
resp.raise_for_status()
return resp.json()
# -- Wallet Management -------------------------------------------
def create_wallet(self) -> dict:
return self._execute("create_wallet", {})
def get_balance(self) -> dict:
return self._execute("get_balance", {})
def deposit(self, amount: float) -> dict:
return self._execute("deposit", {"amount": str(amount)})
# -- Budget Enforcement ------------------------------------------
def set_budget_cap(
self,
daily_limit: float,
monthly_limit: Optional[float] = None,
) -> dict:
payload = {
"agent_id": self.agent_id,
"daily_limit": str(daily_limit),
}
if monthly_limit is not None:
payload["monthly_limit"] = str(monthly_limit)
return self._execute("set_budget_cap", payload)
def get_budget_status(self) -> dict:
return self._execute("get_budget_status", {
"agent_id": self.agent_id,
})
# -- Cost Analytics ----------------------------------------------
def get_usage_analytics(
self,
start_date: str,
end_date: str,
) -> dict:
return self._execute("get_usage_analytics", {
"agent_id": self.agent_id,
"start_date": start_date,
"end_date": end_date,
})
def get_billing_summary(self, period: str = "monthly") -> dict:
return self._execute("get_billing_summary", {
"agent_id": self.agent_id,
"period": period,
})
def get_spending_by_category(
self,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
) -> dict:
payload = {"agent_id": self.agent_id}
if start_date:
payload["start_date"] = start_date
if end_date:
payload["end_date"] = end_date
return self._execute("get_spending_by_category", payload)
# -- Cost Optimization -------------------------------------------
def get_volume_discount(self) -> dict:
return self._execute("get_volume_discount", {
"agent_id": self.agent_id,
})
def estimate_cost(self, tool_name: str, parameters: dict) -> dict:
return self._execute("estimate_cost", {
"tool": tool_name,
"parameters": parameters,
})
def convert_currency(
self,
amount: float,
from_currency: str,
to_currency: str,
) -> dict:
return self._execute("convert_currency", {
"amount": str(amount),
"from_currency": from_currency,
"to_currency": to_currency,
})
# -- Fleet Analytics ---------------------------------------------
def get_agent_leaderboard(self, metric: str = "cost_efficiency") -> dict:
return self._execute("get_agent_leaderboard", {
"metric": metric,
})
def get_platform_stats(self) -> dict:
return self._execute("get_platform_stats", {})
# -- API Key Management ------------------------------------------
def create_api_key(self, label: str, permissions: list = None) -> dict:
payload = {
"agent_id": self.agent_id,
"label": label,
}
if permissions:
payload["permissions"] = permissions
return self._execute("create_api_key", payload)
def rotate_api_key(self, key_id: str) -> dict:
return self._execute("rotate_api_key", {
"agent_id": self.agent_id,
"key_id": key_id,
})
# -- Webhooks ----------------------------------------------------
def register_webhook(
self,
url: str,
events: list,
config: Optional[dict] = None,
) -> dict:
payload = {
"agent_id": self.agent_id,
"url": url,
"events": events,
}
if config:
payload["config"] = config
return self._execute("register_webhook", payload)
def list_webhooks(self) -> dict:
return self._execute("list_webhooks", {
"agent_id": self.agent_id,
})
def update_webhook(
self,
webhook_id: str,
url: Optional[str] = None,
events: Optional[list] = None,
config: Optional[dict] = None,
) -> dict:
payload = {"webhook_id": webhook_id}
if url:
payload["url"] = url
if events:
payload["events"] = events
if config:
payload["config"] = config
return self._execute("update_webhook", payload)
def delete_webhook(self, webhook_id: str) -> dict:
return self._execute("delete_webhook", {
"webhook_id": webhook_id,
})
def get_webhook_logs(
self,
webhook_id: str,
limit: int = 50,
) -> dict:
return self._execute("get_webhook_logs", {
"webhook_id": webhook_id,
"limit": limit,
})
class BudgetExhaustedError(Exception):
"""Raised when an agent exceeds its budget cap (HTTP 402)."""
pass
Chapter 2: Per-Agent Wallet Provisioning
Why One Wallet Per Agent
Shared wallets are the multi-agent equivalent of running all your microservices as root. When five agents share a wallet, a runaway agent drains funds that other agents need. There is no spend attribution, no blast radius containment, and no way to set different budget policies for agents with different risk profiles.
The rule is simple: every agent that can incur cost gets its own wallet. The orchestrator agent gets a wallet. Each worker agent gets a wallet. If the orchestrator funds worker wallets as part of task delegation, the funding amount becomes an explicit cost parameter of the task -- visible, auditable, and capped.
Creating Wallets for a Fleet
import os
API_KEY = os.environ["GREENHELIX_API_KEY"]
# Define your agent fleet
fleet = [
{"agent_id": "orchestrator-01", "initial_deposit": 500.00},
{"agent_id": "researcher-01", "initial_deposit": 100.00},
{"agent_id": "researcher-02", "initial_deposit": 100.00},
{"agent_id": "summarizer-01", "initial_deposit": 75.00},
{"agent_id": "classifier-01", "initial_deposit": 50.00},
]
for agent_cfg in fleet:
finops = AgentFinOps(
api_key=API_KEY,
agent_id=agent_cfg["agent_id"],
)
# Create wallet
wallet = finops.create_wallet()
print(f"Wallet created for {agent_cfg['agent_id']}: {wallet['wallet_id']}")
# Fund it
deposit = finops.deposit(amount=agent_cfg["initial_deposit"])
print(f" Deposited ${agent_cfg['initial_deposit']:.2f}")
# Verify balance
balance = finops.get_balance()
print(f" Balance: ${balance['balance']}")
Pre-Flight Cost Estimation
Before an agent executes an expensive tool call, estimate the cost and compare it against the remaining budget. This prevents the agent from starting work it cannot afford to finish.
def preflight_check(finops: AgentFinOps, tool_name: str, params: dict) -> bool:
"""Check if the agent can afford a tool call before executing it."""
# Estimate the cost of the upcoming operation
estimate = finops.estimate_cost(tool_name=tool_name, parameters=params)
estimated_cost = float(estimate.get("estimated_cost", 0))
# Check remaining budget
budget = finops.get_budget_status()
remaining_daily = (
float(budget.get("daily_limit", 0))
- float(budget.get("spent_today", 0))
)
# Check wallet balance
balance = finops.get_balance()
wallet_balance = float(balance.get("balance", 0))
# Both budget and balance must be sufficient
can_afford = (
estimated_cost <= remaining_daily
and estimated_cost <= wallet_balance
)
if not can_afford:
print(
f"Pre-flight FAIL: {tool_name} costs ~${estimated_cost:.4f}, "
f"daily remaining=${remaining_daily:.2f}, "
f"wallet=${wallet_balance:.2f}"
)
return can_afford
# Usage in an agent loop
finops = AgentFinOps(api_key=API_KEY, agent_id="researcher-01")
tasks = [
("search_services", {"query": "document summarization"}),
("create_escrow", {"amount": "25.00", "payee": "summarizer-01"}),
("submit_metrics", {"metrics": {"accuracy": 0.95}}),
]
for tool_name, params in tasks:
if preflight_check(finops, tool_name, params):
result = finops._execute(tool_name, params)
print(f" Executed {tool_name}: OK")
else:
print(f" Skipped {tool_name}: insufficient budget")
break # Stop the workflow, do not accumulate partial state
Funding Workflows: Orchestrator-to-Worker Deposits
In many architectures, the orchestrator agent funds worker agents as part of task assignment. This creates an explicit cost boundary around each task.
def fund_worker_for_task(
orchestrator: AgentFinOps,
worker_agent_id: str,
task_budget: float,
api_key: str,
) -> AgentFinOps:
"""Fund a worker agent's wallet for a specific task."""
worker = AgentFinOps(
api_key=api_key,
agent_id=worker_agent_id,
)
# Estimate worker's current balance
balance = worker.get_balance()
current = float(balance.get("balance", 0))
# Top up only what is needed
if current < task_budget:
shortfall = task_budget - current
worker.deposit(amount=shortfall)
print(
f"Funded {worker_agent_id}: +${shortfall:.2f} "
f"(new balance: ${task_budget:.2f})"
)
# Set a tight budget cap for this task
worker.set_budget_cap(daily_limit=task_budget)
return worker
# Orchestrator delegates a research task with a $15 budget
orchestrator = AgentFinOps(api_key=API_KEY, agent_id="orchestrator-01")
worker = fund_worker_for_task(
orchestrator=orchestrator,
worker_agent_id="researcher-01",
task_budget=15.00,
api_key=API_KEY,
)
Chapter 3: Budget Caps and Hard Stops
Per-Agent Budget Caps
Budget caps are the most important cost governance primitive. When an agent exceeds its cap, the gateway returns 402 Payment Required on the next tool call. The agent's code catches this as a BudgetExhaustedError and can implement any fail-fast behavior: log the event, notify the orchestrator, gracefully terminate, or queue the remaining work for the next budget cycle.
finops = AgentFinOps(api_key=API_KEY, agent_id="researcher-01")
# Set daily and monthly caps
finops.set_budget_cap(daily_limit=25.00, monthly_limit=500.00)
# Verify the cap is active
status = finops.get_budget_status()
print(f"Daily limit: ${status['daily_limit']}")
print(f"Monthly limit: ${status['monthly_limit']}")
print(f"Spent today: ${status['spent_today']}")
print(f"Spent this month: ${status['spent_this_month']}")
curl -- set budget cap:
curl -s -X POST https://sandbox.greenhelix.net/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GREENHELIX_API_KEY" \
-d '{
"tool": "set_budget_cap",
"input": {
"agent_id": "researcher-01",
"daily_limit": "25.00",
"monthly_limit": "500.00"
}
}'
Per-Workflow Budget Caps
Sometimes you need a budget cap on a workflow, not just an individual agent. The pattern: create a dedicated agent ID per workflow run, give it a wallet with exactly the workflow budget, and route all tool calls through it.
import uuid
from datetime import datetime, timezone
def create_workflow_budget(
api_key: str,
workflow_name: str,
budget: float,
) -> AgentFinOps:
"""Create a budget-capped agent for a single workflow run."""
run_id = uuid.uuid4().hex[:8]
workflow_agent_id = f"wf-{workflow_name}-{run_id}"
finops = AgentFinOps(
api_key=api_key,
agent_id=workflow_agent_id,
)
finops.create_wallet()
finops.deposit(amount=budget)
finops.set_budget_cap(daily_limit=budget) # Entire budget as one-shot
print(
f"Workflow {workflow_name} ({run_id}): "
f"${budget:.2f} budget allocated"
)
return finops
# Create a $50 budget for a research workflow
wf_finops = create_workflow_budget(
api_key=API_KEY,
workflow_name="quarterly-report",
budget=50.00,
)
Handling 402 Payment Required
When the budget cap is hit, the gateway returns HTTP 402. Your agent code must handle this gracefully -- not with a retry, but with a controlled shutdown.
def safe_execute(finops: AgentFinOps, tool: str, input_data: dict) -> dict:
"""Execute a tool with budget-aware error handling."""
try:
return finops._execute(tool, input_data)
except BudgetExhaustedError:
# Log the budget exhaustion event
print(
f"BUDGET EXHAUSTED: Agent {finops.agent_id} hit cap "
f"while calling {tool}. Stopping execution."
)
# Return a sentinel that the calling code can check
return {"error": "budget_exhausted", "tool": tool}
except requests.exceptions.HTTPError as e:
if e.response.status_code == 429:
# Rate limited -- back off and retry
time.sleep(2)
return finops._execute(tool, input_data)
raise
# Agent loop with budget-aware execution
finops = AgentFinOps(api_key=API_KEY, agent_id="researcher-01")
for i in range(100): # Agent might try 100 tool calls
result = safe_execute(finops, "search_services", {"query": f"topic-{i}"})
if result.get("error") == "budget_exhausted":
print(f"Stopped at iteration {i}. Budget exhausted.")
break
# Process result normally
Setting Budget Caps Across a Fleet
# Define tiered budget policies
BUDGET_TIERS = {
"orchestrator": {"daily": 100.00, "monthly": 2000.00},
"researcher": {"daily": 25.00, "monthly": 500.00},
"summarizer": {"daily": 15.00, "monthly": 300.00},
"classifier": {"daily": 10.00, "monthly": 200.00},
}
def apply_fleet_budget_policy(api_key: str, agents: list[dict]):
"""Apply budget caps to all agents based on their role tier."""
for agent in agents:
role = agent["role"]
tier = BUDGET_TIERS.get(role)
if not tier:
print(f"WARNING: No budget tier for role '{role}'. Skipping.")
continue
finops = AgentFinOps(api_key=api_key, agent_id=agent["agent_id"])
finops.set_budget_cap(
daily_limit=tier["daily"],
monthly_limit=tier["monthly"],
)
print(
f" {agent['agent_id']} ({role}): "
f"${tier['daily']}/day, ${tier['monthly']}/month"
)
agents = [
{"agent_id": "orchestrator-01", "role": "orchestrator"},
{"agent_id": "researcher-01", "role": "researcher"},
{"agent_id": "researcher-02", "role": "researcher"},
{"agent_id": "summarizer-01", "role": "summarizer"},
{"agent_id": "classifier-01", "role": "classifier"},
]
apply_fleet_budget_policy(API_KEY, agents)
Chapter 4: Real-Time Spend Alerts with Webhooks
Why Polling Is Not Enough
Checking get_budget_status inside your agent loop works for pre-flight checks, but it misses spend that happens between checks. If your agent makes ten tool calls in rapid succession and the budget cap is hit on call seven, calls eight through ten fail with 402. Webhooks push alerts to your system the moment a threshold is crossed, enabling real-time escalation -- warn the team at 75%, pause the agent at 90%, kill it at 100%.
Registering Budget Threshold Alerts
finops = AgentFinOps(api_key=API_KEY, agent_id="researcher-01")
# Register three escalation tiers
alert_tiers = [
{"threshold_pct": 75, "label": "warning"},
{"threshold_pct": 90, "label": "critical"},
{"threshold_pct": 100, "label": "exhausted"},
]
webhook_ids = []
for tier in alert_tiers:
webhook = finops.register_webhook(
url=f"https://your-app.example.com/alerts/{tier['label']}",
events=["budget.threshold"],
config={"threshold_pct": tier["threshold_pct"]},
)
webhook_ids.append(webhook["webhook_id"])
print(
f"Alert registered: {tier['label']} at {tier['threshold_pct']}% "
f"(webhook_id: {webhook['webhook_id']})"
)
curl -- register a webhook:
curl -s -X POST https://sandbox.greenhelix.net/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GREENHELIX_API_KEY" \
-d '{
"tool": "register_webhook",
"input": {
"agent_id": "researcher-01",
"url": "https://your-app.example.com/alerts/warning",
"events": ["budget.threshold"],
"config": {"threshold_pct": 75}
}
}'
Building the Alert Receiver
Your alert receiver is a simple HTTP endpoint that receives webhook payloads and dispatches escalation actions.
from flask import Flask, request, jsonify
import logging
app = Flask(__name__)
logger = logging.getLogger("finops_alerts")
@app.route("/alerts/warning", methods=["POST"])
def handle_warning():
"""75% budget consumed -- log and notify Slack."""
payload = request.json
agent_id = payload.get("agent_id")
spent_pct = payload.get("spent_pct")
remaining = payload.get("remaining_budget")
logger.warning(
f"BUDGET WARNING: {agent_id} at {spent_pct}% "
f"(${remaining} remaining)"
)
# Send Slack/PagerDuty notification
notify_slack(
channel="#agent-finops",
message=f"Agent {agent_id} has consumed {spent_pct}% of its daily budget. "
f"${remaining} remaining.",
)
return jsonify({"status": "acknowledged"})
@app.route("/alerts/critical", methods=["POST"])
def handle_critical():
"""90% budget consumed -- pause the agent."""
payload = request.json
agent_id = payload.get("agent_id")
logger.critical(
f"BUDGET CRITICAL: {agent_id} at {payload.get('spent_pct')}%. "
f"Pausing agent."
)
# Signal the agent to pause (via shared state, message queue, etc.)
pause_agent(agent_id)
notify_slack(
channel="#agent-finops",
message=f"CRITICAL: Agent {agent_id} paused at 90% budget.",
)
return jsonify({"status": "agent_paused"})
@app.route("/alerts/exhausted", methods=["POST"])
def handle_exhausted():
"""100% budget consumed -- kill the agent process."""
payload = request.json
agent_id = payload.get("agent_id")
logger.error(
f"BUDGET EXHAUSTED: {agent_id}. Terminating."
)
kill_agent(agent_id)
notify_slack(
channel="#agent-finops",
message=f"EXHAUSTED: Agent {agent_id} terminated. Budget fully consumed.",
)
return jsonify({"status": "agent_terminated"})
def notify_slack(channel: str, message: str):
"""Send a Slack notification. Replace with your Slack webhook."""
import requests as req
req.post(os.environ.get("SLACK_WEBHOOK_URL", ""), json={
"channel": channel,
"text": message,
})
def pause_agent(agent_id: str):
"""Signal an agent to pause. Implementation depends on your runtime."""
# Example: write a pause flag to Redis
# redis_client.set(f"agent:{agent_id}:paused", "1", ex=3600)
pass
def kill_agent(agent_id: str):
"""Terminate an agent process. Implementation depends on your runtime."""
# Example: send SIGTERM to the agent's PID
# os.kill(agent_pids[agent_id], signal.SIGTERM)
pass
Auditing Webhook Configuration
Before relying on webhooks in production, verify they are correctly configured.
finops = AgentFinOps(api_key=API_KEY, agent_id="researcher-01")
# List all registered webhooks
webhooks = finops.list_webhooks()
for wh in webhooks.get("webhooks", []):
print(
f" ID: {wh['webhook_id']} | URL: {wh['url']} | "
f"Events: {wh['events']} | Config: {wh.get('config', {})}"
)
curl -- list webhooks:
curl -s -X POST https://sandbox.greenhelix.net/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GREENHELIX_API_KEY" \
-d '{
"tool": "list_webhooks",
"input": {"agent_id": "researcher-01"}
}'
Adjusting Thresholds Dynamically
As your fleet evolves, you may need to tighten or relax alert thresholds. Use update_webhook to adjust without deleting and re-creating.
# Tighten the warning threshold from 75% to 60%
finops.update_webhook(
webhook_id=webhook_ids[0],
config={"threshold_pct": 60},
)
print("Warning threshold tightened to 60%")
Debugging Missed Alerts
When an alert should have fired but did not, check the webhook logs.
# Inspect delivery history for a specific webhook
logs = finops.get_webhook_logs(webhook_id=webhook_ids[0], limit=20)
for entry in logs.get("logs", []):
print(
f" {entry['timestamp']} | Status: {entry['delivery_status']} | "
f"HTTP {entry.get('response_code', 'N/A')}"
)
curl -- get webhook logs:
curl -s -X POST https://sandbox.greenhelix.net/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GREENHELIX_API_KEY" \
-d '{
"tool": "get_webhook_logs",
"input": {"webhook_id": "wh_abc123", "limit": 20}
}'
Cleaning Up Stale Webhooks
When decommissioning an agent, remove its webhooks to prevent orphaned alert traffic.
def cleanup_agent_webhooks(finops: AgentFinOps):
"""Remove all webhooks for an agent being decommissioned."""
webhooks = finops.list_webhooks()
for wh in webhooks.get("webhooks", []):
finops.delete_webhook(wh["webhook_id"])
print(f" Deleted webhook {wh['webhook_id']}")
Chapter 5: Cost Attribution and Category Spend
Why Attribution Matters
Budget caps prevent overspend. Attribution answers a different question: where is the money going? Without category-level spend data, you cannot optimize. You cannot answer "which tool category consumes 60% of our budget?" or "which agent has the worst cost-per-task ratio?" or "did last week's prompt change increase or decrease total spend?"
Tagging Spend by Agent, Workflow, and Tool
GreenHelix tracks spend at the agent level natively. Every tool call executed by an agent is attributed to that agent's wallet. To get workflow-level attribution, use the dedicated workflow agent pattern from Chapter 3. To get tool-level attribution, use get_spending_by_category.
finops = AgentFinOps(api_key=API_KEY, agent_id="researcher-01")
# Get spend breakdown by tool category
category_spend = finops.get_spending_by_category(
start_date="2026-04-01",
end_date="2026-04-06",
)
print("Spend by category (April 1-6):")
for category in category_spend.get("categories", []):
print(
f" {category['category']:.<30} "
f"${category['total_cost']:>8.2f} "
f"({category['call_count']} calls)"
)
curl -- get spending by category:
curl -s -X POST https://sandbox.greenhelix.net/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GREENHELIX_API_KEY" \
-d '{
"tool": "get_spending_by_category",
"input": {
"agent_id": "researcher-01",
"start_date": "2026-04-01",
"end_date": "2026-04-06"
}
}'
Building Chargeback Reports
In organizations where different teams own different agents, chargebacks attribute platform costs to the team that caused them. This is standard FinOps practice for cloud infrastructure, adapted for multi-agent systems.
def generate_chargeback_report(
api_key: str,
team_agents: dict[str, list[str]],
period: str = "monthly",
) -> dict:
"""Generate a chargeback report by team.
team_agents: {"data-team": ["researcher-01", "researcher-02"],
"ml-team": ["classifier-01", "summarizer-01"]}
"""
report = {}
for team, agent_ids in team_agents.items():
team_total = 0.0
agent_details = []
for agent_id in agent_ids:
finops = AgentFinOps(api_key=api_key, agent_id=agent_id)
summary = finops.get_billing_summary(period=period)
agent_cost = float(summary.get("total_cost", 0))
team_total += agent_cost
agent_details.append({
"agent_id": agent_id,
"cost": agent_cost,
"tool_calls": summary.get("total_calls", 0),
})
report[team] = {
"total_cost": round(team_total, 2),
"agents": agent_details,
}
return report
# Generate monthly chargeback
chargeback = generate_chargeback_report(
api_key=API_KEY,
team_agents={
"data-team": ["researcher-01", "researcher-02"],
"ml-team": ["classifier-01", "summarizer-01"],
"ops-team": ["orchestrator-01"],
},
)
for team, data in chargeback.items():
print(f"\n{team}: ${data['total_cost']:.2f}")
for agent in data["agents"]:
print(
f" {agent['agent_id']}: ${agent['cost']:.2f} "
f"({agent['tool_calls']} calls)"
)
Per-Agent P&L Statements
For agents that both spend and earn (e.g., a service agent that charges for its work), compute a per-agent profit and loss.
def agent_pnl(api_key: str, agent_id: str, period: str = "monthly") -> dict:
"""Compute profit and loss for an agent."""
finops = AgentFinOps(api_key=api_key, agent_id=agent_id)
# Cost side: what the agent spent
summary = finops.get_billing_summary(period=period)
total_cost = float(summary.get("total_cost", 0))
# Revenue side: what the agent earned (from usage analytics)
analytics = finops.get_usage_analytics(
start_date=summary.get("period_start", "2026-04-01"),
end_date=summary.get("period_end", "2026-04-30"),
)
total_revenue = float(analytics.get("revenue_earned", 0))
return {
"agent_id": agent_id,
"revenue": round(total_revenue, 2),
"cost": round(total_cost, 2),
"profit": round(total_revenue - total_cost, 2),
"margin_pct": (
round((total_revenue - total_cost) / total_revenue * 100, 1)
if total_revenue > 0 else 0.0
),
}
# Compute P&L for a service agent
pnl = agent_pnl(API_KEY, "summarizer-01")
print(
f"Agent {pnl['agent_id']}: "
f"Revenue=${pnl['revenue']}, Cost=${pnl['cost']}, "
f"Profit=${pnl['profit']} ({pnl['margin_pct']}% margin)"
)
Historical Spend Analysis
Use get_usage_analytics for time-series spend data to identify trends, anomalies, and the impact of configuration changes.
finops = AgentFinOps(api_key=API_KEY, agent_id="researcher-01")
# Pull weekly analytics for the last 4 weeks
weeks = [
("2026-03-09", "2026-03-15"),
("2026-03-16", "2026-03-22"),
("2026-03-23", "2026-03-29"),
("2026-03-30", "2026-04-05"),
]
print("Weekly spend trend for researcher-01:")
for start, end in weeks:
analytics = finops.get_usage_analytics(start_date=start, end_date=end)
cost = float(analytics.get("total_cost", 0))
calls = analytics.get("total_calls", 0)
print(f" {start} to {end}: ${cost:.2f} ({calls} calls)")
Chapter 6: Volume Discounts and Cost Optimization
Checking Volume Discount Eligibility
High-volume agents may qualify for automatic discounts based on cumulative usage. Check your current tier and what it takes to reach the next one.
finops = AgentFinOps(api_key=API_KEY, agent_id="orchestrator-01")
discount = finops.get_volume_discount()
print(f"Current tier: {discount.get('current_tier')}")
print(f"Discount rate: {discount.get('discount_pct')}%")
print(f"Monthly volume: ${discount.get('monthly_volume')}")
print(f"Next tier at: ${discount.get('next_tier_threshold')}")
print(f"Next tier discount: {discount.get('next_tier_discount_pct')}%")
curl -- check volume discount:
curl -s -X POST https://sandbox.greenhelix.net/v1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GREENHELIX_API_KEY" \
-d '{
"tool": "get_volume_discount",
"input": {"agent_id": "orchestrator-01"}
}'
Pre-Execution Cost Estimation
Before choosing which tool to use for a task, estimate the cost of each option. This enables cost-aware routing: the orchestrator picks the cheapest tool that meets quality requirements.
def cheapest_tool(
finops: AgentFinOps,
candidates: list[dict],
) -> dict:
"""Pick the
…(truncated)