# Moving cost tracking from Langfuse to Veqen

Langfuse shows each generation's cost next to its trace, worked out from its model price definitions unless you send the cost yourself. Veqen keeps cost as a ledger instead: every call priced with the provider's billing rules, attributed to a customer and feature, checked against the provider's invoice, and booked at month end. You can run both: Langfuse for traces, prompts and evals, Veqen for what the AI cost and who it was for.

## 1. Add Veqen next to Langfuse

Veqen doesn't replace Langfuse's integration, so add it beside it. Langfuse's drop-in OpenAI module and `veqen.wrap()` work together on the same client:

```python [Python]
import veqen
from langfuse.openai import OpenAI  # Langfuse keeps tracing

veqen.init()  # reads VEQEN_API_KEY, an ingest key
client = veqen.wrap(OpenAI(), feature="support")
```

```ts [TypeScript]
import OpenAI from "openai";
import { observeOpenAI } from "@langfuse/openai";
import { wrap } from "@veqen/sdk";

const client = wrap(observeOpenAI(new OpenAI()), { feature: "support" });
```

In LangChain or LangGraph, pass Veqen's handler with Langfuse's: `config={"callbacks": [langfuse_handler, VeqenCallbackHandler()]}`. See [LangChain](/integrations/langchain).

Moving off Langfuse entirely? Remove its import and wrap the plain client; nothing else changes.

## 2. Map trace attributes to tags

| Langfuse | Veqen |
|---|---|
| `user_id` on the trace | `veqen.tags(user=...)` |
| `session_id` | `veqen.tags(run=...)`: the conversation's total cost on **Agent runs** |
| `metadata={"customer": "acme"}` | `veqen.tags(customer="acme")` |
| A trace name or tag for the feature | `veqen.wrap(client, feature="search")` or `veqen.tags(feature="search")` |
| `LANGFUSE_TRACING_ENVIRONMENT` | `VEQEN_ENVIRONMENT=production`, or the `environment` tag |
| Project per product | `veqen.tags(project="...")` or a separate Veqen API key |

Tags are set once for a request context and apply to every call inside it:

```python
with veqen.tags(customer=account.id, user=user.id, run=conversation.id):
    answer = agent.run(question)
```

## 3. Move your custom model prices

Langfuse's model definitions (a match pattern and prices per usage type) become [custom prices](/docs/custom-prices) under Settings › Your prices: an exact rate, or a discount off list for a provider. Veqen's price book already carries list prices for cached input, cache writes, batch, priority and long-context tiers, so you only need custom prices for negotiated rates and models you host yourself. To move many at once, upload them as a CSV rate card.

## 4. Fill in history

Langfuse's history stays in Langfuse. To see real spend from day one, connect your providers under Settings › Connections (OpenAI, Anthropic, AWS Bedrock, Google Cloud, Azure and OpenRouter): Veqen imports the billed cost of the last 30 days by model before your first tracked call.

## What changes

- **Exact rather than estimated.** Costs follow each provider's billing rules, then [reconciliation](/docs/reconciliation) checks them against the invoice and shows any spend your code never saw.
- **Budgets that act.** The SDK checks a cap before the call and can stop it; see [budgets](/docs/budgets).
- **Finance gets its numbers.** [Margin per customer](/docs/margin) from Stripe revenue, and month-end [journal entries](/docs/close) for QuickBooks or Xero.
- **No prompts leave your app.** Veqen reads only usage counts and tags, so cost data can be shared with finance without sharing conversations.
