App attribution
Tag every inference with the app, page, or sub-user that originated it. Three optional request headers — User-Agent, HTTP-Referer, X-Title — flow into your activity log as searchable columns. Same convention as OpenRouter, drop-in compatible.
Why this exists
A real failure mode from a customer:
Without attribution headers, all you see in your log is the same API key making thousands of calls. With them, the offending app shows up by name. The pattern works for any of:
- One key shared across multiple internal apps — see per-app breakdown
- SaaS where your customers are the end-users — see per-customer breakdown
- Debugging an SDK upgrade — see version-string spread
Set the headers
Set them on the HTTP client, not in the JSON body — they apply to any Ollima endpoint, not just chat completions.
# Python (openai SDK) from openai import OpenAI client = OpenAI( base_url="https://api.ollima.com/v1", api_key="sk-t0-…", default_headers={ "X-Title": "acme-nightly-summarizer", "HTTP-Referer": "https://internal.acme.com/cron/summarize", # User-Agent is set by the SDK itself; openai-python uses # "openai/<version> python/<ver>" — already useful as-is. }, ) client.chat.completions.create(...)
Three rules of thumb:
| Header | What it's for | Limit |
|---|---|---|
X-Title | Human-readable app name. Shown first in the Logs page "App" column. | 128 chars |
HTTP-Referer | URL of the calling page or job. We display the hostname; full value visible in the request detail panel. | 512 chars |
User-Agent | SDK/client identifier. Set automatically by every standard SDK — you typically don't override. | 256 chars |
Empty / oversized / non-UTF8 values are silently dropped. Existing headers are never overwritten.
See it in your activity
Go to Dashboard → Logs. The App column shows the best available label per inference (X-Title → Referer hostname → User-Agent prefix). Click any row to expand and see all three raw values.
Programmatically: GET /orgs/<slug>/inferences includes three optional fields per row:
{
"inference_id": "01HKBN…",
"timestamp": "2026-06-15T14:54:44Z",
"model_name": "deepseek-v4",
"input_tokens": 8932,
"output_tokens": 127,
"x_title": "acme-nightly-summarizer",
"http_referer": "https://internal.acme.com/cron/summarize",
"user_agent": "openai-python/1.59.4"
} Multi-tenant SaaS pattern
If you're a SaaS company and your end-users each generate calls, set X-Title to a stable per-user identifier so you can attribute spend back to them:
client = OpenAI( base_url="https://api.ollima.com/v1", api_key="sk-t0-…", default_headers={"X-Title": f"acme:user:{user_id}"}, ) # or as a per-request override: client.chat.completions.create( ..., extra_headers={"X-Title": f"acme:user:{u.id}"}, )
Then GET /orgs/<slug>/inferences?app_prefix=acme:user: (coming in a follow-up) gives you a per-customer cost report. For now, export the Logs page to CSV and group in your tool of choice.
vs OpenRouter
OpenRouter's HTTP-Referer + X-Title convention is the de-facto industry standard. We deliberately match it byte-for-byte so any SDK that already sets these headers for OpenRouter works on Ollima without changes. If you're migrating from OpenRouter, your attribution data continues to flow.