> ## 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 usage from your own gateway

> Attribute and meter LLM traffic that passes through a proxy you operate, while keeping budget checks in your application.

Some teams route all model traffic through an internal proxy: for shared keys, logging, or because several services in different languages call models. The proxy sees every request, but not which customer or agent it was for. This guide splits the work across the boundary: your application checks the budget and sends attribution as headers, and the proxy reports what it observed.

```mermaid theme={null}
sequenceDiagram
    participant App as Your application
    participant S as Stigg
    participant Px as Your proxy
    participant P as Provider

    App->>S: Check (in-process)
    S-->>App: allowed
    App->>Px: request + x-stigg-* headers
    Px->>P: request
    P-->>Px: response with usage
    Px--)S: ingestFromHeaders(headers, usage)
    Px-->>App: response
```

> [!NOTE]
>
> If your application calls the model through a client it can wrap, [wrapping the client](/documentation/ai-agents/overview) is simpler. Use this pattern for traffic that only your proxy sees, for example from services written in languages the Agent SDK does not support.

**Before you start:**

* A Stigg server API key in both the application and the proxy.
* A metered feature or credit type to meter usage against. This guide reports to the `credits` credit type in `sync` mode, so no meter configuration is needed.

**1. Check and send attribution from the application**

Check the budget before sending the request, then add the attribution headers.

The check runs in the application because the application knows who the request is for and what to check it against, and it is the one that can respond to the user when access is denied, for example with an offer to buy more credits. The proxy only sees requests.

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

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

const context = {
  customerId: 'customer-acme',
  entitlement: { currencyId: 'credits' },
  agentId: 'agent-support-bot',
  attributionKey: 'agentId',
};

const decision = await stigg.check(context);
if (!decision.hasAccess) return showRemedy(decision);

await fetch(`${PROXY_URL}/v1/chat/completions`, {
  method: 'POST',
  headers: { 'content-type': 'application/json', ...stigg.governanceHeaders(context) },
  body: JSON.stringify({ model, messages }), // the request your proxy forwards to the provider
});
```

The headers carry the customer, the attribution dimensions (here `{"agentId":"agent-support-bot"}`), the attribution key that names the agent, and a correlation ID. They contain no secrets.

Applications in other languages can set the same headers by hand: `x-stigg-customer-id`, `x-stigg-dimensions` (a JSON object), `x-stigg-attribution-key` (the key in `x-stigg-dimensions` that names the agent, here `agentId`) and `x-stigg-run-id`.

**2. Report from the proxy**

After the upstream call returns, report the usage with the incoming request's headers:

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

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

// In your request handler:
const completion = await upstream.chat.completions.create(body);

const result = await stigg.ingestFromHeaders(req.headers, {
  vendor: 'openai',                // the format of the upstream response: OpenAI Chat Completions here
  usage: completion.usage,
  idempotencyKey: completion.id,
  entitlement: { currencyId: 'credits' },
  metrics: unitsPerTokens('credits', 1_000),
  ingest: 'sync',
});

res.json(completion);
```

* `vendor` names the response shape the proxy observed: `openai`, `openai-responses`, `anthropic`, `gemini` or `typesafe`.
* `idempotencyKey` should be the upstream request ID, so a retried report is not counted twice.
* Reporting never throws. Answer the caller even if `result.ok` is `false`, and log the failure.
* Requests without an `x-stigg-customer-id` header are not attributed.

**3. Verify**

Send a request through the proxy and open `customer-acme` in the Stigg app. The credit balance drops by the reported amount, and the usage is attributed to `agent-support-bot` and every level above it.

## Things to know

* **Access is enforced in the application.** The proxy reports usage but does not check access. A request that reaches the proxy without the application checking it first is still metered.
* **Usage is reported as token counts.** The proxy reports the token counts from the provider's response. To meter what a hosted gateway such as OpenRouter or LiteLLM actually charged, wrap the client you use to call it instead. See [Metering through a gateway](/documentation/ai-agents/usage-metering#metering-through-a-gateway).
* **Meter each request once.** If the application also wraps its client for the same requests, their usage is reported twice. Use one or the other.


## Related topics

- [Meter LLM gateway spend](/guides/ai-agents/meter-llm-gateway-spend.md)
- [Usage metering](/documentation/ai-agents/usage-metering.md)
- [Meter LLM token usage](/guides/ai-agents/meter-llm-token-usage.md)
- [Databricks](/documentation/ai-agents/providers/databricks.md)
- [LiteLLM Proxy](/documentation/ai-agents/providers/litellm.md)


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