Home › Track AI agent API usage per customer
Track AI agent API usage per customer and endpoint
More of your customers now call your API through AI agents, MCP servers and automations as well as through their own apps. That's real usage, and you'll usually want to bill it the same way. What helps is seeing it as its own bucket: how much of Acme's traffic on /v1/orders/:id comes from their agents and how much from their app. Then you can plan capacity, price agent-heavy plans and spot which endpoints agents rely on.
The honest part first: there is no agent field
API Meter records method, normalized endpoint, status, latency, sizes, customer and plan (see ingest docs). There's no separate "agent" or "bot" field. The approach below puts the bucket on the plan label: pro for app traffic, pro-agent for agent traffic. The customer stays the same, so their total is unchanged.
How it works
- Your auth middleware already knows the customer and their plan.
- A small function decides whether the call came from an agent. Prefer signals you control: a separate API key type for agents, an OAuth client type, or a header your own SDK or MCP server sets (for example
x-client-type: agent). A user-agent match is a fallback guess. - Agent calls are sent with
plan: "<plan>-agent". Everything else is sent as usual. - Every request is counted toward the customer's usage either way. Nothing is blocked or filtered.
Snippet: Express with the ingest API
This posts batches to POST /api/ingest/<slug> with your msi_ ingest key, the same endpoint as the standard ingest snippets: up to 500 events per request, a capped queue of 5,000, a 2 s flush and a 5 s timeout, and it fails open so your API never waits on us.
// Express: count AI agent / bot calls per customer and endpoint as their own bucket.
// API Meter has no agent field, so the bucket rides on the plan label: "pro" vs "pro-agent".
const SLUG = process.env.API_METER_SLUG; // your API's slug
const KEY = process.env.API_METER_KEY; // msi_... ingest key (server-side only)
const URL_ = `https://api-meter-lab.pages.dev/api/ingest/${SLUG}`;
const AGENT_UA = /(gpt|claude|anthropic|openai|perplexity|langchain|llamaindex|bot|agent)/i;
// Decide the traffic type. Prefer signals you control (a separate agent API key,
// an OAuth client type, or a header your SDK/MCP server sets); user-agent is a fallback guess.
function trafficType(req) {
if (req.get("x-client-type") === "agent") return "agent";
if (req.apiKey && req.apiKey.kind === "agent") return "agent";
if (AGENT_UA.test(req.get("user-agent") || "")) return "agent";
return "app";
}
let queue = [];
function flush() {
if (!queue.length) return;
const events = queue.splice(0, 500);
fetch(URL_, { method: "POST", headers: { authorization: `Bearer ${KEY}`, "content-type": "application/json" },
body: JSON.stringify({ events }), signal: AbortSignal.timeout(5000) }).catch(() => {}); // fail-open
}
setInterval(flush, 2000).unref();
function apiMeter(req, res, next) {
const t0 = Date.now();
res.on("finish", () => {
const base = (req.customerPlan || "unknown").slice(0, 25);
const type = trafficType(req);
if (queue.length >= 5000) return; // capped queue: drop rather than grow
queue.push({
method: req.method,
path: req.route ? req.baseUrl + req.route.path : req.path, // template, e.g. /v1/orders/:id
status: res.statusCode,
latency_ms: Date.now() - t0,
customer: req.customerId, // same customer either way
plan: type === "agent" ? `${base}-agent` : base, // agent bucket, billed the same
});
if (queue.length >= 500) flush();
});
next();
}
module.exports = { apiMeter, flush };
// app.use(apiMeter) after your auth middleware sets req.customerId / req.customerPlan
Call flush() on shutdown (for example in a SIGTERM handler) so the last batch is sent. Plan labels are lowercased and cut to 32 characters by the API; the snippet trims the base plan to 25 so -agent always fits.
Using the proxy instead
If your traffic goes through the API Meter proxy, return the same label from your origin in the response header X-MSA-Plan (for example X-MSA-Plan: pro-agent) next to X-MSA-Customer-Id. The proxy reads both and strips them before the response reaches the caller.
res.set("X-MSA-Customer-Id", req.customerId);
res.set("X-MSA-Plan", trafficType(req) === "agent" ? `${req.customerPlan}-agent` : req.customerPlan);
Reading the numbers
- Per customer, endpoint and bucket: the detail export (
/api/export?view=detail) has one row per customer × plan × method × endpoint, soacme / proandacme / pro-agentsit side by side for each endpoint. - Per customer total: the customers view (
view=customers) sums all buckets into one row and lists the plans it saw (for examplepro,pro-agent). Use that for invoicing. - Billing: API Meter's own price counts every request, agent or not, per started million above the included amount.
Limits, stated plainly
- The plan column now carries two things (plan tier and traffic type). If you also use plan labels for pricing, strip the
-agentsuffix when you group by tier. - Detection is yours. API Meter doesn't classify traffic. User-agent strings are easy to change and many agents use ordinary HTTP libraries, so a user-agent match will miss some agent calls and may catch some scripts. An agent-specific key or header is far more reliable.
- The proxy doesn't detect agents on its own; it only records the plan label your origin returns.
- One extra bucket per plan only. If you need more types (agent, MCP, batch job), you can use more suffixes, but keep the whole label within 32 characters.
- Beta limits apply: 35 days of per-minute totals, and a shared limit of about 100,000 proxied requests/day across all APIs during the beta.
FAQ
Should I block AI agents?
This guide doesn't cover that. Agents calling your API with a customer's key are that customer's usage, and API Meter counts them like any other request.
Does agent traffic cost more on API Meter?
No. A request is a request; the bucket only changes how it's labelled.
Can I do this with the Python, Django or Go snippets?
Yes. They send the same plan field, so set it to <plan>-agent for agent calls in the same place. See ingest docs.
Try it
Related: API usage analytics per customer · Per-customer usage billing · Ingest docs · Integrations · Compare tools · Track AI agent API usage