Get Started with AI Measurement
Route your AI API calls through the Tailpipe proxy and it measures their energy, carbon, and cost. Anthropic (including Claude Code), OpenAI, Gemini, and Mistral are supported. Hosted setup below; self-hosted is available on request.
Prerequisites
- A Tailpipe account with AI measurement enabled
- Your existing provider API key (Anthropic, OpenAI, Gemini, or Mistral)
Hosted setup
Get your proxy URL and key
In Tailpipe, open Settings → Setup → AI Usage. Mint your telemetry key there. It is shown once, so copy it now.
The same page shows your proxy base URL and a ready-made env-var block for your
environment. Copy that block rather than typing the values by hand. The snippets below show the
shape of each setup with <your-proxy-url> and
<your-tenant-id> placeholders; if you type them by hand,
substitute the values from that page.
Configure your client
Pick your provider. Claude Code needs two environment variables and no code changes; the other SDKs take the base URL and one header in code.
macOS
# Set them for the current shell
export ANTHROPIC_BASE_URL="https://<your-proxy-url>/tenant/<your-tenant-id>"
export ANTHROPIC_CUSTOM_HEADERS="x-tailpipe-api-key: tp_your_key_here"
# Persist for new shells (zsh is the macOS default)
echo 'export ANTHROPIC_BASE_URL="https://<your-proxy-url>/tenant/<your-tenant-id>"' >> ~/.zshrc
echo 'export ANTHROPIC_CUSTOM_HEADERS="x-tailpipe-api-key: tp_your_key_here"' >> ~/.zshrcLinux
# Set them for the current shell
export ANTHROPIC_BASE_URL="https://<your-proxy-url>/tenant/<your-tenant-id>"
export ANTHROPIC_CUSTOM_HEADERS="x-tailpipe-api-key: tp_your_key_here"
# Persist for new shells (bash is the default on most distributions)
echo 'export ANTHROPIC_BASE_URL="https://<your-proxy-url>/tenant/<your-tenant-id>"' >> ~/.bashrc
echo 'export ANTHROPIC_CUSTOM_HEADERS="x-tailpipe-api-key: tp_your_key_here"' >> ~/.bashrcWindows (PowerShell)
# Set them for the current PowerShell session
$env:ANTHROPIC_BASE_URL = "https://<your-proxy-url>/tenant/<your-tenant-id>"
$env:ANTHROPIC_CUSTOM_HEADERS = "x-tailpipe-api-key: tp_your_key_here"
# Persist for new sessions, then reopen your terminal
setx ANTHROPIC_BASE_URL "https://<your-proxy-url>/tenant/<your-tenant-id>"
setx ANTHROPIC_CUSTOM_HEADERS "x-tailpipe-api-key: tp_your_key_here"# Anthropic (Python) — same route as Claude Code: change base_url and add the header
from anthropic import Anthropic
client = Anthropic(
base_url="https://<your-proxy-url>/tenant/<your-tenant-id>",
default_headers={"x-tailpipe-api-key": "tp_your_key_here"},
)# OpenAI (Python) — note the /openai/v1 suffix: the SDK appends /chat/completions to it.
from openai import OpenAI
client = OpenAI(
base_url="https://<your-proxy-url>/openai/v1",
default_headers={"x-tailpipe-api-key": "tp_your_key_here"},
)# Gemini (Python) — set base URL and header via http_options; the SDK has no
# base-URL env var. Your Google key goes in api_key as usual — the SDK sends it
# in its x-goog-api-key header, which the proxy forwards to Google.
import os
from google import genai
client = genai.Client(
api_key=os.environ["GEMINI_API_KEY"],
http_options={
"base_url": "https://<your-proxy-url>/gemini",
"headers": {"x-tailpipe-api-key": "tp_your_key_here"},
},
)# Mistral (Python) — set server_url explicitly; the SDK has no base-URL env var.
# The header goes on an HTTP client you pass in, used for every request.
import os, httpx
from mistralai.client import Mistral # 2.9.x; earlier releases: from mistralai import Mistral
client = Mistral(
api_key=os.environ["MISTRAL_API_KEY"],
server_url="https://<your-proxy-url>/mistral",
client=httpx.Client(
headers={"x-tailpipe-api-key": "tp_your_key_here"},
follow_redirects=True,
),
)| Provider | Route suffix | Base URL set via | x-tailpipe-api-key via |
|---|---|---|---|
| Claude Code | /tenant/<your-tenant-id> | ANTHROPIC_BASE_URL | ANTHROPIC_CUSTOM_HEADERS |
| Anthropic SDK | /tenant/<your-tenant-id> | base_url (code) | default_headers (code) |
| OpenAI | /openai/v1 | OPENAI_BASE_URL or constructor | default_headers (code) |
| Gemini | /gemini | http_options (code) | http_options headers (code) |
| Mistral | /mistral | server_url (code) | httpx.Client headers (code) |
The Claude Code and Anthropic SDK URLs carry a
/tenant/<your-tenant-id> segment. On the OpenAI, Gemini, and
Mistral routes your tenant is identified by the header instead, and adding
/tenant/ there sends the request upstream with the wrong path.
The Anthropic, OpenAI, Gemini, and Mistral SDK examples are Python, but the same two settings work in any language, and are identical on macOS, Linux, and Windows.
Keys and privacy
Two credentials travel with each request, doing different jobs. Your provider key
(x-api-key or Authorization: Bearer) authenticates you to the
provider: Tailpipe forwards your request to the provider and keeps no copy of
the key. The x-tailpipe-api-key header is what attributes usage to your
account, and it is a secret. Keep it out of source control and tickets. If it is ever
exposed, rotate it from the AI Usage page and the old value stops working within about
a minute. Rotating a live fleet has an operational sequence — read the fleet
section first.
The proxy keeps none of your content:
- Prompts and responses are relayed to your provider and never logged, stored, or retained.
- What Tailpipe records is usage metadata — model name, token counts, latency, status, and request attribution — never message content.
- Your provider key is forwarded to the provider and never stored.
Self-hosted setups keep the telemetry store in your own AWS account, and Tailpipe reads it cross-account, read-only.
Rolling out to a fleet
The setup is two environment variables, so roll it out with the tooling you already use for endpoints:
- macOS: an MDM configuration profile (Jamf, Intune), or a managed
/etc/zshenv. - Linux: Ansible, Puppet, Chef, or Salt writing
/etc/profile.d/tailpipe-ai.sh, or your golden image or container base image. - Windows: a Group Policy or Intune environment-variable policy.
The base URL only carries your tenant id and can be baked into images. The key is a secret: distribute it through the secret manager you already run (Vault, AWS Secrets Manager, 1Password, an Intune secure value) and have machines read it into the environment at login.
Plan rotations. Your tenant has one active telemetry key at a time.
Minting a replacement issues the new key first, then retires the old one within about a
minute. A machine still holding the old key gets a 401, and because the
proxy rejects requests it cannot attribute, that machine's AI calls fail, not just its
measurement. Have the new key ready to distribute before you rotate. Anything that does
not inherit your shell environment (background agents, daemons, IDE plugins, scheduled
jobs) keeps the value it started with until it restarts. If some traffic works and some
401s after a rotation, look there first.
Usage attributes to your organization as a whole, never to an individual machine or developer. You get organization-level emissions data, and nobody gets a per-person usage trail as a side effect.
Self-hosted (advanced)
If your data governance requires the telemetry store to live in your own AWS account, run the proxy yourself: a small stack writes telemetry to an S3 bucket in your account, and Tailpipe reads it cross-account, read-only. Setup is a provided script plus a one-time handback so we can read your bucket.
The self-hosted kit is available on request — contact us and we'll send it over with the walkthrough.
When your data appears
Usage is batched and aggregated once a day: calls buffer for about a minute at the proxy, a daily compaction runs at 01:00 UTC, then ingestion aggregates the day. Allow up to about 25 hours before new activity shows — not seeing your first day's usage until the next day is normal. Once telemetry has been ingested, the AI Usage page shows a "telemetry received (last 48h)" indicator.
Troubleshooting
A 401 from Tailpipe names the reason at the end of the message. The
/tenant/ routes (Claude Code and the Anthropic SDK) see
Tailpipe credential required (missing_credential).; the OpenAI, Gemini,
and Mistral routes see
{"error": "Unauthorized: missing_credential"}. The reason code
tells you what to fix:
| Symptom | Likely cause | Fix |
|---|---|---|
"tenant_id is required" (400) | Your Claude Code or Anthropic SDK base URL is missing its /tenant/<id> segment | Copy the full URL from the AI Usage page |
| No data on the dashboard | Daily aggregation takes up to ~25 hours | Wait a day; then check the telemetry-received indicator |
401 · missing_credential | No header arrived. Usually a process that doesn't inherit your shell environment | Set the variable where the process can see it, then restart the process |
401 · malformed_credential / unknown_or_revoked | A truncated copy, or a key replaced by a later rotation | Re-copy the current key from the AI Usage page |
401 · malformed_tenant_row / config_error | A fault on our side; your key is fine | Contact support rather than re-minting |
401 mentioning x-api-key or Bearer | Your provider key, not your Tailpipe key. On the OpenAI, Gemini, and Mistral routes the provider answers directly with its own error | Check the provider's own variable (for example ANTHROPIC_API_KEY) |
"model not found" | An upstream provider error, not Tailpipe | Check the model name against the provider's docs |
Per-model pricing is maintained by Tailpipe. A brand-new model may record usage before its pricing lands; if a model looks unpriced, let us know.
Need help getting set up?
Check our FAQs or get in touch — we're happy to walk you through it.