Skip to main content
Portkey

Portkey's AI gateway → the Naive /llm primitive

Portkey gives an AI agent one OpenAI-compatible endpoint that routes to many models across providers (Portkey’s catalog size varies — check their docs for current counts) — point your client at the gateway, attach a config, and portkey.chat.completions.create({ model, messages }). It does that job well, and the API is clean. But it is also a separate vendor account:
  • LLM routing lives behind its own API key, its own provider keys (virtual keys / Model Catalog), and its own dashboard.
  • Its _user metadata tag scopes observability and budgets for LLM calls and nothing else — it knows what the agent spent on tokens, but not its virtual card, its inbox, its vault secrets, or its KYC status.
  • “Who let this agent burn $400 on GPT-5, and what else can it touch?” is answered in Portkey for tokens, and somewhere else for everything else. There is no shared accountability.
Naive’s /llm primitive gives the agent the same capability — one OpenAI-compatible endpoint, 300+ models, provider routing, fallbacks, streaming — but rooted in one identity:
  • The tenant user that makes the LLM call is the same user that owns its cards, its email inbox, its vault secrets, and its KYC.
  • Whether the agent may call the model at all is decided by that user’s Account Kit at execution time — not by which key happened to be in the request header.
  • Every completion lands in the same per-user activity log as everything else the agent does, and is billed in the same credits as its cards and domains.
