Skip to main content
Not every prompt needs a $15/M-token model. A “fix this typo” request and a “design an event sourcing system” request look identical to your API call, but one costs 10x more than it should. The Morph Router classifies prompt difficulty, ambiguity, and domain in a single ~180ms call, then tells you which model to send it to. Trained on millions of coding prompts. $0.005 per request. Pricing: $0.005/request | Max input: 65,536 tokens
Radar chart comparing candidate model routing profiles

Quick Start

Ask the router which model to use, then call it:
Two endpoints. /v1/router/multimodel hands Morph your model list and returns the one to call. /v1/router/classify returns the raw classifier labels and leaves the mapping to you.

/router/multimodel

Hand the router your candidate models (or whole providers) plus a policy. It classifies the prompt and returns the single best model to call, with no mapping table to maintain. Request allowed_models and allowed_providers are unioned: a model qualifies if it matches either. Leaving both empty considers the whole catalog, which is the right way to explore the API and the wrong way to run it in production. Two or three candidates is the shape that holds up. See Best practices. Model catalog Policies Selection scores every candidate on how far it sits from the request’s difficulty and ambiguity tier, whether it covers the domain, and what it costs. The policy sets the weights: balanced and cost_efficient have domain weight 0, so they return the same model for every domain at a given difficulty and ambiguity. Where each request lands With the full catalog allowed under balanced: GLM-5.2 owns the medium tier outright and takes hard work at low ambiguity. Opus keeps hard x med-ambiguity. High ambiguity always escalates to Fable 5, the strongest model for prompts whose intent is unclear. Switch to cost_efficient and five cells move: medium x low drops to deepseek-v4-pro, hard x med drops to glm-5.2, and the high-ambiguity column above easy goes to kimi-k3, which covers the same cells as Fable 5 at less than half the price. Restrict to allowed_providers: ["anthropic"] and you get Sonnet everywhere except hard x med (Opus) and high ambiguity (Fable 5).
Response
model is what you call next. The classifier signals are echoed back so you can act on them too, e.g. show a “let’s clarify” prompt when difficulty is needs_info. ambiguity and domain are present only when those heads cleared their threshold; treat a missing field as “no signal.” If the prompt resolves to needs_info and you passed a default_model, that model is returned as-is.

Best practices

Routing saves money by moving requests off models they don’t need. It loses money when the switching itself costs more than the tier difference. Four rules keep it on the right side of that line.

Route between two or three models, not ten

Every extra candidate is another prefix cache, another failure mode, and another surface to evaluate. Two tiers, cheap and strong, capture most of the available savings. A third earns its place only when it owns a cell the other two are genuinely bad at. Passing the whole catalog looks like more optimization and is usually less: it maximizes how often the model changes, which is the thing that costs you (see the next rule). In production, pin a set:

Be cache-aware: a model switch is a full re-prefill

The router returns a model per call, but calling it per turn is usually wrong. Switching models mid-session invalidates the upstream KV prefix cache, so the next turn re-prefills the entire conversation from scratch at the full input rate. The size of that mistake: on Morph’s own models, cached input is 0.22/Magainst0.22/M against 1.10/M uncached, an 80% discount you forfeit on every switch. A 60k-token agent session that “saves” money by moving from a 15/Mmodeltoa15/M model to a 6/M model pays for 60k tokens of fresh prefill to do it, and can come out behind. Classify at session and task boundaries. Not every turn.

Know your cache-breaking events

A switch is free when the cache was already cold, and expensive when it wasn’t. These are the moments that decide which: Details on all of these: Prompt Caching.

Pin the model once the context is expensive

Past roughly 60k tokens, prefill dominates any per-token rate difference. Stop re-classifying and hold whatever the session is already on. Morph’s own Claude Code proxy ships this as a context lock: once a turn’s context passes the threshold it skips the classify call entirely and keeps the route, so the prefix cache keeps hitting. If your context is the problem, shrink it rather than re-route around it. Compact cuts 50-70% and is itself a clean boundary to re-route on.

Labels

The classifier heads return these labels. /v1/router/multimodel maps them for you; /v1/router/classify hands them over raw. Difficulty Ambiguity Domain

/router/classify

Runs the requested classifier heads against your prompt and returns the raw labels. Use this when you already have a model mapping you trust and only want the signals. Request
Response
Each head returns label, class_id, confidence, and meets_threshold (whether confidence cleared the head’s threshold). When difficulty does not meet its threshold, treat it as needs_info: the prompt is too ambiguous to size confidently.

Production example

