Skip to main content
Use this when one OpenAI call should become one Margovia run.
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.
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.
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.
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.
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:
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(...).