> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opentype.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Select a model

> Classifies a task with Neon 1.1 and selects a model from the benchmark catalog. Requires `runs_write`.

Billed as one decision run: the same admission, quota, credit and settlement as `POST /v1/runs` with `"kind": "decision"`. Send the task as `prompt` or as `messages`, not both. The body may be up to 4 MiB; decisions read up to 262,144 input tokens.

`Idempotency-Key` is optional. Replaying a key returns the stored classification with `replayed: true` and never charges twice.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/router/select
openapi: 3.1.0
info:
  title: OpenType API
  version: 0.1.0
  license:
    name: Apache-2.0
  description: >-
    The OpenType HTTP API: decision runs on Neon 1.1, API keys, usage, quota and
    billing. Every `/v1` route takes `Authorization: Bearer <credential>`, where
    the credential is an API key (`otsk_` followed by 64 hex characters) or a
    console session token. Amounts are integers in micro-USD (1,000,000 = 1 US
    dollar). Errors share one envelope, `{"error": {"code", "message",
    "request_id"}}`. Stripe is named only where it hosts checkout, the billing
    portal and receipts.
servers:
  - url: https://api.opentype.dev
    description: Production
  - url: https://api.opentype.dev
    description: Production
security:
  - bearer: []
  - bearer: []
tags:
  - name: runs
    description: Create, list, retrieve and stream runs.
  - name: keys
    description: Create, list, rotate and revoke API keys.
  - name: usage
    description: Usage rollups, the daily series, the ledger and quota.
  - name: billing
    description: Credit balance, checkout, the billing portal and auto-recharge.
  - name: health
    description: Public liveness and readiness checks.
  - name: router
    description: >-
      Model Router: classify a task with Neon 1.1 and pick a model from the
      benchmark catalog.
paths:
  /v1/router/select:
    post:
      tags:
        - router
      summary: Select a model
      description: >-
        Classifies a task with Neon 1.1 and selects a model from the benchmark
        catalog. Requires `runs_write`.


        Billed as one decision run: the same admission, quota, credit and
        settlement as `POST /v1/runs` with `"kind": "decision"`. Send the task
        as `prompt` or as `messages`, not both. The body may be up to 4 MiB;
        decisions read up to 262,144 input tokens.


        `Idempotency-Key` is optional. Replaying a key returns the stored
        classification with `replayed: true` and never charges twice.
      operationId: select
      parameters:
        - name: Idempotency-Key
          in: header
          description: >-
            Optional. Replaying a key returns the stored classification and
            never charges twice.
          required: false
          schema:
            type:
              - string
              - 'null'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RouterSelectRequest'
        required: true
      responses:
        '200':
          description: The selected model, the classification and the ranking
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterSelectResponse'
        '400':
          description: >-
            Malformed body, invalid_policy, weights_require_balanced,
            unknown_model_id, or no_eligible_model
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '401':
          description: Missing, malformed, or expired credential
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '402':
          description: The organization's credits do not cover the classification
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '403':
          description: The credential lacks runs_write
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '409':
          description: >-
            The idempotency key was used with a different body, or its
            classification is not ready
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '413':
          description: '`body_too_large` (over 4 MiB) or `input_too_large`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '429':
          description: >-
            The organization's spend or token quota for this period cannot cover
            the classification.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '503':
          description: The classifier or a required dependency is unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
        '504':
          description: >-
            `deadline_exceeded`: the classification did not finish within its
            deadline.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunsErrorBody'
      security:
        - bearer: []
        - bearer: []
