> ## 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 the response comes back into a Node process you control, wrapping the client there is simpler and also gives you the gateway's real cost. Use this pattern for traffic you cannot wrap, for example from services in other languages.
</Note>

**Before you start:**

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

<Steps>
  <Step title="Check and send attribution from the application">
    Check the budget before sending the request, then add the attribution headers.

    ```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: 'gpt-5', messages }),
    });
    ```

    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`.
  </Step>

  <Step title="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',
      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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

## Limits of this pattern

* **The proxy cannot deny a call.** Only the application holds the budget context, so the check happens there. A request that skips the check is still metered, but not gated.
* **Tokens, not cost.** What crosses the boundary is a usage report. To bill the gateway's real cost, wrap a [gateway you call](/documentation/ai-agents/llm-wrappers/gateways#a-gateway-you-call) instead.
* **No double metering.** Do not also wrap the client in the application for the same requests, or usage is reported twice.


## Related topics

- [Gateways](/documentation/ai-agents/llm-wrappers/gateways.md)
- [Metering usage](/documentation/ai-agents/llm-wrappers/metering.md)
- [Supported providers and gateways](/documentation/ai-agents/llm-wrappers/supported-providers.md)
- [Bring your own vendor](/documentation/ai-agents/llm-wrappers/providers/custom.md)
- [Meter LLM token usage](/guides/ai-agents/meter-llm-token-usage.md)


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