Opsmeter logo
Opsmeter
AI Cost & Inference Control
Integration docs

Developer Docs

Ship telemetry fast with LLM cost tracking and OpenAI cost monitoring. Request-level budget alerts are available on Pro+ plans.

Updated for 2026API v1GitHub

Budget alert messaging

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.

Billing plan change flow

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

  • Upgrade/downgrade requests are confirmed in-app and then move to pending_webhook.
  • Final amount and proration are calculated by Lemon.
  • Cancellation is period-end: access continues until endsAt.

Rate limits and backoff

Ingest rate limits are plan-based and evaluated per workspace. These limits throttle telemetry only; your provider LLM requests continue.

PlanIngest rate limit
Free120 req/min
Pro600 req/min
Team3000 req/min
EnterpriseCustom (config/workspace policy)

When ingest returns 429, read Retry-After and retry telemetry later with backoff. Do not block your main user flow.

HeaderMeaning
Retry-AfterSeconds to wait before the next ingest retry after 429.
X-RateLimit-LimitCurrent per-minute ingest limit for the workspace.
X-RateLimit-RemainingRemaining ingest requests in the current window.
X-RateLimit-ResetUnix timestamp (UTC seconds) when the window resets.
Node.js backoff snippet
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
  }
}
.NET backoff snippet
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
  }
}
Python backoff snippet
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