components:
  schemas:
    RouterSelectRequest:
      type: object
      description: >-
        A selection request: the task, as `prompt` or as `messages` (exactly
        one).
      properties:
        prompt:
          type:
            - string
            - 'null'
          description: >-
            The task. Bodies up to 4 MiB are accepted; only the head and tail of
            the task are read to classify it.
        messages:
          type: array
          items:
            $ref: '#/components/schemas/RunMessage'
          description: >-
            The task as conversation turns, joined into one text as for
            `prompt`.
        policy:
          type:
            - string
            - 'null'
          description: |-
            `balanced` (default), `cost_efficient`, `capability_heavy` or
            `domain_skills`. Anything else is `400` `invalid_policy`.
          example: balanced
        domain:
          type:
            - string
            - 'null'
          description: |-
            v1 override: route as this domain's default task type (`coding`,
            `math`, `reasoning`, `knowledge`, `agentic`, `long_context`,
            `writing`, `multilingual` or `general`). The task type is then not
            classified; difficulty and the facets still are.
        task_type:
          type:
            - string
            - 'null'
          description: |-
            Skip task-type classification and route as this task type (see
            `GET /v1/router/task-types`). Wins over `domain`.
          example: code_generation
        latency:
          type:
            - string
            - 'null'
          description: |-
            `interactive`, `standard` (default) or `batch`: how much estimated
            latency weighs in `balanced`.
          example: standard
        max_latency_ms:
          type:
            - number
            - 'null'
          format: double
          description: |-
            Drop models whose estimated time to the full answer exceeds this, or
            whose speed is not measured.
        weights:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/RouterWeights'
              description: |-
                `balanced` only: replaces the quality, cost and latency weights.
                With any other policy it is `400` `weights_require_balanced`.
        models:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/RouterModelFilters'
      additionalProperties: false
    RouterSelectResponse:
      type: object
      required:
        - id
        - run_id
        - policy
        - model
        - classification
        - ranking
        - score_basis
        - filters_applied
        - low_confidence
        - input_tokens_est
        - reason
        - decision_model
        - catalog_as_of
        - benchmarks_as_of
        - replayed
      properties:
        id:
          type: string
          description: '`rtr_` plus the uuid of the classification run.'
          example: rtr_0f8e3c1a9b2d4e5f8a7b6c5d4e3f2a1b
        run_id:
          type: string
          description: >-
            The classification run, readable at `/v1/runs/{run_id}` and in
            usage.
        policy:
          type: string
        model:
          $ref: '#/components/schemas/RouterModelRef'
        classification:
          $ref: '#/components/schemas/RouterClassification'
        ranking:
          type: array
          items:
            $ref: '#/components/schemas/RouterRankingEntry'
          description: Top candidates, best first, at most ten.
        score_basis:
          $ref: '#/components/schemas/RouterScoreBasis'
        difficulty_floor:
          type:
            - number
            - 'null'
          format: double
          description: v1 name for `threshold.tau` (`balanced`, `cost_efficient`).
        threshold:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/RouterThreshold'
              description: The quality bar (`balanced`, `cost_efficient`).
        filters_applied:
          type: array
          items:
            $ref: '#/components/schemas/RouterFilterCount'
          description: Filters that removed at least one model, in the order applied.
        low_confidence:
          type: boolean
          description: '`domain_skills` with a most probable task type under 40%.'
        input_tokens_est:
          type: integer
          format: int64
          minimum: 0
        reason:
          type: string
        decision_model:
          type: string
          example: neon-1.1
        catalog_as_of:
          type: string
          description: The catalog snapshot date.
        benchmarks_as_of:
          type: string
          description: The benchmark snapshot date.
        usage:
          oneOf:
            - type: 'null'
            - $ref: '#/components/schemas/UsageResponse'
        cost_micros:
          type:
            - integer
            - 'null'
          format: int64
          minimum: 0
        replayed:
          type: boolean
          description: True when an `Idempotency-Key` replayed a stored classification.
    RunsErrorBody:
      type: object
      description: The error envelope, shared by every route. Branch on `error.code`.
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/RunsErrorDetail'
    RunMessage:
      type: object
      description: One prompt turn. Unknown keys are refused.
      required:
        - role
        - content
      properties:
        role:
          $ref: '#/components/schemas/MessageRole'
        content:
          type: string
      additionalProperties: false
    RouterWeights:
      type: object
      description: The caller's own `balanced` trade-off, normalized to sum to 1.
      properties:
        quality:
          type: number
          format: double
        cost:
          type: number
          format: double
        speed:
          type: number
          format: double
      additionalProperties: false
    RouterModelFilters:
      type: object
      description: >-
        Filters over the catalog. All optional; an empty object keeps every
        model.
      properties:
        include:
          type: array
          items:
            type: string
          description: |-
            Only these model ids. An id the catalog does not list is `400`
            `unknown_model_id`.
        exclude:
          type: array
          items:
            type: string
          description: Never these model ids. Same check as `include`.
        providers:
          type: array
          items:
            type: string
          description: Only these providers, e.g. `openai`, case-insensitive.
        open_weights:
          type:
            - boolean
            - 'null'
          description: '`true`: open-weights models only; `false`: closed only.'
        max_price_per_mtok:
          type:
            - number
            - 'null'
          format: double
          description: Maximum blended price (3:1 input:output), USD per million tokens.
        min_context_tokens:
          type:
            - integer
            - 'null'
          format: int64
          minimum: 0
        modalities:
          type: array
          items:
            type: string
          description: |-
            Every listed modality must be supported: `text`, `image`, `audio`,
            `video`.
      additionalProperties: false
    RouterModelRef:
      type: object
      description: A model, as a selection names it.
      required:
        - id
        - name
        - provider
        - open_weights
      properties:
        id:
          type: string
          example: gpt-6-sol
        name:
          type: string
          example: GPT-6 Sol
        provider:
          type: string
          example: openai
        open_weights:
          type: boolean
    RouterClassification:
      type: object
      required:
        - domain
        - difficulty
        - task_type
        - facets
      properties:
        domain:
          $ref: '#/components/schemas/RouterLabel'
          description: v1 vocabulary, derived from the task-type distribution.
        difficulty:
          $ref: '#/components/schemas/RouterLabel'
          description: v1 vocabulary (`easy`, `medium`, `hard`), derived from the level.
        task_type:
          $ref: '#/components/schemas/RouterTaskType'
        facets:
          $ref: '#/components/schemas/RouterFacets'
    RouterRankingEntry:
      type: object
      description: One ranked candidate.
      required:
        - id
        - name
        - provider
        - open_weights
        - score
        - blended_price_per_mtok
        - domain_score
        - expected_quality
        - uncertainty
        - estimated_cost_usd
        - estimated_latency_ms
        - latency_estimated
        - strengths
        - weaknesses
        - imputed
      properties:
        id:
          type: string
        name:
          type: string
        provider:
          type: string
        open_weights:
          type: boolean
        score:
          type: number
          format: double
          description: |-
            The policy's sort key, higher is better. For `cost_efficient` it is
            the negated estimated cost.
        blended_price_per_mtok:
          type: number
          format: double
        domain_score:
          type: number
          format: double
          description: v1 name for `expected_quality`.
        expected_quality:
          type: number
          format: double
          description: |-
            Weighted normalized benchmark quality for this task, 0-1, minus the
            imputation penalty.
        uncertainty:
          type: number
          format: double
          description: 'Weight on imputed values: 0 when every benchmark was measured.'
        estimated_cost_usd:
          type: number
          format: double
          description: |-
            USD for this request: input, expected output, reasoning tokens and
            expected turns.
        estimated_latency_ms:
          type: number
          format: double
          description: Milliseconds to the full answer.
        latency_estimated:
          type: boolean
          description: A catalog median stood in for a missing speed or TTFT.
        strengths:
          type: array
          items:
            $ref: '#/components/schemas/RouterBenchmarkContribution'
          description: Top three benchmarks by contribution.
        weaknesses:
          type: array
          items:
            $ref: '#/components/schemas/RouterBenchmarkContribution'
          description: Up to two benchmarks where it trails the best candidate most.
        imputed:
          type: array
          items:
            $ref: '#/components/schemas/RouterImputed'
    RouterScoreBasis:
      type: string
      description: |-
        Which benchmarks decided. v2 always decides on the task's weighted
        benchmark vector; `domain` and `intelligence` are the v1 values.
      enum:
        - domain
        - intelligence
        - benchmarks
    RouterThreshold:
      type: object
      description: The quality bar in force (`balanced`, `cost_efficient`).
      required:
        - q_star
        - r
        - tau
      properties:
        q_star:
          type: number
          format: double
          description: Best expected quality among the filtered models.
        r:
          type: number
          format: double
          description: Required share of `q_star` at this difficulty.
        tau:
          type: number
          format: double
    RouterFilterCount:
      type: object
      description: How many models one filter removed.
      required:
        - filter
        - removed
      properties:
        filter:
          type: string
        removed:
          type: integer
          minimum: 0
    UsageResponse:
      type: object
      description: Tokens the run used.
      required:
        - input_tokens
        - output_tokens
      properties:
        input_tokens:
          type: integer
          format: int64
          minimum: 0
        output_tokens:
          type: integer
          format: int64
          minimum: 0
    RunsErrorDetail:
      type: object
      required:
        - code
        - message
        - request_id
      properties:
        code:
          type: string
          description: Stable snake_case code. The only field to branch on.
        message:
          type: string
        request_id:
          type: string
        violations:
          type: array
          items:
            type: string
          description: >-
            Only on `verdict_schema_violation`: up to 10 JSON Pointers into the
            rejected document.
    MessageRole:
      type: string
      enum:
        - user
        - assistant
    RouterLabel:
      type: object
      description: One classified label and the distribution it was the argmax of.
      required:
        - label
        - probabilities
      properties:
        label:
          type: string
        probabilities:
          type: object
          description: >-
            Probability per label. For a caller-fixed label this is that label
            at

            `1.0`.
          additionalProperties:
            type: number
            format: double
          propertyNames:
            type: string
    RouterTaskType:
      type: object
      description: 'The task-type distribution: the argmax and the five most probable.'
      required:
        - label
        - family
        - top
        - fixed
      properties:
        label:
          type: string
          example: code_generation
        family:
          type: string
        top:
          type: array
          items:
            $ref: '#/components/schemas/RouterTaskTypeProbability'
          description: |-
            The five most probable types, most probable first. The ranking mixes
            every type at 5% or more.
        fixed:
          type: boolean
          description: True when the caller fixed the task type (`task_type` or `domain`).
    RouterFacets:
      type: object
      description: The facets the ranking conditions on.
      required:
        - difficulty_expected
        - difficulty
        - output_length
        - output_tokens_est
        - needs_tools
        - needs_vision
        - safety_sensitive
        - language
        - input_tokens_est
      properties:
        difficulty_expected:
          type: number
          format: double
          description: |-
            Expected level on the 0-3 scale (trivial, standard, hard, expert),
            after the safety floor.
        difficulty:
          $ref: '#/components/schemas/RouterLabel'
          description: '`trivial`, `standard`, `hard` or `expert`.'
        output_length:
          $ref: '#/components/schemas/RouterLabel'
          description: '`short`, `medium`, `long` or `huge`.'
        output_tokens_est:
          type: number
          format: double
          description: Expected visible output tokens.
        needs_tools:
          type: number
          format: double
        needs_vision:
          type: number
          format: double
        safety_sensitive:
          type: number
          format: double
        language:
          type: string
          description: 'Language the task is written in: `en`, `fr`, `zh`, `es` or `other`.'
        target_language:
          type:
            - string
            - 'null'
          description: Translation target, when the task asks for one.
        input_tokens_est:
          type: integer
          format: int64
          minimum: 0
    RouterBenchmarkContribution:
      type: object
      description: One benchmark's part in a candidate's expected quality.
      required:
        - benchmark
        - name
        - norm
        - weight
        - contribution
      properties:
        benchmark:
          type: string
          example: swe_bench_verified
        name:
          type: string
          example: SWE-bench Verified
        value:
          type:
            - number
            - 'null'
          format: double
          description: The published value, null when imputed.
        rank:
          type:
            - integer
            - 'null'
          format: int32
          description: Rank among catalog models with a published value, null when imputed.
          minimum: 0
        norm:
          type: number
          format: double
          description: Normalized value, 0-1.
        weight:
          type: number
          format: double
          description: Weight of the benchmark for this task.
        contribution:
          type: number
          format: double
          description: weight × norm.
        gap_to_best:
          type:
            - number
            - 'null'
          format: double
          description: 'Weaknesses only: weight × (this model − the best candidate).'
    RouterImputed:
      type: object
      description: A benchmark value that was imputed for a candidate.
      required:
        - benchmark
        - rule
      properties:
        benchmark:
          type: string
        rule:
          type: string
          description: '`correlated`, `family` or `index`.'
        from:
          type:
            - string
            - 'null'
    RouterTaskTypeProbability:
      type: object
      description: One task type and its probability.
      required:
        - task_type
        - family
        - probability
      properties:
        task_type:
          type: string
          example: code_generation
        family:
          type: string
          example: coding
        probability:
          type: number
          format: double
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      description: An API key (otsk_ + 64 hex) or a console session token.

````