openapi: 3.1.0
info:
  title: UsageTap Realtime Model Alternative API
  version: 1.0.0
  description: >-
    Public model lifecycle, preferred-key, replacement, and alternative
    resolution. No UsageTap account or API key is required.
  license:
    name: UsageTap Terms
    url: https://usagetap.com/terms
externalDocs:
  description: Implementation guide and complete field reference
  url: https://usagetap.com/docs/MODEL_ALTERNATIVES_API
servers:
  - url: https://api.usagetap.com
paths:
  /v1/model-alternatives:
    get:
      operationId: discoverModelAlternativesApi
      summary: Discover the public API contract
      description: Returns supported purposes, defaults, query parameters, and lifecycle transitions.
      responses:
        "200":
          description: API discovery document
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /v1/model-alternatives/{provider}/{model}:
    get:
      operationId: resolveModelAlternative
      summary: Resolve lifecycle and alternatives for one provider model key
      parameters:
        - name: provider
          in: path
          required: true
          description: Provider namespace.
          schema:
            type: string
            enum: [openai, anthropic, google]
        - name: model
          in: path
          required: true
          description: Provider model ID or alias. URL-encode this path segment.
          schema:
            type: string
            minLength: 1
            maxLength: 300
          example: gpt-5.6-terra
        - name: response
          in: query
          description: Compact real-time decision or complete inspection payload.
          schema:
            type: string
            enum: [full, light]
            default: full
        - name: purpose
          in: query
          description: Decision the caller is making.
          schema:
            $ref: "#/components/schemas/ResolvePurpose"
        - name: inputTokens
          in: query
          schema:
            type: number
            minimum: 0
            maximum: 10000000
            default: 8000
        - name: outputTokens
          in: query
          description: Input and output tokens cannot both be zero.
          schema:
            type: number
            minimum: 0
            maximum: 10000000
            default: 2000
        - name: cachedInputPercent
          in: query
          schema:
            type: number
            minimum: 0
            maximum: 100
            default: 30
        - name: maxPriceIncreasePercent
          in: query
          schema:
            type: number
            minimum: 0
            maximum: 1000
            default: 20
        - name: requiredParameters
          in: query
          description: Comma-separated API capabilities.
          schema:
            type: string
          example: tools,structured_outputs
        - name: minimumContext
          in: query
          schema:
            type: number
            minimum: 0
            maximum: 10000000
        - name: minimumOutput
          in: query
          schema:
            type: number
            minimum: 0
            maximum: 10000000
        - name: endpoint
          in: query
          description: Required provider endpoint or operation.
          schema:
            type: string
            pattern: "^[a-zA-Z0-9_./-]{1,100}$"
          example: chat/completions
        - name: allowedProviders
          in: query
          description: Comma-separated provider namespaces.
          schema:
            type: string
          example: openai,anthropic
        - name: allowedModelKeys
          in: query
          description: Comma-separated, application-evaluated model keys.
          schema:
            type: string
          example: openai/gpt-5.6-terra,anthropic/claude-sonnet-4-6
        - name: allowPreview
          in: query
          schema:
            type: boolean
            default: false
        - name: allowAutoApply
          in: query
          description: Requests eligibility evaluation; never performs a change or retry.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: Model resolution. Inspect degraded before acting.
          headers:
            ETag:
              description: Validator for conditional requests.
              schema:
                type: string
            Cache-Control:
              schema:
                type: string
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/LightModelAlternativeResolution"
                  - $ref: "#/components/schemas/FullModelAlternativeResolution"
              examples:
                light:
                  summary: Compact application decision
                  value:
                    schemaVersion: 1
                    catalogVersion: "2026-09-16"
                    response: light
                    requested:
                      modelKey: openai/gpt-5.6-terra
                    lifecycle:
                      status: ACTIVE
                      source:
                        label: OpenAI API deprecations
                        url: https://developers.openai.com/api/docs/deprecations
                        checkedAt: "2026-09-16"
                    action: KEEP
                    decisionId: 8ecaa12077282770a4750685
                    generatedAt: "2026-09-17T19:00:00.000Z"
                    validUntil: "2026-09-17T19:05:00.000Z"
                    degraded: false
                    automation:
                      autoApplyRecommended: false
                preferredAlias:
                  summary: Provider-verified preferred key
                  value:
                    schemaVersion: 1
                    catalogVersion: "2026-09-16"
                    response: light
                    requested:
                      modelKey: anthropic/claude-haiku-4-5-20251001
                    lifecycle:
                      status: ACTIVE
                    action: KEEP
                    keyGuidance:
                      requestedModelKey: anthropic/claude-haiku-4-5-20251001
                      preferredModelKey: anthropic/claude-haiku-4-5
                      resolvedModelKey: anthropic/claude-haiku-4-5-20251001
                      relationship: provider_alias
                      confidence: provider_verified
                      shouldUpdate: true
                      note: The provider verifies this shorter alias for the same model.
                    degraded: false
                    automation:
                      autoApplyRecommended: false
        "304":
          description: The If-None-Match validator still matches. Response body is empty.
        "400":
          description: Invalid model key or request parameters.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "405":
          description: Only GET is supported.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
