we-fly tracks per-application traffic so app owners can debug their integration and admins can spot misbehaving partners. This page describes what's measured, how to read it, and what triggers admin attention.
What we count
Counters are aggregated per-application, per-calendar-day in UTC and retained for a limited window before older rows are deleted automatically.
| Counter | When it bumps | Notes |
|---|---|---|
tokensIssued | Every successful POST /api/oauth/token, any grant type | Includes refresh-token rotation issuances |
apiCalls | Every authenticated /api/v1/* request that passes rate-limit | Does not include calls that get throttled |
authErrors | 401 responses where we identified the app (expired/revoked tokens, suspended app, unconsented owner) | Surfaced for your debugging; routine token expiry isn't held against your app's health |
scopeErrors | 403 insufficient_scope responses | Counts against error rate |
rateLimitErrors | 429 responses | Counts against error rate |
Counts associated with unidentified tokens (a request with a
garbage Authorization header, or a token from a different service)
are not attributed to any app — there's no way to know which one to
attribute them to.
Error rate
We expose a rolled-up errorRatePct over the window. It reflects the
share of attributable requests that failed for reasons within your
control — chiefly scope errors and rate-limit errors. Routine token
expiry and refresh are not counted against you, so an app with long
user sessions isn't penalised for normal re-auth.
Most healthy integrations sit near zero. A sustained, elevated error rate is worth investigating on your side; if it stays high we may reach out, and persistent abuse can lead to suspension.
Where to see it
Owner view — /developer shows a compact 7-day strip on each app
card with calls / tokens / error rate, and a 30-day daily series when
you open an app. Days with zero traffic are simply omitted from the
series — a charting renderer should fill them with zero rather than
skipping the x-axis tick.
Admin view — /admin/oauth-apps shows the same 7-day strip in
each moderation row. Admins also see active token counts, so a
spike in 429s without proportional growth in active tokens is a
signal worth investigating.
What it cannot tell you
- Latency isn't tracked. If you need P95 latency, instrument on your side and compare against your own clock.
- Per-endpoint breakdowns aren't tracked. We can't tell you
whether your
flights:writecalls or yourflights:readcalls are failing — only the aggregate. Use the response status codes on your side for granular debugging. - Per-user breakdowns aren't tracked. We'd need to attribute events to the resource owner, which is sensitive data the partner cannot see anyway.
- Real-time isn't supported. Counters update asynchronously with a short lag. Don't poll faster than once per minute.
Privacy
Telemetry rows contain only the application ID and counter values — no IPs, no user IDs, no request bodies. Owners see only their own apps; admins see all apps. The same TTL applies to both.
Tuning the error rate on your side
When your error rate is unexpectedly high, look at the breakdown:
- High
scopeErrors: you're requesting scopes you weren't granted. Check the consent screen UI and your stored scope set. - High
rateLimitErrors: you're hitting the per-app or per-endpoint cap. See rate limits — honourRetry-After, cache where you can, and consider a tier upgrade if your use case genuinely needs it. - High
authErrors: usually means tokens are expiring before you refresh. Make sure you refresh at least a minute beforeexpires_inruns out and that you replace your stored refresh token atomically — replays will revoke your chain.