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

# LLM Strategy

> Auto-meter LLM token usage per customer and bill on usage, activity, or outcome — tax and compliance handled.

Every model call your app makes has a cost and, increasingly, a price. The LLM strategy closes the gap between the two: wrap a model once, and Macropay records the input, output, and cached tokens of every call as a billable event — tagged to the customer who triggered it. No manual counting, no glue code in your request path.

Because Macropay is your [Merchant of Record](/), the events you ingest here roll straight into invoices where sales tax and VAT are calculated, collected, and remitted for you. You meter the tokens; we handle the seller-of-record obligations.

<Info>
  This is one of several ingestion strategies. For the bigger picture — meters, metered prices, and credits — start with the [strategy introduction](/features/usage-based-billing/ingestion-strategies/ingestion-strategy).
</Info>

## Why meter LLM usage

The token count from a single completion is the raw material for three different billing models. Pick the one that matches how you charge:

| Bill on      | What you meter    | Example                               |
| ------------ | ----------------- | ------------------------------------- |
| **Usage**    | Tokens consumed   | \$0.000004 per output token           |
| **Activity** | Calls or sessions | \$0.10 per resolved support chat      |
| **Outcome**  | Value delivered   | \$2 per qualified lead an agent books |

The LLM strategy captures the per-call token detail. From there, a [meter](/features/usage-based-billing/meters) aggregates the events and a metered price turns them into charges — or feeds your [agent billing](/) and value-receipt flows when you're charging for outcomes rather than raw tokens.

## TypeScript SDK

The strategy wraps any model from the [`@ai-sdk/*`](https://sdk.vercel.ai) family. Once wrapped, prompt and completion tokens fire automatically on every model call — `generateText`, `streamText`, and friends all work unchanged.

<Steps>
  <Step title="Install the packages">
    ```bash theme={null}
    pnpm add @macropayments/ingestion ai @ai-sdk/openai
    ```
  </Step>

  <Step title="Wrap the model and route calls through it">
    Configure the strategy once at module scope, then derive a per-customer client inside each request so events are attributed correctly.

    ```typescript theme={null}
    import { Ingestion } from "@macropayments/ingestion";
    import { LLMStrategy } from "@macropayments/ingestion/strategies/LLM";
    import { generateText } from "ai";
    import { openai } from "@ai-sdk/openai";

    // Configure the LLM ingestion strategy once.
    const llmIngestion = Ingestion({ accessToken: process.env.MACROPAY_ACCESS_TOKEN })
      .strategy(new LLMStrategy(openai("gpt-4o")))
      // Optional: attach what the call cost you (COGS) so margin is visible per customer.
      .cost((ctx) => ({ amount: 42, currency: "usd" })) // amount in cents → $0.42
      .ingest("draft-assistant-tokens");

    export async function POST(req: Request) {
      const { prompt }: { prompt: string } = await req.json();

      // Bind the wrapped model to the customer making this request.
      const model = llmIngestion.client({
        customerId: "cus_4821",
      });

      const { text } = await generateText({
        model,
        system: "You are a concise copy editor.",
        prompt,
      });

      return Response.json({ text });
    }
    ```
  </Step>
</Steps>

<Tip>
  The optional `.cost()` callback records what each call cost you. Pair it with billed revenue and Macropay can show your **agentic margin** — revenue earned versus AI cost — per customer or per agent, instead of leaving you to reconcile two spreadsheets.
</Tip>

### What gets ingested

Each model call emits an event named after the string you passed to `.ingest()`. Token metadata is filled in automatically; the `_cost` block appears only when you provide a `.cost()` callback.

```json theme={null}
{
  "customerId": "cus_4821",
  "name": "draft-assistant-tokens",
  "metadata": {
    "inputTokens": 100,
    "outputTokens": 200,
    "cachedInputTokens": 10,
    "totalTokens": 300,
    "model": "gpt-4o",
    "provider": "openai.responses",
    "strategy": "LLM",
    "_cost": {
      "amount": 42,
      "currency": "usd"
    },
    "_llm": {
      // full provider usage object, passed through verbatim
    }
  }
}
```

<Note>
  Amounts are always integer **cents**, never decimals — `$0.42` is `42`, `$1.23` is `123`.
</Note>

## Python SDK

The ingestion helper ships inside the Macropay SDK. It batches events and sends them in the background, so metering never blocks the response you're returning to the user.

<CodeGroup>
  ```bash pip theme={null}
  pip install macropay
  ```

  ```bash uv theme={null}
  uv add macropay
  ```
</CodeGroup>

### Ingestion helper

For full control, call the helper directly. This is the lowest-level entry point — useful when you're metering something other than a framework's built-in usage object.

```python theme={null}
import os
from macropay_sdk.ingestion import Ingestion

ingestion = Ingestion(os.getenv("MACROPAY_ACCESS_TOKEN"))

ingestion.ingest({
    "name": "summarizer-tokens",
    "external_customer_id": "cus_4821",
    "metadata": {
        "total_tokens": 512,
    }
})
```

### PydanticAI strategy

[PydanticAI](https://ai.pydantic.dev) is a typed agent framework for Python. Its `RunResult` already carries token usage, so the strategy reads it straight off the result you get back — one `ingest()` call and the run is metered.

```python theme={null}
import os
from macropay_sdk.ingestion import Ingestion
from macropay_sdk.ingestion.strategies import PydanticAIStrategy
from pydantic import BaseModel
from pydantic_ai import Agent


ingestion = Ingestion(os.getenv("MACROPAY_ACCESS_TOKEN"))
strategy = ingestion.strategy(PydanticAIStrategy, "expense-categorizer")


class Categorized(BaseModel):
    category: str
    confidence: float


agent = Agent("gpt-4.1-nano", output_type=Categorized)

if __name__ == "__main__":
    result = agent.run_sync("Uber to the airport, $48.20, business trip.")
    print(result.output)
    # Meter this run against the customer who triggered it.
    strategy.ingest("cus_4821", result)
```

<Note>
  The structured-output pattern above follows the [Pydantic model example](https://ai.pydantic.dev/examples/pydantic-model/) in the PydanticAI docs.
</Note>

#### What gets ingested

The strategy reads the run's usage and emits a single event under the name you registered:

```json theme={null}
{
  "name": "expense-categorizer",
  "external_customer_id": "cus_4821",
  "metadata": {
    "requests": 1,
    "total_tokens": 78,
    "request_tokens": 58,
    "response_tokens": 20
  }
}
```

## Where the events go

Once events land, a meter filters and aggregates them and a metered price converts the aggregate into charges on the customer's next invoice. If you're charging for results rather than raw tokens, route the same usage into outcome-based [agent billing](/) and issue value receipts that certify the ROI you delivered.

## Need a different model framework?

Don't see your stack? Any token count you can read in code can be sent through the ingestion helper directly — see the [strategy introduction](/features/usage-based-billing/ingestion-strategies/ingestion-strategy) for the other built-in strategies, or email [support@macropay.ai](mailto:support@macropay.ai) and we'll help you wire it up.
