API analytics by customer and endpoint
Updated October 20, 2026
API analytics for a paid API should answer three questions: who is calling, which endpoints they use, and what happened to each request. With UsageRail, one middleware in your API server counts every request by customer, endpoint and outcome, and your dashboard shows those numbers next to each customer's quota and billing. Counting and quotas work today; the billing side, through Stripe, isn't live yet.
What API analytics should show
If you sell API access, traffic graphs aren't enough. Useful API usage analytics tie each request to a customer and a price:
| Question | What to look at |
|---|---|
| Who uses the API, and how much? | Requests and units per customer, per day |
| Which endpoints matter? | Requests per endpoint, grouped by method and route template |
| Is anything failing? | Outcomes: 2xx, 3xx, 4xx, 5xx, and requests rejected before your handler ran |
| Who is about to hit a limit? | Usage against each customer's quota and rate limit |
| What will each customer pay? | This period's usage, priced against their plan |
Two details make these numbers usable. First, group endpoints by route template (GET /v1/users/:id), not by raw path (/v1/users/8231), or every ID becomes its own row. OpenTelemetry's HTTP conventions make the same call: its http.route attribute is "the matched route template" and must be low-cardinality. Second, count in the unit you charge for. If you price per token or per page, request counts alone say little about revenue.
What UsageRail records
The SDK counts each request in memory and groups the counts by four things:
| Dimension | What it holds |
|---|---|
| Customer | The customer who owns the API key, or your own customer ID (hashed by default) if you keep your own authentication |
| Endpoint | HTTP method plus route template. Past 500 distinct routes, the rest are grouped as _other |
| Outcome | 2xx, 3xx, 4xx, 5xx or aborted, plus four rejections the SDK makes itself: a key that's invalid, revoked or expired; a customer you've suspended; a rate limit or quota reached; prepaid credits used up |
| Minute | The minute the request started |
Each group holds two numbers: the request count and the units. A request counts as 1 unit unless you say otherwise. Call track(units) in a handler to count tokens, rows or pages instead, or give a route a fixed weight, such as 10 units per call to an image endpoint.
Only 2xx and 3xx responses count toward billing. Client errors, server errors, aborted requests and the SDK's own rejections are recorded so you can see them, but never billed. A WebSocket connection counts once, when it opens.
How the counts feed limits and invoices
Quotas and invoices use the billable part of those counts (2xx and 3xx), and after each period UsageRail checks what Stripe billed against its own total:
- A stop-at-limit plan answers a customer who has used up the period's quota with a 429 (
quota_exceeded) and aRetry-Afterthat runs to the end of the period. A prepaid plan returns a 402 (insufficient_credits) when the balance runs out. An overage plan doesn't stop customers at the quota. It bills the extra at the end of the period, and rate limits still apply. - At 80% and 100% of a quota, the customer gets an email and you get a webhook. You can change the percentages.
- Two hours after a billing period ends, UsageRail sends Stripe one usage event per customer, and it shows up on that customer's Stripe invoice. Mid-period usage is visible in UsageRail (your dashboard, the customer portal and the usage widget), not in Stripe's upcoming invoice. Metered billing explains the period-end model.
- Each customer sees their own daily usage and a breakdown by endpoint in the customer portal, so "why is my bill higher this month?" has an answer they can look up.
What we don't collect
The SDK doesn't send us request or response bodies, and it doesn't record IP addresses or raw API keys. We receive per-minute totals, not individual requests, so there's no request log to search. There are no response times either: UsageRail counts usage and doesn't measure latency. If you need traces, latency percentiles or payload inspection, keep your APM or logging tool for that job.
How the SDK collects it
Add one middleware to your API server. In Express it looks like this (the SDK is still in development, so names may change before release):
import { usageRail } from "@usagerail/node/express";
app.use(usageRail({ appKey: process.env.USAGERAIL_APP_KEY, auth: "api-key" }));
app.post("/v1/generate", async (request, response) => {
const result = await generate(request.body);
request.usageRail.track(result.tokens); // optional: count tokens instead of requests
response.json(result);
});What happens after that:
- Requests never pass through UsageRail. The SDK checks keys and limits inside your process and keeps counts in memory.
- Counts are grouped per minute and sent to us in batches every 60 seconds.
- SDKs cover Node.js (Express, Hono, Fastify, Next.js) and Python (FastAPI, Flask, Django), under the MIT license. Other languages can call an HTTP check endpoint, at the cost of one extra network call per request.
- Our design target is under 1 ms of added time per request at p99 once keys and limits are loaded. It stays a target until we publish the benchmark.
- If a process is killed hard (
kill -9, out of memory), up to about 10 minutes of unsent counts are lost and never billed.
How far back you can look depends on your UsageRail plan: 7 days on Free, 30 on Starter, 90 on Growth and 365 on Scale. See pricing.
Other ways to get API analytics
| Approach | Example | Good at | Gaps for a paid API |
|---|---|---|---|
| Gateway access logs | AWS API Gateway | A line per request with the fields you choose | You build the pipeline that turns log lines into per-customer usage, and nothing ties it to billing |
| APM | Datadog | Requests, errors and latency per endpoint, plus traces | Per-customer views need your own span tags, with no link to plans or invoices |
| Product analytics | PostHog | Trends, funnels and retention on events you send | An event per API call adds up fast, and the counts don't drive limits or invoices |
| API analytics tools | Moesif, Apitally | API metrics and request logs from a few lines of middleware. Moesif also inspects payloads and can report usage to Stripe | Another SDK and data pipeline to run next to your keys, limits and billing code |
UsageRail uses the same per-customer counts for API usage tracking, quotas and billing. Keep your existing tools for latency, payload inspection and request logs.
See usage by customer next to what you bill them
Requests by customer, endpoint and outcome, shown next to each customer's quota and this period's bill.
Start freeStripe billing isn't live yet. Keys, rate limits, quotas and the portal work today.