Skip to content
Official · LobstackCostv1.0.0MIT

Read a Lobstack receipt

lobstack-receipts

Read the receipt Lobstack returns on every model call — cost_usd, savings_usd, baseline_reason — and report cost from it instead of estimating. Use when a response carries x_lobstack or an x-lobstack-* header, when asked what a call or a run cost, or when a cost renders as $0.00.

#cost#receipts#metering#gateway

Install

Copy the file and save it at the path below, then start a new session. Any agent that reads a skills directory will pick it up; the path shown is Claude Code's. Delete the folder to uninstall.

mkdir -p .claude/skills/lobstack-receipts
# paste SKILL.md into .claude/skills/lobstack-receipts/SKILL.md

No package, no registry client, no telemetry. 179 lines of text, licensed MIT.


What the agent matches on

Frontmatter

An agent decides whether to load a skill from name and description alone — it does not read the body first. That is why the description says when to use this, not only what it is.

---
name: lobstack-receipts
description: "Read the receipt Lobstack returns on every model call — cost_usd, savings_usd, baseline_reason — and report cost from it instead of estimating. Use when a response carries x_lobstack or an x-lobstack-* header, when asked what a call or a run cost, or when a cost renders as $0.00."
license: MIT
metadata:
  title: "Read a Lobstack receipt"
  version: 1.0.0
  author: lobstack
  category: cost
  tags: [cost, receipts, metering, gateway]
---

179 lines · MIT

SKILL.md

