OpenRouter Provider Setup for OpenClaw Models

Learn how to connect OpenRouter to OpenClaw, sign in with a single key, and access many models through one API. Includes model selection and Tailscale HTTPS requirements for browser sign-in.

Read this when

  • You want a single API key for many LLMs
  • You want to run models via OpenRouter in OpenClaw
  • You want to use Jev for typed decisions through OpenRouter
  • You want to use OpenRouter for image generation
  • You want to use OpenRouter for music generation
  • You want to use OpenRouter for video generation

OpenRouter puts many models behind a single API and a single key. Chat traffic goes over the OpenAI-compatible openai-completions transport. Typed Jev decisions travel through the separate System One API instead.

Getting started

Inside a private chat, either send /login openrouter or pick OpenRouter through /login. Hit Sign in with OpenRouter, grant access in your browser, then come back to chat. The browser callback is handled by OpenClaw, which stores the credential and only then reports success. To abandon a sign-in that is still pending, use /login cancel.

Signing in stores access but picks no starter model. Should the current model restrictions hide OpenRouter models, pick Show all OpenRouter models or Keep current restrictions. Either way the credential remains stored. The Control UI offers the same credential-only path under Settings → Models → Connect; afterward, choose a model from the Gateway's catalog in the model menu.

Browser sign-in for chat relies on the Gateway's managed Tailscale HTTPS address. When Tailscale Serve is in use, your browser needs access to that same tailnet. If no managed HTTPS address exists, turn on Serve and try again, or fall back to the CLI flow described below. Note that the callback does not log you in to the Control UI.

The Control UI gets the return automatically when reached at the managed HTTPS address, or when it is opened directly on the local Gateway's loopback address and port. Any other address requires completing the redirect by hand. If what you paste is incomplete or invalid, fix it within the same sign-in attempt and submit once more.

OAuth

Run OAuth onboarding

openclaw onboard --auth-choice openrouter-oauth

OpenClaw launches OpenRouter's browser sign-in flow (PKCE), trades the code for an OpenRouter API key, and saves that key into the default OpenRouter auth profile. On remote or headless hosts, OpenClaw displays the sign-in URL and has you paste the redirect URL once you have signed in.

(Optional) Switch to a specific model

Onboarding starts with openrouter/auto. A concrete model can be chosen afterward:

openclaw models set openrouter/<provider>/<model>

API key

Get your API key

Head to openrouter.ai/keys to create an API key.

Run API-key onboarding

openclaw onboard --auth-choice openrouter-api-key

(Optional) Switch to a specific model

Onboarding starts with openrouter/auto. A concrete model can be chosen afterward:

openclaw models set openrouter/<provider>/<model>

Config example

{
  env: { vars: { OPENROUTER_API_KEY: "sk-or-..." } },
  agents: {
    defaults: {
      model: { primary: "openrouter/auto" },
    },
  },
}

Model references

Note

Model refs are written as openrouter/<provider>/<model>. OpenRouter's model catalog lists every provider and model that OpenRouter routes to. To understand how OpenClaw resolves model refs and handles failover, read Model selection.

Bundled starter models add to a public catalog that is not empty. If a live request fails, the result is reported as a discovery failure; these rows are not used as a substitute. A successful response that returns nothing stays empty:

Model refNotes
openrouter/autoOpenRouter automatic routing
openrouter/moonshotai/kimi-k2.6Kimi K2.6 via MoonshotAI
openrouter/moonshotai/kimi-k2.5Kimi K2.5 via MoonshotAI

Every other openrouter/<provider>/<model> ref, openrouter/openrouter/fusion included (see Fusion router), is resolved on the fly against OpenRouter's live model catalog.

Tool support for discovered models comes from what OpenRouter advertises. If a model's supported_parameters list leaves out tools, OpenClaw's requests carry no tool definitions and no tool choice. Models lacking that metadata fall back to the default tool behavior.

