> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stigg.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Meter LLM gateway spend

> Burn down a customer's credit pool by what their LLM calls actually cost through OpenRouter or LiteLLM, plus your markup.

In this guide you meter what each customer's calls actually cost, plus a markup, and burn it down from the customer's prepaid credit pool. The cost comes from the gateway itself, so it reflects caching, routing and fallbacks rather than a price list you maintain by hand.

**What you will build:**

* A credit pool that burns down by the gateway's real cost times your markup, call by call.
* A check before each call that denies access when the credit pool is empty, so you can offer the customer more credits with a [top-up](/documentation/modeling-your-pricing-in-stigg/credits/self-service-top-up).

**Before you start:**

* A Stigg server API key.
* An [OpenRouter](https://openrouter.ai) account and API key, or a [LiteLLM Proxy](https://docs.litellm.ai/docs/simple_proxy), self-hosted or cloud-hosted.
* A [credit type](/documentation/modeling-your-pricing-in-stigg/credits/credit-types) in Stigg (this guide uses `credits`, where 1 credit is worth 1 US cent) and a customer with a credit grant. See [Set up credits](/guides/i-want-to/set-up-credits).

**1. Define your markup**

Both gateways report each call's cost in millionths of a US dollar by default: OpenRouter in millionths of an OpenRouter credit (1 OpenRouter credit is \$1), and LiteLLM in millionths of a dollar.

With 1 Stigg credit worth \$0.01 and a 20% markup, each call burns:

```text theme={null}
credits = cost × 1.2 / 10,000
```

For example, a call that cost the gateway \$0.00108 (a `cost` of 1,080) burns 0.1296 credits.

**2. Install and initialize**

```bash theme={null}
npm install @stigg/agent-sdk-js openai
```

```typescript theme={null}
import OpenAI from 'openai';
import { StiggAgentSDK, openrouterRecipe, weightedMetrics } from '@stigg/agent-sdk-js';

const stigg = new StiggAgentSDK(process.env.STIGG_SERVER_API_KEY);
```

**3. Wrap the gateway client**

**OpenRouter**

Wrap an `OpenAI` client pointed at OpenRouter:

```typescript theme={null}
const recipe = openrouterRecipe();

export const llm = stigg.wrap(
  new OpenAI({ baseURL: 'https://openrouter.ai/api/v1', apiKey: process.env.OPENROUTER_API_KEY }),
  {
    recipe,
    stiggContext: {
      entitlement: { currencyId: 'credits' },
      usageMapper: weightedMetrics(recipe, 'credits', { cost: 1.2 }, { per: 10_000 }),
      ingestMode: 'sync',
    },
  },
);
```

To wrap OpenRouter's own client instead, see [OpenRouter](/documentation/ai-agents/providers/openrouter).

**LiteLLM Proxy**

Wrap an `OpenAI` client pointed at your LiteLLM Proxy, and pass the proxy's URL to the recipe:

```typescript theme={null}
import { litellmRecipe } from '@stigg/agent-sdk-js';

const recipe = litellmRecipe({ baseUrl: process.env.LITELLM_URL });

export const llm = stigg.wrap(
  new OpenAI({ baseURL: process.env.LITELLM_URL, apiKey: process.env.LITELLM_KEY }),
  {
    recipe,
    stiggContext: {
      entitlement: { currencyId: 'credits' },
      usageMapper: weightedMetrics(recipe, 'credits', { cost: 1.2 }, { per: 10_000 }),
      ingestMode: 'sync',
    },
  },
);
```

LiteLLM reports cost only for calls that are not streamed. See [LiteLLM Proxy](/documentation/ai-agents/providers/litellm).

What each setting does:

* `entitlement` turns on the check before each call, against the `credits` credit pool.
* `usageMapper` applies your markup to the gateway's `cost` and reports the result in `credits`, straight to the credit pool. See [Weighted credits](/documentation/ai-agents/usage-metering#weighted-credits).
* `ingestMode: 'sync'` updates the credit pool with each call, so the next check already includes it.

**4. Make calls and handle an empty credit pool**

```typescript theme={null}
try {
  const completion = await llm.chat.completions.create({
    model: 'anthropic/claude-opus-5',
    messages,
    stiggContext: { customerId: account.stiggCustomerId },
  });
  return completion;
} catch (err) {
  const decision = stigg.denial(err);
  if (!decision) throw err;
  // decision.remedy === 'top-up'
  return renderTopUpPrompt(decision.message);
}
```

Denied access is never cached, so a customer who buys more credits can continue on their very next call.

**5. Verify**

Make a few calls and open the customer's credit balance in the Stigg app. Each call burns its marked-up cost.

To compare what was reported with the gateway's own dashboard, print the wrapped client's [summary](/api-and-sdks/references/sdk/backend/rest/agent-sdk#summary), which `flush()` returns:

```typescript theme={null}
console.log(await llm.stigg.flush());
// { checks: 3, ingested: 3, reported: { credits: 0.3888 }, ingestFailures: 0, ... }
```

To log every report as it is sent instead, pass an [`onIngest`](/api-and-sdks/references/sdk/backend/rest/agent-sdk#stiggagentsdk) hook to the SDK.

## Things to know

* **A call can go past the last few credits.** Each check asks only whether any credits are left, and the call's real cost is burned after it. A customer with almost no credits left can make one more call, which may cost more than what remained. See [Enforcing a limit on cost](/documentation/ai-agents/access-enforcement#enforcing-a-limit-on-cost) to check against an estimate of the call's cost instead.
* **Calls with no cost burn no credits.** Some calls return no cost, for example on OpenRouter with your own provider key. To burn credits for those too, add token weights to the `weightedMetrics` table.
* **Calls attributed to agents are rounded up.** If you also attribute calls to [agents](/documentation/ai-agents/usage-governance), each call's credits are rounded up to a whole credit. See [Weighted credits](/documentation/ai-agents/usage-metering#weighted-credits).
* **Which model served each call.** Credits burned straight from the credit pool carry no dimensions, so this setup does not record the model. To track it, also report the calls as events in `async` mode. See [Routing drift](/documentation/ai-agents/usage-metering#routing-drift).


## Related topics

- [Meter LLM token usage](/guides/ai-agents/meter-llm-token-usage.md)
- [Databricks](/documentation/ai-agents/providers/databricks.md)
- [Meter usage from your own gateway](/guides/ai-agents/meter-usage-from-your-own-gateway.md)
- [Usage metering](/documentation/ai-agents/usage-metering.md)
- [AI agents](/documentation/ai-agents/overview.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.