Your AI agent now has an API key and a very long to-do list. The more autonomous it gets — scheduled jobs, background workers, and human-in-the-loop purchases — the more important explicit limits become. A runaway loop can consume tool allowances or credits much faster than intended.
Agent Media Tools gives every agent key a real spend policy: daily caps in dollars and credits, per-purchase limits, item allowlists, approval thresholds, and a hard kill switch. All of it is readable by the agent itself over REST, and all of it is verifiable in the Toolbox or with two curl commands. This post shows you exactly how to monitor usage, set guardrails, and rotate keys when things go sideways.
Humans stop and think before clicking "buy". Agents don't. An agent reads an instruction, calls a tool, and moves on. If the tool is a paid one, the charge is instant. That's why the key you give a worker bot should never be an unlimited key, and why the platform lets you set limits at the key level instead of only at the account level. You can have one key for your interactive session (loose limits) and another for the overnight batch worker (tight limits, approval required over a few cents).
Create an agent key in the Toolbox (/app → Agent Keys), or with POST /api/agent/keys from a logged-in session. Keys look like mt_... and are sent as a Bearer token:
export AMT_KEY="mt_xxxxxxxxxxxxxxxx" curl -s https://agentmediatools.com/api/agent/usage \ -H "Authorization: Bearer $AMT_KEY" | python3 -m json.tool
GET /api/agent/usage is the first thing your agent should call on startup. It returns your plan, how many calls you've used today, the daily limit, what's remaining, a percentage, your credit summary, and even a suggested action (for example consider_upgrade when you're almost out of free calls). Counts reset at midnight UTC, so a scheduled job can check it before every run and back off instead of erroring out.
The same shape in Python:
import os
import requests
KEY = os.environ["AMT_KEY"]
r = requests.get(
"https://agentmediatools.com/api/agent/usage",
headers={"Authorization": f"Bearer {KEY}"},
)
print(r.json()["used_today"], "/", r.json()["daily_limit"], "calls used today")
Every key has a stored policy. GET /api/agent/policy returns the policy plus today's actual spend in both cents and credits:
curl -s https://agentmediatools.com/api/agent/policy \ -H "Authorization: Bearer $AMT_KEY" | python3 -m json.tool
You'll get something like this (fields abbreviated):
{
"success": true,
"policy": {
"purchase_consent": true,
"max_purchase_cents": 5000,
"allowed_items": [],
"daily_spend_cents": 0,
"daily_credit_spend_limit": 0,
"require_approval_over_cents": 0,
"kill_switch": false,
"notify_channels": { "email": null, "discord_webhook": null, "telegram_bot_token": null, "telegram_chat_id": null }
},
"today": {
"spent_cents": 0,
"credits_spent": 0,
"remaining_spend_cents": null,
"remaining_credits_budget": null
}
}
Every field means something concrete when a purchase is attempted:
| Field | What it does |
|---|---|
purchase_consent | Master switch. Off means the key can never buy anything (403 NO_CONSENT). |
max_purchase_cents | Ceiling for a single purchase in US cents (default 5000 = $50). |
allowed_items | Allowlist of purchasable item IDs. Empty means any item within other limits. |
daily_spend_cents | Total money cap per UTC day. 0 = no cap. |
daily_credit_spend_limit | Cap on paid credits per day. 0 = no cap. |
require_approval_over_cents | Purchases above this amount pause and ask a human. 0 = never ask. |
kill_switch | Hard stop on all purchases until a human turns it off. |
Policies are written by the human who owns the key (session-authenticated, not agent-authenticated — deliberately). From a logged-in browser session, POST /api/agent/keys/:id/spend-policy accepts any subset of the fields:
# Lock the overnight worker to $1/day, 20 credits/day, and ask before anything over $0.50
curl -s -X POST https://agentmediatools.com/api/agent/keys/KEY_ID/spend-policy \
-b cookies.txt -H "Content-Type: application/json" \
-d '{"daily_spend_cents": 100,
"daily_credit_spend_limit": 20,
"require_approval_over_cents": 50}' | python3 -m json.tool
You can also restrict which items the key may buy at all:
curl -s -X POST https://agentmediatools.com/api/agent/keys/KEY_ID/spend-policy \
-b cookies.txt -H "Content-Type: application/json" \
-d '{"allowed_items": ["credits-100"]}' | python3 -m json.tool
Every policy change is recorded as a signed policy receipt on the key (kind policy, action policy.update), so there's an audit trail of who tightened what, and when. You can review receipts with GET /api/agent/receipts.
If you'd rather click than curl, all of this lives in the Toolbox UI under your agent key settings — same fields, same result.
When require_approval_over_cents trips, the platform creates an approval request and fans it out to the notify channels configured on the key. Set them with POST /api/agent/keys/:id/notify-channels (Discord webhook, Telegram bot + chat, or plain email):
curl -s -X POST https://agentmediatools.com/api/agent/keys/KEY_ID/notify-channels \
-b cookies.txt -H "Content-Type: application/json" \
-d '{"discord_webhook": "https://discord.com/api/webhooks/123/abc",
"telegram_bot_token": "123456:ABC-DEF",
"telegram_chat_id": "@ops-alerts"}' | python3 -m json.tool
Now a $4 purchase attempt from a worker bot lands as an approve/deny link in your ops channel instead of silently hitting your card. The full approval flow is covered in Human-in-the-Loop Approvals for AI Agents.
When a key is compromised — or an experiment goes feral — you have three speeds of response:
{"kill_switch": true} on the spend-policy endpoint. Instantly blocks all purchases while still letting the key use free tools. Good for "pause spending now, investigate later".POST /api/agent/keys/:id/rotate revokes the old key and returns a fresh mt_... with the same name and plan. Use this when a key leaked in logs or a chat transcript.POST /api/agent/keys/:id/revoke deactivates the key; DELETE /api/agent/keys/:id removes it after the server safely reconciles linked records. Prefer revocation when retaining history matters.# Rotate immediately after a suspected leak curl -s -X POST https://agentmediatools.com/api/agent/keys/KEY_ID/rotate \ -b cookies.txt | python3 -m json.tool
Part of cost control is knowing a worker is still alive versus silently stuck in a paid retry loop. POST /api/agent/heartbeat lets the agent report its status to the presence dashboard:
curl -s -X POST https://agentmediatools.com/api/agent/heartbeat \
-H "Authorization: Bearer $AMT_KEY" -H "Content-Type: application/json" \
-d '{"status": "working",
"session_type": "worker",
"activity_hint": "processing 40 invoices",
"note": "nightly batch, policy-capped"}' | python3 -m json.tool
Statuses are online, working, queued, idle, offline, and stuck; session types are always_on, live_session, and worker. A stuck overnight job with a spend cap is a notification, not an invoice.
If your agent talks MCP instead of raw HTTP, the same controls are exposed as tools on the hosted MCP server: get_spend_policy returns the policy and today's spend, agent_heartbeat updates presence, and request_approval/get_approval drive the human-in-the-loop flow. Setup is covered in Connect Claude to Agent Media Tools in 5 Minutes.
A budget is not a limit until something enforces it. Agent Media Tools enforces spend policies at the key level, the agent can read its own limits before acting, and you can flip a kill switch from your phone the moment a number looks wrong. Five minutes of setup — a daily dollar cap, an approval threshold, a Discord webhook — is the difference between "the agent did something expensive" and "the agent asked first".
Create a key, read /api/agent/policy once, and tighten the caps before your next scheduled job starts.
Create an agent key, set its spend policy, and run the same tools in the browser — or call them from your agent with an API key.
Open toolbox