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

# Migrating from Helicone

> Helicone is an observability layer you point a base URL at; KnoxCall is a control plane in the same position. Concept mapping, before/after snippets, and a straight account of what you gain, what you lose, and what to keep running alongside.

# Migrating from Helicone

Helicone's integration is famously one line — change the base URL, keep your SDK —
and KnoxCall's is the same line. That makes the mechanical part of this migration
close to trivial and the interesting part entirely about what sits behind it.

Be clear about the difference before you start, because it decides whether this is
a migration or an addition: **Helicone is an observability layer; KnoxCall is a
control plane.** Helicone tells you what happened. KnoxCall decides what is
allowed to happen, and then tells you what happened.

## Concept mapping

| Helicone                                   | KnoxCall                                                                  | Notes                                                     |
| ------------------------------------------ | ------------------------------------------------------------------------- | --------------------------------------------------------- |
| `Helicone-Auth` header + your provider key | A [capability token](/ai-gateway/tokens-and-dpop) and **no** provider key | The big one — see below                                   |
| Custom properties (`Helicone-Property-*`)  | Agent `tags` + `X-KC-User` / `X-KC-Team`                                  | Same idea, feeds cost attribution                         |
| User metrics (`Helicone-User-Id`)          | `X-KC-User`, resolved against your SCIM directory                         |                                                           |
| Caching                                    | [Response cache](/ai-gateway/overview) — `cache_mode` per agent           |                                                           |
| Rate limiting                              | Per-token rate limits + `budget_daily_usd`                                | Dollars as well as requests                               |
| Request logging                            | `ai_gateway_usage` + `api_requests`                                       | Bodies are **not** stored unless you turn body logging on |
| Prompt / session tracking                  | *(partial)*                                                               | Session-level grouping is on the roadmap, not shipped     |
| Evaluations, experiments, playground       | *(no equivalent)*                                                         | Keep Helicone, or another tool, for these                 |

## Before / after

**Before** — your app holds the provider key and Helicone sees it:

```python theme={"dark"}
client = OpenAI(
    api_key=OPENAI_API_KEY,                       # a real provider key, in your app
    base_url="https://oai.helicone.ai/v1",
    default_headers={"Helicone-Auth": f"Bearer {HELICONE_API_KEY}"},
)
```

**After** — your app holds neither:

```python theme={"dark"}
client = OpenAI(
    api_key=KNOXCALL_CAPABILITY_TOKEN,            # not a provider key
    base_url="https://acme.knoxcall.com/v1/ai/support-bot/v1",
)
```

That is the whole code change. The provider key lives in KnoxCall, envelope-
encrypted, and is injected at the egress hop — so it is not in your environment,
not in your container, and not in a heap dump.

## What you gain

* **Your workload stops holding a provider key.** A leaked capability token is
  scoped to one agent, one model set, one spend cap and one time window, and can
  be revoked without rotating anything at the provider.
* **[Mid-stream PII redaction](/ai-gateway/streaming-guarantees).** Entities are
  removed inside the SSE stream — including ones split across two frames — without
  buffering the response and losing streaming.
* **[A prompt firewall](/ai-gateway/firewall) that can refuse**, plus
  [your own scanner](/ai-gateway/guardrail-webhook) if you already run one.
* **Spend caps that actually stop a call**, shared across workers rather than
  counted per process.
* **[Routing and fail-over](/ai-gateway/routing-and-failover)** — retries on 429
  honouring `Retry-After`, weighted load balancing across providers.

## What you lose, stated plainly

Helicone does things we do not, and pretending otherwise would make the rest of
this page less trustworthy:

* **Evaluations and experiments.** No equivalent. If you run prompt experiments
  through Helicone, keep doing that.
* **Prompt management and versioning.** No equivalent.
* **Session-level grouping.** Our usage rows are per call, attributable to a user
  and a team, but multi-turn session rollups are not shipped yet.
* **Its dashboard.** Ours is built around cost, protection outcomes and audit
  rather than around request exploration.

Running both is entirely reasonable: point your SDK at KnoxCall and forward its
logs onward, or keep Helicone on the experiments you are actively running while
production traffic goes through the gateway.

## A word on timing

Helicone's OSS repository has been reported as being in maintenance mode. We are
not going to build a migration argument on a competitor's health — that ages
badly, and it is the sort of claim that turns out to be wrong in public. Check the
repository and their own communications yourself; if it is thriving, migrate for
the reasons in "What you gain", or do not migrate at all.

## Suggested order

1. Create one agent per model-and-purpose, with a secret holding the provider key.
2. Mint one capability token per calling service, scoped to the models that
   service uses.
3. Swap the base URL and drop the `Helicone-Auth` header and the provider key.
4. Rotate the provider key at the provider — it has been in your application's
   environment, so treat it as exposed.
5. Turn on redaction and a firewall policy in `warn`, read the events for a few
   days, then move to `block`.

<Note>
  Step 4 is the one people skip. The reason to move the key into custody is that it
  stops being reachable from your workload — which does nothing for a key that has
  already been sitting in a container's environment for a year.
</Note>
