Skip to main content
Squasher works well with OpenRouter because OpenRouter exposes an OpenAI-compatible API and can provide model, token, and cost details for every request. You can integrate in two ways:
  1. Use @squasher-ai/agent in your app or agent runtime
  2. Send Langfuse-style batch events to Squasher’s AI ingest endpoint

Option 1: Agent SDK + OpenRouter

This is the best path when you want session tracking, tool calls, and agent spans in addition to plain generations.
This captures, per step:
  • the generation itself
  • prompt, completion, total, reasoning, and cached input tokens (from the AI SDK’s usage.outputTokenDetails / inputTokenDetails)
  • the model and provider (with the AI SDK’s .chat / .responses suffix stripped)
  • assistant text output (text) and, only with captureReasoning: true, provider-supplied reasoning text (reasoningText)
  • cost in USD, captured automatically when OpenRouter returns it on providerMetadata.openrouter.usage.cost (use @openrouter/ai-sdk-provider or pass providerOptions: { openrouter: { usage: { include: true } } } to enable cost in the response). When the provider doesn’t report cost, Squasher computes it server-side from your token counts × the public model rate table — no extra config required.
  • tool calls and their input/output (sanitized to JSON-safe values, or omitted in privacyMode)
  • the enclosing session / run

Option 2: Direct HTTP ingest (no SDK)

If you don’t want to install an SDK, POST batch events directly. The endpoint is Langfuse-compatible: trace, generation, span, agent, tool, and event types are all accepted in the same batch and arrive on the AI -> Sessions / Requests views the same way an SDK call would.
A complete worked example with cost, reasoning, text, and a tool call:
You can post a single event or a full batch. The same endpoint accepts these type values: Field reference for generation-create:
  • id, traceId, parentObservationId
  • name, model, provider, modelParameters
  • startTime, endTime, completionStartTime (ISO 8601)
  • input, output — any JSON. Put your assistant text under output.text and reasoning text under output.reasoning to surface them in the dashboard.
  • usageDetails — Langfuse-style map. Squasher reads input / prompt_tokens / input_tokens, output / completion_tokens / output_tokens, total, plus output_reasoning_tokens, input_cached_tokens, input_cache_read, input_cache_write, accepted_prediction_tokens, rejected_prediction_tokens.
  • usage — legacy alias supporting promptTokens, completionTokens, totalTokens, totalCost.
  • costDetails — map with input, output, cache_read_input_tokens, total. If you only have a single number, send { "total": 0.00123 }.
  • level (DEFAULT / WARNING / ERROR), statusMessage, version, environment, metadata
  • promptName, promptVersion for prompt-management linking

OpenRouter-specific tips

  • Set provider explicitly to openrouter when you emit custom events.
  • Pass the fully qualified model string (for example openai/gpt-4.1-nano or anthropic/claude-3.5-sonnet).
  • For automatic cost capture through the SDK, either use @openrouter/ai-sdk-provider (which surfaces cost on providerMetadata.openrouter.usage.cost) or pass providerOptions: { openrouter: { usage: { include: true } } } to streamText / generateText.
  • For raw HTTP ingest, send costDetails.total (USD) when you have it.

Cost without doing anything

You don’t have to attach cost yourself. If a generation arrives with token counts but no costDetails / cost_usd / gen_ai.response.cost, Squasher computes the cost server-side from a maintained per-model rate table — the same approach Langfuse and Helicone take. Provider-reported cost always wins over the computed estimate, so if you start sending OpenRouter’s usage.cost later, the dashboard switches to the exact number with no other changes on your side. The rates come from models.dev, the open-source community-maintained AI model database. It covers ~3,700 models across the major frontier providers (OpenAI, Anthropic, Google, x-ai, DeepSeek, Meta-Llama, Mistral, Cohere, Groq, Fireworks, Together, OpenRouter pass-throughs, and ~100 others) with cached-input rates where the provider supports prompt caching. Squasher refreshes model rates regularly. Models that are not in the table show cost 0 until the next refresh; if a model you depend on is missing or mispriced, open a PR on the models.dev repo and the rate flows through automatically.

Verify

After you send traffic, open your project and go to:
  • AI -> Dashboard for aggregate cost, request, and latency charts
  • AI -> Requests for individual generations and tool calls
  • AI -> Sessions to follow a chat/session timeline
  • AI -> Users to break usage down by user

Billing behavior

Squasher counts completed generations as AI requests for plan enforcement and billing.
  • On free plans, Squasher drops additional AI requests after the monthly included quota is exhausted.
  • On paid plans, Squasher keeps ingesting and records overage usage once you go beyond the included monthly AI request quota.