Spend Attribution

How do I attribute LLM costs by feature and team?

Add X-Cost-Feature and X-Cost-Department headers to your LLM API calls. See per-feature and per-team AI spend breakdown in real time.

Pass X-Cost-Feature and X-Cost-Department headers on your Cognocient proxy calls. Every attributed call appears in your dashboard broken down by feature and team — no code changes beyond adding the headers.

Start here — 2 headers unlock 80% of the value

You don't need to add every header on day one. These two are all you need to unlock the most useful dashboards:

HeaderWhat it doesExample
X-Cost-FeatureTags the product feature making the callchatbot, search, pdf-extractor
X-Cost-DepartmentTags the team or business unitengineering, customer-success, sales

Add them now, see results immediately.

Set it once at the client level

Instead of adding headers to every call, set them once when you create the client. Every call from that client is tagged automatically — no per-call code changes needed.

client = OpenAI(
    api_key="sk-cog-YOUR-PROXY-KEY",
    base_url="https://api.cognocient.com/v1",
    default_headers={
        "X-Cost-Feature":    "ticket-resolver",
        "X-Cost-Department": "customer-success",
    }
)
# Every call from this client is now tagged — no extra_headers needed

What you'll see after tagging

Within seconds of your first tagged call, the dashboard updates:

Before headersAfter headers
Total AI spend: $12,400 — no breakdownchatbot: $5,200
No idea which feature is expensivesearch-summariser: $4,800
Can't do chargebackspdf-extractor: $2,400

The Spend by Feature and Spend by Department charts light up automatically. No configuration required.

Naming conventions

Use lowercase hyphen-separated names. Cognocient aggregates by exact string match.

Good:   ticket-resolver    customer-success    pdf-extractor
Bad:    Ticket Resolver    CustomerSuccess     PDF_EXTRACTOR

If you have multiple services, tag each one at the client level with its own feature name. This gives you automatic per-service cost breakdown with zero per-call overhead.


Add more context when you're ready

The next two headers that deliver the most value:

Track individual users — X-Cost-User

Pass an internal user ID (never raw email or PII). Unlocks the Users tab showing your most expensive users and cost-per-user trends.

extra_headers={
    "X-Cost-Feature":    "ticket-resolver",
    "X-Cost-Department": "customer-success",
    "X-Cost-User":       f"user_{user_id}",    # internal ID, not email
}

Track conversations — X-Cost-Session

Pass a unique ID for each conversation or task. Unlocks the Sessions tab showing total cost per conversation, turn count, and context growth.

import uuid
 
session_id = f"sess-{uuid.uuid4()}"   # generate once when the conversation starts
 
def chat(messages: list, user_id: str):
    return client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        extra_headers={
            "X-Cost-Feature": "support-chat",
            "X-Cost-Session": session_id,      # same ID for all turns in this conversation
            "X-Cost-User":    f"user_{user_id}",
        }
    )

X-Cost-Session is also how you connect AI spend to JIRA tickets and GitHub PRs. See Workstream Attribution below.


What attribution headers does Cognocient support?

All headers are optional. Use what's relevant to your product.

HeaderWhat it tagsDashboard it unlocks
X-Cost-FeatureProduct feature nameSpend by Feature chart
X-Cost-DepartmentTeam or business unitSpend by Department chart, chargebacks
X-Cost-UserInternal user IDUsers tab — top spenders, cost trends
X-Cost-SessionConversation or task IDSessions tab, Workstreams tab
X-Cost-GL-AccountGeneral Ledger account codeFOCUS 1.1 export, accounting integration
X-Cost-Run-IDSingle agent execution IDPer-run budget isolation
X-Cost-Workloadagentic-write or agentic-readControls budget enforcement behaviour
X-Cost-ProjectTime-bounded project nameProject spend tracking
X-Cost-OutcomeBusiness outcome achievedCost/Outcome ROI dashboard

GL account tagging — for finance teams

Add X-Cost-GL-Account to route AI spend to specific cost centres in your accounting system. The value appears as-is in the FOCUS 1.1 export, so your accounting team can reconcile without any mapping.

extra_headers={
    "X-Cost-Feature":    "pdf-extractor",
    "X-Cost-Department": "data-team",
    "X-Cost-GL-Account": "5100-software",   # appears in FOCUS export
}

Workstream attribution — tie spend to JIRA tickets and PRs

Use X-Cost-Session with your ticket or PR ID to see exactly how much AI spend each story or PR generated.

# Tag calls with a JIRA ticket
extra_headers={"X-Cost-Session": f"JIRA-{story_id}"}
 
# Tag calls with a GitHub PR
extra_headers={"X-Cost-Session": f"pr-{pr_number}"}

The Workstreams dashboard shows each session with total cost, call count, duration, and models used:

WorkstreamFeatureTotal CostCallsDuration
JIRA-2341chatbot$12.408473d 2h
pr-892search$4.204745m

This answers the question your engineering manager and CFO both ask: "What work did we spend that AI budget on?"


Per-run attribution — for agent workflows

For autonomous agents that run multiple steps, pass a unique X-Cost-Run-ID for the entire execution. Cognocient tracks total spend per run. When a run exceeds its per-run budget, only that run is blocked — other concurrent runs continue normally.

import uuid
 
async def run_agent(task: str):
    run_id = f"run-{uuid.uuid4()}"   # generate once per agent execution
 
    for step in agent_pipeline(task):
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=step.messages,
            extra_headers={
                "X-Cost-Feature": "my-agent",
                "X-Cost-Run-ID":  run_id,        # same ID for every step in this run
                "X-Cost-Workload": "agentic-write",
            }
        )

Generate a fresh run_id per execution, not per call. Re-using the same run ID across different agent executions defeats per-run budget isolation.

X-Cost-Workload — control what happens when the budget runs out

ValueOn budget exceededUse when
agentic-writeHard stop (429)Agent will write to DB, send email, or call an external API
agentic-readGraceful degradation — cheaper model completes the callAgent is doing research, summarisation, or retrieval

You don't need to set X-Cost-Workload manually if your tool names are descriptive. Cognocient infers the type: tools with create, update, delete, send, or write in the name are treated as agentic-write. Everything else is agentic-read. Set the header to override.


ROI tracking — X-Cost-Outcome

Add X-Cost-Outcome on calls that produce a measurable business result. This unlocks the AI Investment ROI panel on the dashboard and the Cost/Outcome view in Executive Overview.

# Only set this on calls that confirmed a successful outcome
extra_headers={
    "X-Cost-Feature": "ticket-resolver",
    "X-Cost-Outcome": "ticket-resolved",   # set after the ticket is confirmed resolved
}

The dashboard then shows: cost per ticket resolved, cost per contract drafted, cost per report generated — the ROI number your CFO needs.

See Outcomes & ROI for naming conventions and the full API.


Troubleshooting

No data showing up after I added headers?

  1. Make sure you're using your Cognocient proxy key (sk-cog-...), not your OpenAI key directly.
  2. Make sure base_url / baseURL points to https://api.cognocient.com/v1.
  3. Check the Live Calls tab (/calls) — your call should appear there within seconds. If it does, the headers are working. Dashboard charts update within a few minutes.

Feature names showing up inconsistently?

Attribution is case-sensitive and exact-match. Chatbot and chatbot are different features. Pick a convention (lowercase-hyphen) and stick to it.


Next steps: Waste Detection · Budget Enforcement · MCP/A2A Attribution