This guide maps Portkey’s API to Naive’s, shows the smallest working swap, and is explicit about what does not map yet.
Portkey is a trademark of its owner, used here for identification only. No endorsement or affiliation is implied.
Tested against: Portkey AI Node SDK portkey-ai (gateway base https://api.portkey.ai/v1, PORTKEY_GATEWAY_URL; API surface per portkey.ai/docs, snapshot June 2026) and the Naive Node SDK @usenaive-sdk/server against the Naive API (base https://api.usenaive.ai/v1, docs snapshot June 2026).Version notes:
  • Portkey renamed Virtual Keys → AI Providers / Model Catalog. Models are now referenced as @provider-slug/model-name in the model field; the virtualKey / x-portkey-virtual-key header still works for backward compatibility. This guide notes both.
  • Naive’s /llm is a managed wrapper over OpenRouter, so models use OpenRouter’s provider/model convention (e.g. anthropic/claude-sonnet-4.6) and Naive holds the upstream key — there is no bring-your-own provider key. See gaps.
  • Both are evolving APIs — verify method and model names against your installed SDK version.

Concept map

Before / after: the core path

The path that matters for almost every agent is send a chat completion, with a fallback model if the first is unavailable. Here it is on both platforms.
The completion call lines up almost one to one. The real differences to plan for:
  • No provider keys to manage. In Portkey you create a virtual key / Model Catalog entry per provider and reference it. Naive holds the OpenRouter key server-side and bills you in credits — there is no upstream key to provision or rotate. (The flip side: you cannot bring your own provider key — see gaps.)
  • Fallbacks are an ordered list, not a saved config. Portkey’s config (a pc-… object with strategy/targets) becomes the models: [...] array on the request, plus an optional provider object for OpenRouter routing preferences.
  • Cost is inline and per-user. Portkey surfaces spend in its dashboard keyed by a _user metadata tag. Naive returns credits_used on the response and writes the event to the caller’s activity log — the same log as that user’s cards and email.

Keep your existing OpenAI client (drop-in proxy)

If you already point the OpenAI SDK at Portkey’s gateway, the migration is a two-line change: swap the baseURL and drop createHeaders.
  • The Naive proxy maps every path under /v1/proxy/openrouter/* to OpenRouter, authenticated by your Naive key and billed in credits — paid credits: the proxy is gated exactly like the typed route, so it is not a way to route on the free signup grant.
  • The proxy is not Account-Kit gated. When you want per-tenant policy enforcement, use the typed naive.llm.chat() / POST /v1/llm/chat/completions routes instead — that is the path the consolidation below relies on.

Minimal viable migration

The smallest swap that keeps a working agent running is just change the endpoint and the model slug. You do not need Account Kits or tenant-user fan-out to make your first call.
You do need a paid account. LLM routing is the one Naive primitive the 20 free signup credits do not cover, so a brand-new workspace cannot complete this migration on the trial alone: buy a credit pack (naive billing topup --pack small) or subscribe (naive billing subscribe --plan pro) first. Coming from Portkey you were already paying providers directly, so this is a bill you are moving rather than adding — and one purchase entitles the account permanently, whatever the balance does afterwards. Without it, both the typed route and the proxy answer 402 llm_routing_requires_payment. Browsing models (naive.llm.models()) is free either way.
1

Install the SDK and set your key

Set NAIVE_API_KEY (a server-side key from the dashboard).
2

Translate model slugs

Portkey’s @provider/model (Model Catalog) becomes OpenRouter’s provider/model. Browse the routable set with naive.llm.models("claude") (free) to find exact ids like anthropic/claude-sonnet-4.6 or openai/gpt-5.2.
3

Swap the call

Replace portkey.chat.completions.create({ model, messages }) with naive.llm.chat({ model, messages }), or — if you use the OpenAI SDK — just point baseURL at https://api.usenaive.ai/v1/proxy/openrouter and drop createHeaders.
4

Move fallbacks/routing onto the request

A Portkey fallback config becomes models: ["primary", "backup"]; provider preferences become the provider: { … } object. No saved config object to create.
5

Ship it

At this point you are off Portkey for the core completion path. Everything below is upside, not a requirement.

Consolidate further once you’re on Naive

This is where the migration pays for itself. In Portkey, the _user metadata tag isolates LLM observability and budgets and nothing else. On Naive, the unit of isolation is a tenant user, and it isolates the agent’s entire footprint.

Gain #1 — one identity across primitives

  • With Portkey, the agent’s LLM usage is an island tagged by metadata. With Naive, naive.forUser(acme.id) is a single handle to LLM and cards and email and vault and KYC.
  • You provision a customer’s whole agent footprint from one identity, and tear it down from one place. Sibling tenants can never read each other’s completions, cards, or secrets.

Gain #2 — execution-time permission enforcement

  • Whether an agent may call the model at all is policy on the Account Kit — not a key that happens to be in scope, and not a budget that lives in a separate product.
  • The agent’s code is identical for every tier — client.llm.chat({ model, … }). Whether the call runs is decided by the caller’s kit at execution time:
    • primitives_config.llm.enabled: false returns forbidden for that user — same line of code, no model access.
    • requiresApproval freezes a sensitive sibling action (a card charge, a domain purchase) until a human approves — the API replays it only after approval.
  • Move the user to a kit that disables llm and the exact same line returns forbidden, with no code change on your side. Portkey gates which key is used; Naive additionally gates whether execution happens at all, per user, in the same model as every other primitive.

Gain #3 — unified accountability

  • Every completion for a customer lands in one per-user activity log — alongside their card, email, and vault events, not in a separate LLM dashboard:
  • Spend is unified too: LLM calls bill the same credits as the agent’s cards and domains (Naive bills OpenRouter’s returned usage.cost × a small markup), so “what did this customer’s agent cost us this month?” is one number, not a reconciliation across Portkey, Stripe, and your own ledger.

What does not map yet

A migration guide that hides gaps is worse than none. None of the following block the core path (OpenAI-compatible completions, multi-model fallbacks, provider routing, streaming, and the drop-in proxy all map cleanly), but they are real differences. Check this list against your app before you commit.
If your agent depends on your own provider keys/contracts, prompt templates, gateway-side guardrails or caching, or hard per-key budgets, those are the gaps most likely to matter — the first one (BYO provider keys) is the big architectural difference. The OpenAI-compatible completion loop with multi-model fallbacks and per-user Account-Kit governance — the most common agent LLM pattern — maps cleanly today.

Where to go next