For public openrouter.ai chat-completions routes, OpenClaw transmits function.strict: false alongside tool definitions and keeps the schema's required fields intact, so inputs marked optional remain optional. Custom proxy endpoints retain their current compatibility policy. Supplying an explicit compat.supportsStrictMode: false drops the strict field.

Typed decisions with Jev

Pick Jev as your decision model and reuse the OpenRouter connection and auth profiles you already have. There is no separate TypeSafe login:

{
  agents: {
    defaults: { decisionModel: "openrouter/typesafe/jev-1.14" },
  },
}

The canonical catalog lists openrouter/typesafe/jev-1.13, openrouter/typesafe/jev-1.14, and openrouter/~typesafe/jev-latest as decision-only routes. These never show up as chat choices, and picking a decision model leaves your primary and utility models untouched. The latest alias tracks upcoming releases rather than pinning a version. For reproducible model selection, pin 1.14.

Text, structured JSON objects or arrays, or a single inline PNG/JPEG image with optional text are all accepted by the OpenClaw adapter. Boolean, Choice, and Score questions work on both versions. Box questions are additionally supported by Jev 1.14 and the latest alias. Every question needs instructions. Choice takes 2, 255 options; Score takes 2, 10 non-null levels. Boolean criteria may be left out, but if you include them they must cover both true and false. Sorting, tags and explicit reasoning controls are refused before inference runs. Either omit reasoning or use auto. No free-form prose or reasoning trace comes back from Jev.

OpenClaw issues a single request to /systemone, appended to the effective OpenRouter API base URL, a declared custom proxy path prefix included. A baseUrl override on its own does not declare native decision support: the owning plugin has to publish that route and protocol in its manifest model catalog. Endpoints from elsewhere that lack that declaration are refused. Normal prepared auth and provider routing preferences (privacy restrictions included) are kept. Chat-only parameters that are unsupported get rejected instead of quietly dropped. Nothing is added to the request body: no session IDs, no user identity, no trace fields.

A 262,144-token budget covering state plus questions is declared by this integration. Decoded images must be at most 4 MiB and must satisfy TypeSafe's current dimension requirements; OpenClaw neither downloads remote images nor resizes them. Upstream, image and Box support are experimental. Jev's published input price is $0.042 per million tokens, and output tokens cost nothing. Reported token counts and the actual usage.cost are preserved by the adapter, an explicit zero included. When actual cost is missing it stays missing; the adapter never fabricates a bill or finalizes usage twice.

Call contractVersion: 2 together with the decision_evaluate core tool and tagged state (for example, { type: "text", text: "Ticket contents" }). Plugin consumers ought to use api.runtime.decisions.evaluateV2. Consumers limited to V1 cannot automatically consume OpenRouter results that carry native USD billing or provider metadata. Native model identity, upstream provider, selected labels, fractional scores and rounded distributions are all passed through as-is. The legacy V1 adapter succeeds only if the response can be represented without losing billing or metadata; if not, it returns unsupported-input instead of silently throwing those facts away.

For an image, supply tagged state { type: "image", dataUri: "data:image/png;base64,...", text: "Listing photo" } plus a question such as { type: "box", instructions: "the product in the listing photo" }. Box answers carry box: { top, bottom, left, right }, measured from the top-left corner and normalized against image width and height. An answer of this kind does not prove the target exists: include a Boolean presence question in the same batch. Upstream behavior is covered in Multimodal Decisions and Box.

The known Jev routes are bounded canonical manifest declarations. Ordinary live text catalog handling does not convert decisions output rows into synthetic chat models. For the upstream contract, consult Jev on OpenRouter and the System One API.

Image generation

OpenRouter is able to power the image_generate tool. Under agents.defaults.mediaModels.image, specify an OpenRouter image model:

{
  env: { vars: { OPENROUTER_API_KEY: "sk-or-..." } },
  agents: {
    defaults: {
      mediaModels: {
        image: {
          primary: "openrouter/google/gemini-3.1-flash-image-preview",
          timeoutMs: 180000,
        },
      },
    },
  },
}