components:
  schemas:
    ResolvePurpose:
      type: string
      enum: [upgrade, fallback, retirement]
      default: upgrade
    LifecycleStatus:
      type: string
      enum: [ACTIVE, DEPRECATED, RETIRED, UNKNOWN]
    ResolutionAction:
      type: string
      enum: [KEEP, REPLACE, REVIEW]
    RecommendationSource:
      type: string
      enum: [provider, admin_review, computed, none]
    RequestedLight:
      type: object
      required: [modelKey]
      properties:
        modelKey:
          type: string
    RequestedFull:
      type: object
      required: [modelKey, model]
      properties:
        modelKey:
          type: string
        provider:
          type: string
          enum: [openai, anthropic, google]
        model:
          type: string
    LifecycleLight:
      type: object
      required: [status]
      properties:
        status:
          $ref: "#/components/schemas/LifecycleStatus"
        announcedAt:
          type: string
          format: date
        shutdownAt:
          type: string
          format: date
        source:
          $ref: "#/components/schemas/LifecycleSource"
    LifecycleFull:
      type: object
      required: [status]
      properties:
        status:
          $ref: "#/components/schemas/LifecycleStatus"
        announcedAt:
          type: string
          format: date
        shutdownAt:
          type: string
          format: date
        source:
          $ref: "#/components/schemas/LifecycleSource"
    LifecycleSource:
      type: object
      required: [label, url, checkedAt]
      properties:
        label:
          type: string
        url:
          type: string
          format: uri
        checkedAt:
          type: string
          format: date
    ModelKeyGuidance:
      type: object
      required:
        - requestedModelKey
        - preferredModelKey
        - resolvedModelKey
        - relationship
        - confidence
        - shouldUpdate
        - note
      properties:
        requestedModelKey:
          type: string
        preferredModelKey:
          type: string
        resolvedModelKey:
          type: string
        relationship:
          type: string
          const: provider_alias
        confidence:
          type: string
          const: provider_verified
        shouldUpdate:
          type: boolean
        note:
          type: string
    LightAutomation:
      type: object
      required: [autoApplyRecommended]
      properties:
        autoApplyRecommended:
          type: boolean
    FullAutomation:
      type: object
      required: [canResolveWithoutUsageTapAccount, autoApplyRecommended, note]
      properties:
        canResolveWithoutUsageTapAccount:
          type: boolean
          const: true
        autoApplyRecommended:
          type: boolean
        note:
          type: string
    LightModelAlternativeResolution:
      type: object
      required:
        - schemaVersion
        - catalogVersion
        - response
        - requested
        - lifecycle
        - action
        - degraded
        - automation
      properties:
        schemaVersion:
          type: integer
          const: 1
        catalogVersion:
          type: string
        response:
          type: string
          const: light
        requested:
          $ref: "#/components/schemas/RequestedLight"
        lifecycle:
          $ref: "#/components/schemas/LifecycleLight"
        action:
          $ref: "#/components/schemas/ResolutionAction"
        keyGuidance:
          $ref: "#/components/schemas/ModelKeyGuidance"
        recommendedModelKey:
          type: string
        providerReplacementModelKey:
          type: string
        recommendationSource:
          $ref: "#/components/schemas/RecommendationSource"
        decisionId:
          type: string
        generatedAt:
          type: string
          format: date-time
        validUntil:
          type: string
          format: date-time
        degraded:
          type: boolean
        automation:
          $ref: "#/components/schemas/LightAutomation"
    ModelAlternativeCandidate:
      type: object
      required: [modelKey, provider, relation, confidence, rationale, requiresEvaluation]
      properties:
        modelKey:
          type: string
        provider:
          type: string
          enum: [openai, anthropic, google]
        relation:
          type: string
          enum: [official_replacement, same_provider_similar, similar_price_and_strength]
        confidence:
          type: string
          enum: [authoritative, reviewed, candidate]
        rationale:
          type: string
        requiresEvaluation:
          type: boolean
        score:
          type: number
        priceDistancePercent:
          type: number
        inputUsdPerMillion:
          type: number
        outputUsdPerMillion:
          type: number
        category:
          type: string
          enum: [upgrade, variant, alternative]
        compatibility:
          $ref: "#/components/schemas/Compatibility"
        availability:
          type: string
          enum: [available, unknown]
        estimatedRequestUsd:
          type: number
        priceChangePercent:
          type: number
        reasons:
          type: array
          items:
            type: string
    Compatibility:
      type: object
      required: [status, gaps, unknowns]
      properties:
        status:
          type: string
          enum: [compatible, unknown, incompatible]
        gaps:
          type: array
          items:
            type: string
        unknowns:
          type: array
          items:
            type: string
    RecommendationPolicy:
      type: object
      required:
        - purpose
        - inputTokens
        - outputTokens
        - cachedInputPercent
        - maxPriceIncreasePercent
        - requiredParameters
        - allowedProviders
        - allowedModelKeys
        - allowPreview
        - allowAutoApply
      properties:
        purpose:
          $ref: "#/components/schemas/ResolvePurpose"
        inputTokens:
          type: number
        outputTokens:
          type: number
        cachedInputPercent:
          type: number
        maxPriceIncreasePercent:
          type: number
        requiredParameters:
          type: array
          items:
            type: string
        allowedProviders:
          type: array
          items:
            type: string
        allowedModelKeys:
          type: array
          items:
            type: string
        minimumContext:
          type: number
        minimumOutput:
          type: number
        endpoint:
          type: string
        allowPreview:
          type: boolean
        allowAutoApply:
          type: boolean
    FullModelAlternativeResolution:
      type: object
      required:
        - schemaVersion
        - catalogVersion
        - requested
        - lifecycle
        - action
        - equivalents
        - alternatives
        - automation
      properties:
        schemaVersion:
          type: integer
          const: 1
        catalogVersion:
          type: string
        requested:
          $ref: "#/components/schemas/RequestedFull"
        lifecycle:
          $ref: "#/components/schemas/LifecycleFull"
        action:
          $ref: "#/components/schemas/ResolutionAction"
        keyGuidance:
          $ref: "#/components/schemas/ModelKeyGuidance"
        recommendedModelKey:
          type: string
        providerReplacementModelKey:
          type: string
        recommendationSource:
          $ref: "#/components/schemas/RecommendationSource"
        match:
          type: object
          required: [matchedModelKey, strategy]
          properties:
            matchedModelKey:
              type: string
            strategy:
              type: string
            score:
              type: number
        pricing:
          type: object
          required: [snapshotId]
          properties:
            snapshotId:
              type: string
            inputUsdPerMillion:
              type: number
            outputUsdPerMillion:
              type: number
            blendedUsdPerMillion:
              type: number
        equivalents:
          type: array
          items:
            $ref: "#/components/schemas/ModelAlternativeCandidate"
        variants:
          type: array
          items:
            $ref: "#/components/schemas/ModelAlternativeCandidate"
        alternatives:
          type: array
          items:
            $ref: "#/components/schemas/ModelAlternativeCandidate"
        excludedCandidates:
          type: array
          items:
            type: object
            required: [modelKey, reasons]
            properties:
              modelKey:
                type: string
              reasons:
                type: array
                items:
                  type: string
        policy:
          $ref: "#/components/schemas/RecommendationPolicy"
        decisionId:
          type: string
        scoringVersion:
          type: number
        generatedAt:
          type: string
          format: date-time
        validUntil:
          type: string
          format: date-time
        degraded:
          type: boolean
        warnings:
          type: array
          items:
            type: string
        automation:
          $ref: "#/components/schemas/FullAutomation"
    ApiError:
      type: object
      required: [error, message]
      properties:
        error:
          type: string
          enum: [INVALID_MODEL_KEY, INVALID_MODEL_REQUEST, METHOD_NOT_ALLOWED]
        message:
          type: string