Route once per session, then reuse the decision for every turn in it. This is the shape that actually saves money, because the model only changes when the cache was going to be cold anyway.
Wrap the router call in a try/catch and fall back to a safe default model if it ever fails. default_model already covers the needs_info case, not a transport failure.

Integrate with Claude Code

Route every Claude Code turn through the router with no change to how developers work. A local proxy sits between Claude Code and Anthropic (ANTHROPIC_BASE_URL points at it), classifies each turn, and picks the cheapest Claude model, and reasoning effort, that can handle it, following your org’s routing policy. Requires macOS or Linux, Node 22+, and the claude CLI. 1. Install with your Morph API key:
The installer pulls the latest routing runtime, verifies its sha256, installs it under ~/.morph/ccr-router, and gives you a morph-claude command. Re-running the one-liner upgrades in place. 2. Authenticate upstream. By default the proxy uses your Claude Pro/Max subscription: run claude login once. To use your org’s Anthropic key instead, add it to the install:
3. Run morph-claude instead of claude:
Each turn is classified on difficulty, ambiguity, and domain, matched against your org’s routing matrix to a {model, effort}, then clamped to the models that user is permitted. One decision per turn, 1.5s classify timeout; if the classify ever fails, routing fails open to your default model. The proxy is cache-aware by default. Once a turn’s context passes the context lock threshold (60k tokens out of the box) it stops classifying and holds the session’s current model, so the upstream prefix cache keeps hitting instead of being thrown away for a cheaper per-token rate that no longer pays for itself. Set the policy. Admins configure the routing matrix and per-user permissions in the dashboard under Administration → Model Router. Edits reach every developer within the hour, with no redeploy and no reinstall. The Analytics tab shows the model mix, turn volume, and estimated savings vs sending every turn to Opus. Prefer to own the policy? Point the proxy at a local router-matrix.json or an endpoint you host via MORPH_MATRIX_FILE / MORPH_MATRIX_URL.
Routing metrics are metadata-only. No prompt or completion text ever leaves the machine. Set MORPH_METRICS_DISABLED=1 to send nothing at all.

Edge / Cloudflare Workers

fetch is available natively at the edge, so you can call the router from a Cloudflare Worker, Vercel Edge Function, or Deno with no SDK:
The @morphllm/morphsdk/edge build ships a RawRouter helper, but it targets the legacy /router/raw endpoint. For the current endpoints, call them directly with fetch as shown above.

API Reference

Both endpoints are POST https://api.morphllm.com/... with an Authorization: Bearer YOUR_API_KEY header.
Inputs over 65,536 tokens return 413. An unknown classes value or a default_model outside the allow filter returns 400.

When to Use

Use the router when:
  • Processing varied user requests (simple typo fixes to complex architecture tasks)
  • You want to minimize API costs without manually classifying prompts
  • Building cost-conscious AI products with mixed complexity workloads
Skip the router when:
  • All tasks need the same model tier (e.g., always Opus for agentic coding)
  • The ~180ms routing latency matters more than cost savings
  • You need deterministic model selection for testing or compliance

Performance

  • Latency: ~180ms average, one call per routing decision
  • Parallel: Can run in parallel with other work
  • HTTP/2: Connection reuse for subsequent calls

Deprecated endpoints

/v1/router/raw and /v1/router/{provider} are superseded by /v1/router/classify and /v1/router/multimodel. They remain fully supported for backward compatibility, so existing integrations keep working with no changes, but new code should use the endpoints above. The provider endpoints will be removed in a future release.

/router/raw

Returns just a difficulty label. Use /v1/router/classify instead for new code.
Returns: { "difficulty": "easy", "confidence": 0.93 }
Modesbalanced (default) balances cost and quality; aggressive optimizes harder for cost, pushing more prompts to easy. Returns difficulty (easy | medium | hard | needs_info). For edge environments (Cloudflare Workers, Vercel Edge, Deno), use @morphllm/morphsdk/edge:

/router/

Returns a provider-specific model name directly instead of a difficulty label. Registered for openai, anthropic, and gemini only; there is no /v1/router/zai, /v1/router/deepseek, or /v1/router/moonshot. Use /v1/router/multimodel with allowed_providers instead: it does the same model selection with control over the candidate set and policy. Under the hood these now call the multimodel router constrained to that provider, so they keep working with no changes on your side.
Returns: { "model": "claude-haiku-4-5-20251001", "confidence": 0.93 } The SDK still exposes morph.routers.anthropic.selectModel(), morph.routers.openai.selectModel(), and morph.routers.gemini.selectModel() for backwards compatibility. Migrate to /v1/router/multimodel.

See Also