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

# Upsert one test-case result with scores

> Upsert one test-case result (and its scores). Idempotent on (run, test case).

<Note>The TraceRoot SDKs call this endpoint for you; call it directly only where no SDK fits. It accepts a project API key only.</Note>


## OpenAPI

````yaml /api-reference/openapi.json post /api/v1/public/evaluation-runs/{run_id}/results
openapi: 3.1.0
info:
  title: TraceRoot Public API
  version: 0.1.0
servers:
  - description: TraceRoot Cloud
    url: https://app.traceroot.ai
  - description: Self-hosted
    url: '{baseUrl}'
    variables:
      baseUrl:
        default: http://localhost:8000
        description: Your TraceRoot backend URL
security: []
paths:
  /api/v1/public/evaluation-runs/{run_id}/results:
    post:
      tags:
        - Offline Eval
      summary: Upsert one test-case result with scores
      description: >-
        Upsert one test-case result (and its scores). Idempotent on (run, test
        case).
      operationId: upsert_result
      parameters:
        - in: path
          name: run_id
          required: true
          schema:
            title: Run Id
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertResultRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpsertResultResponse'
          description: Successful Response
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Invalid request
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Authentication failed
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Not found
        '413':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Request body too large
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Validation error
        '503':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Authentication service unavailable
      security:
        - BearerAuth: []
components:
  schemas:
    UpsertResultRequest:
      description: >-
        Upsert one test-case result. Idempotent on (``run_id``,
        ``test_case_id``).

        ``trace_id`` may be null now and set on a later call (out-of-order
        arrival).


        ``scores`` is genuinely optional and carries three distinct meanings, so
        the

        out-of-order flow (POST the result with its scores, then re-POST later
        just to

        attach the OTel ``trace_id``) cannot destroy them: absent → leave the
        existing

        scores untouched, ``[]`` → clear them, non-empty → replace them. Do not
        give

        this a ``default_factory=list``, which would collapse the first two
        cases.


        Every optional field is a *partial* update: a key the caller omits keeps
        its

        stored value, while an explicit null clears it. Sending ``scores``
        replaces

        the result's scores (``[]`` clears them); omitting it leaves them alone.
      properties:
        baseline_output:
          anyOf:
            - maxLength: 1000000
              type: string
            - type: 'null'
          title: Baseline Output
        candidate_output:
          anyOf:
            - maxLength: 1000000
              type: string
            - type: 'null'
          title: Candidate Output
        change:
          anyOf:
            - enum:
                - improved
                - regressed
                - unchanged
              type: string
            - type: 'null'
          title: Change
        cost:
          anyOf:
            - minimum: 0
              type: number
            - type: 'null'
          title: Cost
        duration_ms:
          anyOf:
            - maximum: 9007199254740991
              minimum: 0
              type: integer
            - type: 'null'
          title: Duration Ms
        expected_output:
          anyOf:
            - maxLength: 1000000
              type: string
            - type: 'null'
          title: Expected Output
        input:
          maxLength: 1000000
          title: Input
          type: string
        scores:
          items:
            $ref: '#/components/schemas/ScoreInput'
          maxItems: 200
          title: Scores
          type: array
        status:
          enum:
            - passed
            - failed
            - errored
            - not_scored
          title: Status
          type: string
        task_error:
          anyOf:
            - maxLength: 10000
              type: string
            - type: 'null'
          title: Task Error
        test_case_id:
          maxLength: 64
          minLength: 1
          title: Test Case Id
          type: string
        trace_id:
          anyOf:
            - maxLength: 64
              minLength: 1
              type: string
            - type: 'null'
          title: Trace Id
      required:
        - test_case_id
        - input
        - status
      title: UpsertResultRequest
      type: object
    UpsertResultResponse:
      properties:
        evaluation_result_id:
          title: Evaluation Result Id
          type: string
      required:
        - evaluation_result_id
      title: UpsertResultResponse
      type: object
    ErrorResponse:
      description: >-
        The canonical public error envelope (matches the gateway's normalized
        shape).
      properties:
        detail:
          title: Detail
          type: string
      required:
        - detail
      title: ErrorResponse
      type: object
    ScoreInput:
      description: >-
        One scorer's outcome on one result. ``error`` set = the scorer failed to
        judge.
      properties:
        bool_value:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Bool Value
        error:
          anyOf:
            - maxLength: 5000
              type: string
            - type: 'null'
          title: Error
        explanation:
          anyOf:
            - maxLength: 5000
              type: string
            - type: 'null'
          title: Explanation
        numeric_value:
          anyOf:
            - type: number
            - type: 'null'
          title: Numeric Value
        passed:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Passed
        scorer_name:
          maxLength: 200
          minLength: 1
          title: Scorer Name
          type: string
        scorer_version:
          maxLength: 50
          minLength: 1
          title: Scorer Version
          type: string
        string_value:
          anyOf:
            - maxLength: 2000
              type: string
            - type: 'null'
          title: String Value
      required:
        - scorer_name
        - scorer_version
      title: ScoreInput
      type: object
  securitySchemes:
    BearerAuth:
      scheme: bearer
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.