Ship telemetry fast, keep attribution stable, and move from ingest to governance without changing your app network path.
Start with direct ingest, validate one stable payload shape, then harden budgets, retries, and incident workflows.
Implementation rhythm
Use quickstart for initial payloads, then operations docs to harden production workflows.
API responses include explicit status fields (reason, telemetryPaused, providerCallsContinue, isPlanLimitReached) and legacy budget flags (budgetWarning, budgetExceeded). Use these fields to branch telemetry behavior without blocking your main user workflow.
Plan limits are request-based; budget limits stay USD-based and apply to spend controls only.
Alert delivery supports immediate, daily budget alert summary, and weekly budget alert summary modes. Workspace admins can configure the schedule (send time + timezone) in Settings so notifications align with operational reporting cadence.
Warning thresholds are configurable in Settings, so teams can tune when budgetWarning fires.
Default operating baseline: Investigate Spike compares the current window to the immediately previous window with the same duration (for example, current 7d vs previous 7d).
Default alert cooldown is 300 seconds (5 minutes). Unit-cost threshold rules are disabled by default until a workspace owner/admin configures them.
Workspace kill switch forces telemetry policy evaluation into observe mode for that workspace. Rules are still evaluated and events/alerts remain visible, but enforce actions (such as runtime blocking) are not applied until the kill switch is turned off.
Weekly budget alert summary delivery is available on Starter and above (same plan family as budget alerts). Weekly executive report is available on Team and above.
Weekly executive report always uses the same fixed window: the last completed 7 UTC days (current week snapshot vs previous 7-day baseline).
Telemetry onboarding controls are split by plan: First-ingest checklist on Starter+ and Tracking quality score on Pro+.
Board pack export is separate from weekly executive report. Use board pack export for custom date ranges when you need ad-hoc reporting windows.
When a plan limit is reached, ingest returns 402 and telemetry is paused. LLM calls keep running; only telemetry ingest is on hold until you upgrade.
Telemetry paused due to plan limit. LLM calls keep running.
If hard-stop budgets are enforced, exceeding the budget can also return 402. Plan limits pause telemetry only, while budget enforcement is configurable per workspace.
| Capability | Direct ingest (available now) | SDK-enabled / runtime (roadmap) |
|---|---|---|
| Spike detection and root cause | Yes (alerts + attribution views) | Yes |
| Budget warning/exceeded workflow | Yes (workspace policies) | Yes |
| Automatic clamp/fallback/queue on request path | No (advisory only) | Yes (enforcement mode) |
// inside your SDK/Client-side code
const payload = await fetch('/v1/ingest/llm-request', {
method: 'POST',
headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify(metadata)
}).then(r => r.json());
if (payload.isBudgetWarning || payload.budgetWarning) {
showToast('Budget warning threshold reached', 'warning', 'Starter and above include basic budget alerts.');
}
if (payload.isBudgetExceeded || payload.budgetExceeded) {
showToast('Budget exceeded', 'warning', 'Review drivers and containment steps. Telemetry stays active unless a separate hard-stop policy is enabled.');
}
if (payload.reason === 'plan_limit_reached' || payload.telemetryPaused === true) {
showUpgradeBanner('Telemetry paused. Plan limit reached. Provider calls continue.');
} The verify-local.sh script now trips the budget flag after loading demo data, ensuring the flag, toast, and soft-stop guidance stay in sync with product behavior.
Active subscription plan changes run in-app via POST /v1/billing/subscription/change-plan. Financial calculations (proration, tax, currency) are always sourced from Lemon Squeezy.
The change request returns pending_webhook. Final plan, status, and renewal dates are confirmed by webhook events (source of truth), so UI can show a short pending state.
Use the billing portal only for payment method and invoices. Plan upgrades/downgrades in product should not rely on portal redirects.
Renewal dates follow Lemon billing rules and may shift after a plan update depending on billing policy.
Billing actions UX
pending_webhook.endsAt.Ingest rate limits are plan-based and evaluated per workspace. These limits throttle telemetry only; your provider LLM requests continue.
| Plan | Ingest rate limit |
|---|---|
| Free | 120 req/min |
| Starter | 300 req/min |
| Pro | 600 req/min |
| Team | 3000 req/min |
| Enterprise | Custom (config/workspace policy) |
When ingest returns 429, read Retry-After and retry telemetry later with backoff. Do not block your main user flow.
| Header | Meaning |
|---|---|
Retry-After | Seconds to wait before the next ingest retry after 429 |
X-RateLimit-Limit | Current per-minute ingest limit for the workspace. |
X-RateLimit-Remaining | Remaining ingest requests in the current window. |
X-RateLimit-Reset | Unix timestamp (UTC seconds) when the window resets. |
async function sendTelemetry(payload, apiKey) {
if (!apiKey) return;
try {
const res = await fetch('https://api.opsmeter.io/v1/ingest/llm-request', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
body: JSON.stringify(payload)
});
if (res.status === 429) {
const retryAfter = Number(res.headers.get('Retry-After') ?? '1');
console.warn(`Telemetry throttled, retry after ${retryAfter}s`);
return;
}
if (res.status === 402) {
console.warn('Telemetry paused due to plan/budget policy.');
return;
}
} catch {
// telemetry must not break your production flow
}
}using System.Net;
using System.Net.Http.Json;
static async Task SendTelemetryAsync(object payload, string apiKey, ILogger logger)
{
if (string.IsNullOrWhiteSpace(apiKey)) return;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", apiKey);
try
{
var res = await http.PostAsJsonAsync("https://api.opsmeter.io/v1/ingest/llm-request", payload);
if (res.StatusCode == HttpStatusCode.TooManyRequests)
{
var retryAfter = (int?)res.Headers.RetryAfter?.Delta?.TotalSeconds ?? 1;
logger.LogWarning("Telemetry throttled, retry after {Seconds}s", retryAfter);
return;
}
if ((int)res.StatusCode == 402)
{
logger.LogWarning("Telemetry paused due to plan/budget policy.");
return;
}
}
catch
{
// telemetry must not break your production flow
}
}import requests
def send_telemetry(payload: dict, api_key: str):
if not api_key:
return
try:
res = requests.post(
"https://api.opsmeter.io/v1/ingest/llm-request",
json=payload,
headers={"X-API-Key": api_key},
timeout=0.6,
)
if res.status_code == 429:
retry_after = int(res.headers.get("Retry-After", "1"))
print(f"Telemetry throttled, retry after {retry_after}s")
return
if res.status_code == 402:
print("Telemetry paused due to plan/budget policy.")
return
except Exception:
# telemetry must not break your production flow
pass Compare pages always show source links and a Last verified date. When verification age reaches 30 days, a Stale badge is shown.
Stale compare pages remain index,follow for SEO continuity, but include an explicit warning so readers can re-check vendor docs before making purchasing decisions.
For incident-response style guidance, see the AI cost spike guide.