API Meter docs
API Meter is a reverse proxy on Cloudflare's edge. It forwards every request to your API unchanged and records one small event per request: method, normalized endpoint, customer, plan, status and latency.
On this page: Quickstart · Customer and plan headers · Express middleware · Privacy · Limits and pricing
Quickstart: change one base URL
- Sign up with your email, API name and https origin (for example
https://api.acme.dev). You get a slug, a dashboard key and an ownership token. - Serve
https://api.acme.dev/.well-known/api-meter-<token>.txtwith the token as the only body, then click Verify. Until you verify, the proxy answers403 unverified_api. - Point clients at the proxy URL instead of your origin:
# before curl https://api.acme.dev/v1/orders/123 -H "x-api-key: $KEY" # after: same request, same response curl https://api-meter-proxy.marc-cf2.workers.dev/p/acme-orders-1a2b/v1/orders/123 -H "x-api-key: $KEY"
Everything after /p/<slug> is appended to your origin URL, including the query string. Request and response bodies stream straight through. Try it on the demo API:
curl https://api-meter-proxy.marc-cf2.workers.dev/p/demo/v1/orders -H "x-api-key: demo_key_alice"
Your origin receives x-forwarded-host, x-forwarded-prefix and x-msa-proxy-secret (the proxy secret from signup). Check that header if you want to refuse traffic that skips the proxy.
Customer and plan headers
API Meter attributes each request to a customer in this order:
| Priority | Source | Example |
|---|---|---|
| 1 | X-MSA-Customer-Id and X-MSA-Plan response headers from your origin. We strip them before the response reaches the client. | cus_42, pro |
| 2 | x-customer-id and x-customer-plan request headers | set by your SDK |
| 3 | The API key in x-api-key or Authorization: Bearer, stored as a salted hash | k:b43cba44de7d4e92 |
| 4 | No identifier | anonymous |
Customer IDs that look like emails are hashed too. IDs are clipped to 64 characters and plans to 32.
Express middleware option (roadmap)
If you can't change the base URL, a one-file Node/Express middleware will post the same events to API Meter using your ingest key (msi_…, from signup). It's on the roadmap and not released yet. The tagging you'd do in Express today works with the proxy:
app.use((req, res, next) => {
if (req.apiKey) {
res.setHeader('X-MSA-Customer-Id', req.apiKey.customerId);
res.setHeader('X-MSA-Plan', req.apiKey.plan);
}
next();
});
Privacy: what we store
- Stored per request: timestamp, method, normalized endpoint (
/orders/123becomes/orders/:id), customer ID, plan, status, latency, byte counts, 2-letter country. - Never stored: request or response bodies, headers, query strings or IP addresses.
- Hashed: raw API keys and email-like customer IDs (salted HMAC per API). Your signup email is stored as a hash. Dashboard and ingest keys are stored as SHA-256 hashes, so we can't show them again.
- Signup rate limits use a hash of your IP that expires within two hours.
- Data lives on Cloudflare's global network. We bill in CAD and operate from Canada, but we don't offer Canadian data residency.
Limits and pricing
| Plan | Price (CAD) | Included |
|---|---|---|
| Free | CA$0 | 250,000 requests / month |
| Indie | CA$19 / month | 2M requests included, then CA$3 per extra million |
| Higher volume | Same per-million rate | Contact us above 50M / month |
Every plan includes unlimited APIs and seats. Past the free tier we keep forwarding your traffic: we warn at 80%, offer an upgrade at 100% and pause recording at 125%. Your API stays up. Checkout is coming soon, so Indie isn't purchasable yet.
Early-access limits: request bodies up to 100 MB, 30-second origin timeout, origins must be public https hostnames. During early access, events are kept for 7 days and the stats view is sized for demo-scale volume.