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

# OpenAI

> Wrap OpenAI chat completions and capture usage automatically.

## Recommended: tracked OpenAI client

Use this when one OpenAI call should become one Margovia run.

```ts theme={null}
import OpenAI from "openai";
import { Margovia } from "@margovia/sdk";

const margovia = new Margovia();
const openai = margovia.openai(new OpenAI());

await openai.chat.completions.create({
  name: "draft_support_reply",
  customerId: "workspace_456",
  customerName: "Northstar Agency",
  customerPlan: { name: "pro", monthlyUsd: 99 },
  outcome: "reply_generated",
  request: {
    model: "gpt-5-mini",
    messages
  }
});
```

The tracked client starts a run, calls `client.chat.completions.create(request)`, reads `response.usage`, records the cost event, and completes or fails the run.

Use a stable, namespaced `customerId`. Margovia keeps this ID exactly as sent so it can join back to your app or billing data.

The tracked client records:

* `provider: "openai"`
* model
* prompt tokens
* completion tokens
* cached prompt tokens
* reasoning tokens
* latency

## Alternative: patch an existing client

Use this when you want to keep normal OpenAI call sites and pass Margovia fields through provider `metadata`.

```ts theme={null}
import OpenAI from "openai";
import { Margovia } from "@margovia/sdk";

const margovia = new Margovia();
const openai = margovia.wrapOpenAI(new OpenAI(), {
  autoTrack: true,
  defaultName: "openai.chat.completions.create"
});

await openai.chat.completions.create({
  model: "gpt-5-mini",
  messages,
  metadata: {
    margoviaName: "draft_support_reply",
    margoviaOutcome: "message_created",
    userId: "user_123",
    customerId: "workspace_456",
    customerName: "Northstar Agency",
    customerPlan: "pro",
    customerPlanMonthlyUsd: "99"
  }
});
```

This is useful for wide migrations, but the tracked OpenAI client is clearer for new code.

## Custom run input

Use `getRunInput` when your customer metadata lives outside the provider request.

```ts theme={null}
const openai = margovia.wrapOpenAI(new OpenAI(), {
  getRunInput: (_request, [body]) => ({
    name: "support_reply",
    customerId: `workspace_${body.workspace.id}`,
    customerName: body.workspace.name,
    customerPlan: { name: body.workspace.plan, monthlyUsd: 99 },
    outcome: "reply_generated"
  })
});
```

Use `getRunInput` when metadata is not available on the provider request or when you want to derive attribution from your authenticated app context.

## Explicit helper

Use `trackOpenAI(...)` when you already have your own helper function around OpenAI calls.

```ts theme={null}
const response = await margovia.trackOpenAI({
  name: "draft_support_reply",
  customerId: "workspace_456",
  customerName: "Northstar Agency",
  outcome: "reply_generated",
  request: {
    model: "gpt-5-mini"
  },
  fn: () => openai.chat.completions.create({
    model: "gpt-5-mini",
    messages
  })
});
```

This starts the run, calls OpenAI, reads `response.usage`, records cost, and completes or fails the run.

Use a raw OpenAI client inside `trackOpenAI(...)`. Do not pass an already-wrapped client into this helper or you may double-report the same call.

## Manual run context

Use `run.step(...)` when a provider call belongs to a larger manual workflow.

```ts theme={null}
const run = await margovia.startRun({
  name: "resolve_ticket",
  customerId: "workspace_456"
});

await run.step("openai_reply", () =>
  openai.chat.completions.create({
    model: "gpt-5-mini",
    messages
  })
);

await run.complete({ outcome: "ticket_resolved" });
```

When you open a manual run, you own its lifecycle. Always call `run.complete(...)` or `run.fail(...)` after the workflow finishes.

## Common mistake

Do not wrap a raw OpenAI call with `.track(...)` and expect cost to appear:

```ts theme={null}
await margovia.track({
  name: "draft_support_reply",
  fn: () => rawOpenAI.chat.completions.create({ model: "gpt-5-mini", messages })
});
```

That creates a run, but the raw client does not report token usage to Margovia. Use `margovia.openai(client)`, `wrapOpenAI(...)`, `trackOpenAI(...)`, or `run.trackCost(...)`.
