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, with 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: read per-request cost from the usage log, which also names the provider that served it
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 providersRoutes to matching listings, same as OpenRouter, on the seller's own declaration (not platform-verified). Nothing eligible returns 503 no_zdr_provider_available / no_provider_without_data_collection; a bad data_collection value returns 422
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 stripped from the id and reported in X-Onlist-Warnings
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.

Account and key endpoints

The management surface is OpenRouter-compatible too: same paths, same envelopes, so a script written against OpenRouter works after changing the host.

EndpointOpenRouterOnlist
GET /api/v1/keyInference or management keySame
GET /api/v1/creditsManagement keySame
`GETPOST /api/v1/keys`Management key
`GETPATCHDELETE /api/v1/keys/{hash}`
GET /api/v1/generationid = x-generation-idid = the X-Oneapi-Request-Id response header
GET /api/v1/activityManagement keySame, last 30 complete UTC days (today excluded)
POST /api/v1/auth/keys/codeSessionSame. data.id is the authorization code itself
POST /api/v1/auth/keysUnauthenticated PKCE exchangeSame. user_id in the response is always null
POST /api/v1/credits/coinbaseCrypto top-upNot implemented. Top up in the dashboard

Divergences worth knowing before you port a script:

FieldOpenRouterOnlist
Management key prefixCreated in the OR accountmgmt_..., created under Management keys
limit_reset: "monthly"Supported400. Onlist has no calendar-month window and will not approximate a money cap
limit_reset: "weekly"Resets Monday 00:00 UTCResets Thursday 00:00 UTC (the rolling 7-day budget window)
usage_weeklyISO week (Monday, UTC) — it is a log aggregate, not the billing counter
rate_limit on a keyDeprecated placeholder{ requests: -1, interval: "", note: "deprecated" } — Onlist has no per-key request-rate limit
byok_*, external_user, creator_user_id, workspace_idMeaningfulPresent for compatibility, always 0 / null / "default"
Reachable hostsGlobalhttps://onlist.io only — api.onlist.net relays inference, not management

See Management API for the full reference.

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. Read per-request cost from the usage log, which also names the provider that served the request. 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, and what zdr and data_collection actually do.
  • Usage & cost: Token usage fields, and reading out-of-band cost and provider from the usage log.
  • Errors: The error envelope, string code slugs, and the code-to-HTTP table.
  • Management API: Management keys, the key CRUD endpoints, activity, and OAuth PKCE.