Standard OpenRouter image requests go from OpenClaw to the dedicated image API (POST /api/v1/images). Gemini image models also get aspect_ratio and resolution hints, while image edits supply source images as input_references. Results arrive base64-encoded (b64_json) together with an optional media_type; if media_type is missing, OpenClaw detects the image format by inspecting the bytes.

Custom OpenRouter baseUrl destinations that you configure keep the existing chat-completions image route, so proxies lacking the dedicated endpoint still work. For slower models, use agents.defaults.mediaModels.image.timeoutMs; the per-call timeoutMs of the image_generate tool still takes precedence.

Video generation

Through its asynchronous /videos API, OpenRouter is able to power the video_generate tool. Under agents.defaults.mediaModels.video, specify an OpenRouter video model:

{
  env: { vars: { OPENROUTER_API_KEY: "sk-or-..." } },
  agents: {
    defaults: {
      mediaModels: {
        video: {
          primary: "openrouter/google/veo-3.1-fast",
        },
      },
    },
  },
}

Jobs for text-to-video and image-to-video are submitted by OpenClaw, which polls the polling_url it receives back and then downloads the finished video from OpenRouter's unsigned_urls or from the job content endpoint. Reference images are treated as first/last-frame images by default; any image tagged reference_image is instead sent as an input reference. The bundled google/veo-3.1-fast default handles durations of 4/6/8 seconds, 720P/1080P resolutions, and 16:9/9:16 aspect ratios. Video-to-video has no support: text and image references are all the upstream API accepts.

Music generation

Via chat-completions audio output, OpenRouter is able to power the music_generate tool. Under agents.defaults.mediaModels.music, specify an OpenRouter audio model:

{
  env: { vars: { OPENROUTER_API_KEY: "sk-or-..." } },
  agents: {
    defaults: {
      mediaModels: {
        music: {
          primary: "openrouter/google/lyria-3-pro-preview",
          timeoutMs: 180000,
        },
      },
    },
  },
}

google/lyria-3-pro-preview is the default for the bundled OpenRouter music provider, which also exposes google/lyria-3-clip-preview. OpenClaw sends modalities: ["text", "audio"], streams the response, gathers the audio chunks, and stores the result as generated media for delivery to channels. Through the shared music_generate image=... parameter, Lyria models take a single reference image. agents.defaults.mediaMaxMb caps streaming audio, transcript retention, and the derived SSE event envelope (the default audio cap is 16 MB).

Text-to-speech

Through its OpenAI-compatible /audio/speech endpoint, OpenRouter can serve as a TTS provider.

{
  tts: {
    auto: "always",
    provider: "openrouter",
    providers: {
      openrouter: {
        model: "hexgrad/kokoro-82m",
        speakerVoice: "af_alloy",
        responseFormat: "mp3",
      },
    },
  },
}

When tts.providers.openrouter.apiKey is left out, TTS falls back to models.providers.openrouter.apiKey, and then to OPENROUTER_API_KEY.

Speech-to-text (inbound audio)

Inbound voice/audio attachments can be transcribed by OpenRouter through the shared tools.media.audio path, which uses its STT endpoint (/audio/transcriptions). Any channel plugin that forwards inbound voice/audio into media understanding preflight gets this behaviour.

{
  tools: {
    media: {
      models: [
        {
          provider: "openrouter",
          model: "openai/whisper-large-v3-turbo",
          capabilities: ["audio"],
        },
      ],
      audio: { enabled: true },
    },
  },
}

