Migrate from OpenRouter

Onlist speaks the same OpenAI- and OpenRouter-compatible /v1 surface you already call. Migrating is a two-line change: point your SDK at https://onlist.io and swap in an Onlist token. Your request bodies, response shapes, and the official SDKs stay the same.

This page shows the swap, lists what carries over unchanged, and documents every way Onlist behaves differently from OpenRouter. The differences are real and specific; we list them all rather than imply parity we do not deliver.

The swap

Change two values. Everything else in your code is untouched.

from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key="sk-or-v1-...",
)

resp = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)

Only base_url and api_key changed. The Onlist token is a plain bearer token issued in the buyer dashboard — there is no sk-or- prefix (a leading sk- is tolerated and stripped). See Authentication for header normalization across the OpenAI, Anthropic, and Gemini SDKs.

What stays the same

These work on Onlist exactly as they do on OpenRouter — no code changes:

  • Official SDKs. There is no bespoke Onlist SDK. Use the official OpenAI, Anthropic, and Gemini SDKs pointed at Onlist via base_url.
  • Request and response bodies. The OpenAI chat/completions, Anthropic Messages, and Gemini generateContent schemas are unchanged. Modeled fields are forwarded upstream.
  • The provider object. The OpenRouter-compatible provider routing object is read on JSON endpoints, with the same field names.
  • The models[] fallback list. The top-level models array is honored as a try-in-order fallback (the body model is rewritten per attempt), gated by provider.allow_fallbacks.
  • Streaming. stream: true returns an SSE stream of chunks terminated by data: [DONE]. See Streaming.
  • Tools and structured outputs. Tool/function calling and JSON/structured-output request fields pass through unchanged.

What is different

Every documented divergence from OpenRouter. Each row pairs the OpenRouter behavior with what Onlist does instead.

AreaOpenRouterOnlist
Token prefixTokens are prefixed sk-or-...Plain bearer token, no sk-or- prefix (a leading sk- is tolerated and stripped)
Unknown provider fieldsValidated; bad fields can errorAccepted and silently ignored (not 400), then reported in X-Onlist-Warnings
provider.only[]Multi-provider allowlistSingle pin — only only[0] is honored; the rest are dropped and reported as ignored: provider.only[1:N]. Use provider.allow for a multi-provider allowlist
onlist/auto / openrouter/autoPer-prompt smart model selectionOne static platform-default model, not per-prompt selection (422 on endpoints that do not support it)
usage.costReturned in the response bodyNot in the response body. Cost is out of band — correlate a request to its cost via the X-Onlist-Route-Id header
stream_options.include_usageOptional; you set itForced to true when streaming (a terminal usage chunk is required for platform settlement)
Privacy (zdr, data_collection)Routes to matching providersUniversal provider self-attestation — accepted but not platform-verified and not end-to-end (the upstream may still retain). Does not influence routing; warned
Rate-limit headersX-RateLimit-* headersNo X-RateLimit-* headers. Only Retry-After on 429/503
/v1/moderationsAvailableNot yet available — returns 502
/v1/audio/transcriptions, /v1/audio/translationsAvailableNot yet available — return 501
plugins and the :online model suffixWeb search / file parsingNot supported. Plugins are a no-op; :online is unsupported
min_p, top_a, repetition_penaltyForwarded as sampling extensionsDropped. These (and other unknown top-level body keys) are silently removed, with no X-Onlist-Warnings entry for those top-level drops

require_parameters and quantizations are likewise accepted but not implemented (silently ignored, with a warning). For the full provider field reference and how to read X-Onlist-Warnings, see Provider routing.

The three that change behavior most

Caution

Three differences will surprise you if you assume OpenRouter behavior:

  • provider.only is a single pin. Only the first slug is routed to; additional entries are dropped and reported in X-Onlist-Warnings. If you relied on a multi-provider allowlist, switch to provider.allow. See Provider routing.
  • auto is a static default, not smart selection. onlist/auto and openrouter/auto resolve to one fixed platform-default model. If your code expects per-prompt model picking, name a specific model instead. See Models.
  • usage.cost is out of band. Cost is not in the response body. Capture the X-Onlist-Route-Id response header and look the cost up afterward. See Usage & cost and Errors.

Next steps

  • Provider routing — Every provider field, single-pin semantics, and how to read X-Onlist-Warnings.
  • Privacy & data handling — The provider self-attestation model — what zdr and data_collection actually do.
  • Usage & cost — Token usage fields, out-of-band cost, and correlating via X-Onlist-Route-Id.
  • Errors — The error envelope, string code slugs, and the code-to-HTTP table.