.claude/skills/lobstack-receipts/SKILL.md179 lines
---name: lobstack-receiptsdescription: "Read the receipt Lobstack returns on every model call — cost_usd, savings_usd, baseline_reason — and report cost from it instead of estimating. Use when a response carries x_lobstack or an x-lobstack-* header, when asked what a call or a run cost, or when a cost renders as $0.00."license: MITmetadata:  title: "Read a Lobstack receipt"  version: 1.0.0  author: lobstack  category: cost  tags: [cost, receipts, metering, gateway]--- # Read a Lobstack receipt Every response from the Lobstack Gateway carries what the call cost. Read it.Never multiply token counts by a rate card you are holding in your head — thatis how a bundled price table drifts out of date and reports $0.00 next to areal charge, which is a mistake this product shipped for three months. ## Where the number is There are two paths and they carry the receipt differently. This is not adetail; a client that only handles one of them under-reports half its traffic. Buffered (stream: false) — HTTP response headers: ```x-lobstack-request-id: 8f2b1e0c-4d5a-4b91-9c3e-6a7f0d2b5c41x-lobstack-model: gemini-3.8-flash        # what actually served itx-lobstack-tier: standardx-lobstack-complexity: 47x-lobstack-routed: truex-lobstack-mode: managed                  # managed | byok | directx-lobstack-cost-usd: 0.000017             # empty string when unpricedx-lobstack-savings-usd: 0.000352x-lobstack-priced: truex-lobstack-metered: truex-lobstack-baseline-reason: namedx-lobstack-baseline-model: claude-opus-5x-lobstack-baseline-usd: 0.000369``` Streamed (stream: true) — the final SSE frame, under x_lobstack: ```json{  "id": "chatcmpl-…", "object": "chat.completion.chunk", "choices": [],  "usage": { "prompt_tokens": 14, "completion_tokens": 9, "total_tokens": 23 },  "x_lobstack": {    "request_id": "2f1c…",    "served_model": "gpt-5.6-luna",    "requested_model": "claude-opus-5",    "routed": true,    "cost_usd": 0.000017,    "savings_usd": 0.000352,    "priced": true,    "baseline_model": "claude-opus-5",    "baseline_reason": "named",    "baseline_cost_usd": 0.000369  }}``` There is no x-lobstack-cost-usd header on a streamed response, and therecannot be: the headers are written before the provider has counted a singletoken. If you are streaming, the receipt is on the last frame or you do not haveit. usage keeps the exact OpenAI shape so a foreign SDK parses it unchanged;the money hangs off x_lobstack, which those SDKs ignore. ## Three rules ### 1. null is not zero cost_usd is null — never 0 — when the Gateway could not price thecall, and priced is then false. A model key outside the registry gets acompletion and no price. Render null as unknown. Never as $0.00, never as free, and neversummed into a total that you then present as exact. Writing off a real charge aszero is the single most expensive way to be wrong about money, and a UI willhappily do it for you if you let a null fall through a ?? 0. ```ts// wrong: turns "we do not know" into "it was free"total += receipt.cost_usd ?? 0; // right: a total, and a count of what it could not includeif (receipt.cost_usd === null) unpriced += 1;else total += receipt.cost_usd;// report both: "$4.21 across 1,190 calls; 3 calls unpriced"``` ### 2. savings_usd is meaningless without baseline_reason savings_usd is a subtraction, and a subtraction is only honest if the readercan see where the first operand came from. Two reasons exist: - `named` — the caller asked for baseline_model and the router served  something else. savings_usd is a measurement against a model somebody  actually chose. Report it as a saving.- `plan_ceiling` — the caller said "auto" and named nothing.  baseline_model is the most expensive model their plan would have allowed:  what they *would* have paid had they asked for the best one. Nobody requested  it. It is a real number and also the most flattering one available. Print the reason next to the figure, or do not print the figure. Label the secondcase as "vs plan ceiling", never as "saved" — presenting a plan-ceilingcomparison as a saving publishes a number the customer never chose to bemeasured against. baseline_reason is null, with savings_usd also null, when thereis nothing to compare: the requested model is the served model, or the modelcannot be priced. That is the correct third answer, not a gap to fill. ### 3. cost_usd is what the customer owes It is the provider's list price times 1.25 onmode: managed, and pass-through on byok and direct — because on BYOKthe customer already paid their own provider and marking that up would beinventing a charge. What the tokens cost Lobstack is not in the receipt and neverwill be. So a BYOK receipt showing cost_usd is telling you what the tokenscost at the provider, not what will appear on a Lobstack invoice. ## Reading it ```tsimport OpenAI from "openai"; const client = new OpenAI({  apiKey: process.env.LOBSTACK_API_KEY,  baseURL: "https://www.lobstack.ai/api/gateway/v1",}); // Buffered: headers, via the raw response.const { data, response } = await client.chat.completions  .create({ model: "auto", messages: [{ role: "user", content: "…" }] })  .withResponse(); const costHeader = response.headers.get("x-lobstack-cost-usd");const cost = costHeader ? Number(costHeader) : null;   // "" means unpricedconst requestId = response.headers.get("x-lobstack-request-id");``` ```python# Streamed: the last frame with a usage block is the receipt.receipt = Nonefor chunk in client.chat.completions.create(model="auto", messages=msgs, stream=True):    raw = chunk.model_dump()    if raw.get("x_lobstack"):        receipt = raw["x_lobstack"]    for c in chunk.choices:        print(c.delta.content or "", end="") if receipt and receipt["priced"]:    print("\ncost $%.6f on %s" % (receipt["cost_usd"], receipt["served_model"]))elif receipt:    print("\ncost unknown - model not priced")``` ## Also worth keeping - request_id is the id of the trace row and is returned even on failures that  happen before authentication finishes. Quote it in a support thread and a  description becomes a lookup. Log it on every call; it costs nothing.- requested_model vs served_model is the routing decision, in the  response. When they differ, routed is true.- x-lobstack-dropped-params: temperature means a sampling parameter you sent  was not forwarded, because the target model rejects it with a hard 400. The  request succeeded. Nothing is wrong. Do not retry.- x-lobstack-metered: false means the completion happened but the ledger write  failed. You were served and the row is missing. Worth an alert. ## Do not - Do not compute cost from token counts and a local price table. Read it.- Do not sum null as zero.- Do not show a saving without its reason.- Do not assume the buffered and streamed shapes are interchangeable.

Also in Cost