OpenRouter STT requests leave OpenClaw as JSON carrying base64 audio under input_audio (OpenRouter's STT contract); they are not sent as multipart OpenAI form uploads.

Fusion router

A single OpenClaw model ref is sent by OpenRouter Fusion to several OpenRouter models at once, their answers are judged by OpenRouter, and one final response comes back through the normal OpenRouter endpoint. Because the upstream model slug is openrouter/fusion, the OpenClaw model ref carries the OpenClaw provider prefix as well as the upstream OpenRouter namespace:

openclaw models set openrouter/openrouter/fusion

Fusion's panel and judge are configured via the model's params.extraBody; those fields are forwarded straight into the OpenRouter chat-completions request body. Either OAuth or API-key onboarding works with Fusion; when OAuth is in use, leave out the env.vars.OPENROUTER_API_KEY line below.

{
  env: { vars: { OPENROUTER_API_KEY: "sk-or-..." } },
  agents: {
    defaults: {
      model: { primary: "openrouter/openrouter/fusion" },
      models: {
        "openrouter/openrouter/fusion": {
          params: {
            extraBody: {
              plugins: [
                {
                  id: "fusion",
                  analysis_models: [
                    "google/gemini-3.5-flash",
                    "moonshotai/kimi-k2.6",
                    "deepseek/deepseek-v4-pro",
                  ],
                  model: "google/gemini-3.5-flash",
                },
              ],
            },
          },
        },
      },
    },
  },
}

The parallel panel is analysis_models; the judge model is model, set inside the Fusion plugin config. In normal agent/chat turns, do not set top-level tool_choice to "required" as a way to force Fusion: OpenClaw turns may carry their own tool definitions, and a top-level required tool choice could select one of those rather than the Fusion router. Once this Fusion plugin config exists, OpenClaw inserts a sanitized system-prompt note that lists the configured analysis models and the judge model, letting the agent answer questions about its own Fusion panel. No other extraBody fields are copied into the prompt.

Fusion is intentionally slower: OpenRouter fans the prompt out to multiple analysis models and then runs a judge/synthesis step, so latency is higher than with a direct single-model request. Reserve it for deliberate, high-quality answers or escalation paths, not as a latency-sensitive default. A small panel plus faster analysis/judge models gives quicker responses.

Verify a configured ref with a one-shot local call:

openclaw infer model run --local \
  --model openrouter/openrouter/fusion \
  --prompt "Reply with exactly: FUSION_OK" \
  --json

Authentication and headers

OpenRouter authenticates with a Bearer token taken from your API key. OpenRouter OAuth is a PKCE login flow that hands back an OpenRouter API key, so OpenClaw saves the outcome in the same openrouter:default API-key auth profile that manual API-key setup relies on.

To sign in, or to rotate the stored key on an install that already exists, without going through full onboarding again:

openclaw models auth login --provider openrouter --method oauth
openclaw models auth login --provider openrouter --method api-key

When requests go to OpenRouter endpoints (openrouter.ai), OpenClaw attaches the app-attribution headers that OpenRouter documents. This holds for the bundled openrouter provider as well as for custom provider ids whose baseUrl targets OpenRouter:

HeaderValue
HTTP-Refererhttps://openclaw.ai
X-OpenRouter-TitleOpenClaw
X-OpenRouter-Categoriespersonal-agent,cli-agent

Warning

Should you point the OpenRouter provider at a different proxy or base URL, OpenClaw does not add those OpenRouter-specific headers or prompt-cache markers.

Advanced configuration

Response caching

Response caching for OpenRouter is opt-in. Turn it on per model:

{
  agents: {
    defaults: {
      models: {
        "openrouter/auto": {
          params: {
            responseCache: true,
            responseCacheTtlSeconds: 300,
          },
        },
      },
    },
  },
}

OpenClaw sends X-OpenRouter-Cache: true and, where configured, X-OpenRouter-Cache-TTL. responseCacheClear: true forces a refresh for the current request and stores the replacement response. Snake_case aliases (response_cache, response_cache_ttl_seconds, response_cache_clear) are accepted, as is responseCacheTtl / response_cache_ttl without the Seconds suffix. TTL values are truncated and clamped to 1, 86400 seconds; non-finite values are ignored.

This differs from provider prompt caching and from OpenRouter's cache_control prompt-cache markers. It applies only on verified openrouter.ai routes, never on custom proxy base URLs.

Anthropic cache markers

For Anthropic model refs on verified OpenRouter routes, OpenRouter's Anthropic cache_control markers are kept, which improves prompt-cache reuse on system/developer prompt blocks.

Anthropic reasoning prefill

For Anthropic model refs with reasoning enabled on verified OpenRouter routes, trailing assistant prefill turns are dropped before the request reaches OpenRouter. This matches Anthropic's requirement that reasoning conversations end with a user turn.

Thinking / reasoning injection

For its thinking choices and request payloads, OpenClaw uses the reasoning efforts the selected model advertises. The off choice is omitted for models that require reasoning. Agent turns and standalone completions share these controls and reasoning-replay rules. On supported non-auto routes, the selected thinking level is mapped by OpenClaw to OpenRouter proxy reasoning payloads. That injection is skipped for openrouter/auto and for unsupported model hints. Stale openrouter/hunter-alpha refs skip it too, since on that retired route OpenRouter could return final answer text in reasoning fields.

Models that lack an effort selector present on/off controls, or always on where reasoning is mandatory. Such models get binary reasoning controls with no scalar effort. If a thinking request is omitted, their native reasoning default stays as it is; configured reasoning budgets are preserved.

DeepSeek V4 reasoning replay

On verified OpenRouter routes, openrouter/deepseek/deepseek-v4-flash and openrouter/deepseek/deepseek-v4-pro fill in missing reasoning_content on replayed assistant turns, which keeps thinking/tool conversations in the follow-up shape DeepSeek V4 requires. For these routes OpenClaw sends the reasoning.effort values OpenRouter supports: xhigh/max map to xhigh, and every other non-off level maps to high. /think off explicitly sends reasoning.effort: "none" and strips reasoning replay fields rather than falling back to the provider's reasoning default.

OpenAI-only request shaping

OpenRouter goes through the proxy-style OpenAI-compatible path, so native OpenAI-only request shaping is not forwarded. That includes serviceTier, Responses store, OpenAI reasoning-compat payloads, and prompt-cache hints.

Gemini-backed routes

Gemini-backed OpenRouter refs remain on the proxy-Gemini path: Gemini thought-signature sanitation is retained there by OpenClaw, but native Gemini replay validation and bootstrap rewrites are not enabled.

On verified OpenRouter routes, google/gemini* refs (~google/ aliases and :variant suffixes included) get a single cache_control: { type: "ephemeral" } marker on the stable system/developer prompt prefix. Because Gemini honours only the last breakpoint, OpenClaw marks neither tools nor history. cacheRetention: "none" turns this off; "short" and "long" retain the provider's default cache window. The model's minimum cacheable prompt size still applies. See Prompt caching.

Provider routing metadata

OpenRouter accepts a provider request object that controls routing to the underlying provider. To set a default policy for every OpenRouter text-model request, use models.providers.openrouter.params.provider:

{
  models: {
    providers: {
      openrouter: {
        params: {
          provider: {
            sort: "latency",
            require_parameters: true,
            data_collection: "deny",
          },
        },
      },
    },
  },
}

OpenRouter receives that object from OpenClaw as the payload for the request provider. Stick to the snake_case field names OpenRouter documents, which include sort, only, ignore, order, allow_fallbacks, require_parameters, data_collection, quantizations, max_price, preferred_max_latency, preferred_min_throughput, zdr, and enforce_distillable_text.

Params set for an individual model take precedence over the provider-wide routing object:

{
  agents: {
    defaults: {
      models: {
        "openrouter/anthropic/claude-sonnet-4-6": {
          params: {
            provider: {
              order: ["anthropic"],
              allow_fallbacks: false,
            },
          },
        },
      },
    },
  },
}

This behavior is limited to OpenRouter chat-completions routes. Routes that go directly to Anthropic, Google, OpenAI, or a custom provider do not honor OpenRouter routing params.

  • Model selection, Picking providers, model refs, and how failover works.

  • Configuration reference, The complete config reference covering agents, models, and providers.

  • Arcee, Arcee models you can reach with an OpenRouter key.

  • Image generation, Parameters shared by the image tool, plus how a provider is chosen.

  • Video generation, Parameters shared by the video tool, plus how a provider is chosen.

  • Music generation, Parameters shared by the music tool, plus how a provider is chosen.

2,995 words · updated Oct 25, 2026