Ship telemetry fast with LLM cost tracking and OpenAI cost monitoring. Request-level budget alerts are available on Pro+ plans.
API responses include budgetWarning (warning threshold) and budgetExceeded, which tell your SDK/UI that a soft-stop threshold (daily or monthly) was reached. Use plan metadata to surface a polite toast or upgrade call-to-action instead of blocking the workflow.
Plan limits are request-based; budget limits stay USD-based and apply to spend controls only.
Alert delivery supports immediate, daily summary, and weekly 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.
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.
// 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.budgetWarning) {
showToast('Budget warning threshold reached', 'warning', 'Consider upgrading to Pro.');
}
if (payload.budgetExceeded) {
showToast('Budget reached', 'warning', 'Upgrade to Pro to lift the limit.');
}
if (payload.planLimitRequests > 0 && payload.freeLimitRemainingRequests <= 0) {
showUpgradeBanner('Telemetry paused. Plan limit reached.');
} 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 |
| 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