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

# Add, update and delete many dataset items

> Apply a batch of creates, updates and deletes to a dataset's items in a single committed version.

**This is not replace-all.** Only the items named in `items` and `delete_ids` are touched; every other item of the dataset is left exactly as it was. Omitting an id does not delete it.

**Each entry of `items` is a whole-item replace**, in exactly the shape `POST /evals/datasets/{dataset_id}/items` accepts. An absent field is an *empty* field, not "keep whatever is there". Whole-item semantics is what makes one payload mean the same thing whether it creates or updates, and it is how a bulk request clears a field.

An entry whose `id` is currently live is an **update**; an entry with no `id`, or with an `id` that is unknown or whose last revision was a delete, is a **create** (a re-submitted deleted id begins a new lifetime). An entry whose content matches the item's current content (absent, `null` and empty treated alike, as on `POST`) writes nothing at all — its id comes back under `unchanged_ids`. A batch in which *nothing* changed creates no new version and still answers 200.

The whole batch lands under exactly one version, however many items it touches, so a read at any version sees either all of it or none of it.

`items` and `delete_ids` are capped **together**: their combined length may not exceed the bulk limit (by default the dataset item cap, 10,000); a request over it is a 400 whose message states the exact limit. Creates are also held under the dataset's overall item cap, measured on the batch's *net* effect — a batch that deletes fifty items and creates fifty more does not grow the dataset.

`base_version` is required: the version the caller read, typically `data.dataset_version.version` from the item listing. If any id named in `items` or `delete_ids` has a revision (an edit, a delete or a re-create) committed above that version, the whole request is refused with a 409 whose reason is `DatasetItemStaleBaseVersion` and nothing is written, even when the batch would otherwise change nothing. The check is per item: an older `base_version` is still accepted for items that have not changed since it. A retry of a request whose response was lost therefore gets a 409; re-read the listing to see that the change was applied.



## OpenAPI

````yaml PATCH /v3/evals/datasets/{dataset_id}/items
openapi: 3.0.3
info:
  title: Fiddler API - 2.0
  description: APIs to interact with Fiddler
  termsOfService: https://fiddler.ai/about/terms
  contact:
    email: support@fiddler.ai
  license:
    name: Proprietary
    url: '2.0'
  version: '2.0'
servers: []
security:
  - BearerAuth: []
tags:
  - name: access-key
    description: CRUD operations for API keys
  - name: agent-v3
    description: CRUD for the Agent Registry (Stage 1, manual entries)
  - name: aggregation-invalidation-request-v3
    description: Endpoints related to retrieving aggregation invalidation requests
  - name: alert-rules-v3
    description: CRUD for Alert Rules, Summary, and Stats APIs
  - name: application-v3
  - name: auth
    description: Authentication strategies and login flows
  - name: baseline-v3
    description: CRUD for baseline
  - name: catalog-v3
    description: >-
      Entity catalog provides paginated, searchable discovery of entity names
      (attribute keys, agent names, span types, span names, score names,
      evaluator config names) and their distinct values. Powered by ClickHouse
      materialized views — no worker or PostgreSQL dependency.
  - name: chart-annotation-v3
    description: Endpoints related to retrieving chart annotations
  - name: chart-v3
    description: CRUD for chart
  - name: queries-v3
    description: v3 queries API
  - name: configuration-v3
    description: >
      Read and change runtime configurations (Config Manager) for your
      organization, its projects, and its models.


      **Private preview.** These endpoints accept requests on every deployment.

      Whether a saved value takes effect depends on two deployment settings that
      are off by default:

      one makes Fiddler read stored values,

      and the other runs the configuration worker, which applies retention
      changes to stored data.

      Contact your Fiddler Customer Success Manager before using these
      endpoints.


      This reference documents the data retention (TTL) settings:

      `PROD_EVENTS_TTL_DAYS`, `GENAI_TRACES_TTL_DAYS`, and
      `GENAI_METRICS_TTL_DAYS`.

      The API accepts other registered settings too;

      contact your Fiddler Customer Success Manager before changing any of them.

      **Retention settings permanently delete data** once it is older than the
      configured period.

      When existing data is affected depends on the setting; see each setting's
      description.
  - name: cost-evaluators-v3
    description: >
      Paginated roll-up of per-evaluator LLM cost and token usage, aggregated
      hourly. Available only on deployments with evaluator cost reporting
      enabled.
  - name: custom-metrics-v3
  - name: dimensionality-reduction-v3
  - name: environment-v3
    description: Endpoints related to environment management
  - name: evals
  - name: datasets
  - name: evaluation-v3
  - name: evaluator-v3
  - name: rule-evaluators-v3
  - name: experiment-v3
  - name: explainability-v3
  - name: llm_rca-v3
  - name: file-upload
    description: Endpoints related to file uploading.
  - name: fql-expressions-v3
    description: >
      Endpoints for listing FQL (Fiddler Query Language) functions available for
      GenAI custom metrics. Used by the frontend for autocomplete and signature
      hints in the FQL editor.
  - name: genai-alert-rules-v3
    description: CRUD API for GenAI Alert Rules
  - name: genai-custom-metrics-v3
    description: API for GenAI Custom Metrics
  - name: genai-filters-v3
    description: API for GenAI Filters
  - name: genai-metrics-v3
    description: >-
      Endpoints for pre-aggregated GenAI metrics. All metric data is
      pre-aggregated hourly by a Celery-based metric collector; no real-time
      aggregation is performed at request time.
  - name: guardrails-api
    description: Endpoints related to retrieving Guardrails specific data
  - name: ingestion-v3
  - name: intercom-api
    description: Endpoints related to intercom APIs
  - name: jobs-v3
  - name: llm-gateway-v3
  - name: auth-login
  - name: auth-logout
  - name: mcp-client-setup-v3
    description: Endpoints for retrieving MCP client setup instructions.
  - name: metrics-v3
    description: Metrics endpoints
  - name: model-v3
  - name: dashboard-v3
  - name: model-deployment-v3
  - name: monitoring-summary-v3
  - name: histograms-v3
  - name: organization-roles-v3
    description: Update user org role
  - name: organization-settings-v3
    description: Update organization settings such as timezone, email configuration, etc.
  - name: pagerduty-api
    description: CRUD for Pagerduty services.
  - name: project-v3
  - name: project-roles-v3
    description: Project role assignment management
  - name: scores-v3
    description: Unified CRUD for scores and annotations
  - name: searchable-text-key-v3
    description: >-
      Manage the global searchable text keys table that controls which OTel
      attribute keys are routed to the full-text-searchable `ValueContent`
      column in the unified attributes table. Changes propagate to the backing
      ClickHouse dictionary within 1-2 minutes and affect all tenants.
  - name: segments-v3
  - name: semantic-mapping-v3
    description: >-
      Manage the global semantic name mappings table that maps raw OTel
      attribute keys to canonical semantic concepts. Changes propagate to the
      backing ClickHouse dictionary within 1-2 minutes and affect all tenants.
  - name: server-info-v3
    description: Endpoints related to retrieving server information
  - name: service-account
    description: >
      Service accounts and their API keys. A human Org Admin manages the service
      accounts of their own organization: create, read, update, and
      enable/disable (there is no delete — an account is disabled instead), and
      issue, rename, enable/disable, and revoke each account's API keys (a key's
      expiry is fixed at creation and changed only by rotating the key). An API
      key is an `fks_` secret that inherits the account's grants and cannot
      manage service accounts; an active, unexpired key must be disabled before
      it can be revoked, and it authenticates only while both it and its account
      are active. Scopes here are capability scopes (what the account may do),
      not OAuth scopes.
  - name: sessions-v3
    description: v3 session APIs
  - name: span-v3
  - name: team-roles-v3
  - name: team-v3
  - name: traces-v3
    description: v3 trace api for monitoring
  - name: fetch-sessions-v3
    description: v3 fetch sessions api for monitoring
  - name: user-access-key
    description: >
      CRUD operations for user API keys. All endpoints are user-scoped — each
      user can only operate on their own API keys. No one including Org admins
      have access to other users' API keys.
  - name: users-v3
  - name: version-compatibility-v3
  - name: webhooks
externalDocs:
  url: https://docs.fiddler.ai
  description: Find out more about Fiddler
paths:
  /v3/evals/datasets/{dataset_id}/items:
    parameters:
      - name: dataset_id
        in: path
        description: Dataset UUID
        required: true
        schema:
          type: string
          format: uuid
    patch:
      tags:
        - evals
        - datasets
      summary: Add, update and delete many dataset items
      description: >-
        Apply a batch of creates, updates and deletes to a dataset's items in a
        single committed version.


        **This is not replace-all.** Only the items named in `items` and
        `delete_ids` are touched; every other item of the dataset is left
        exactly as it was. Omitting an id does not delete it.


        **Each entry of `items` is a whole-item replace**, in exactly the shape
        `POST /evals/datasets/{dataset_id}/items` accepts. An absent field is an
        *empty* field, not "keep whatever is there". Whole-item semantics is
        what makes one payload mean the same thing whether it creates or
        updates, and it is how a bulk request clears a field.


        An entry whose `id` is currently live is an **update**; an entry with no
        `id`, or with an `id` that is unknown or whose last revision was a
        delete, is a **create** (a re-submitted deleted id begins a new
        lifetime). An entry whose content matches the item's current content
        (absent, `null` and empty treated alike, as on `POST`) writes nothing at
        all — its id comes back under `unchanged_ids`. A batch in which
        *nothing* changed creates no new version and still answers 200.


        The whole batch lands under exactly one version, however many items it
        touches, so a read at any version sees either all of it or none of it.


        `items` and `delete_ids` are capped **together**: their combined length
        may not exceed the bulk limit (by default the dataset item cap, 10,000);
        a request over it is a 400 whose message states the exact limit. Creates
        are also held under the dataset's overall item cap, measured on the
        batch's *net* effect — a batch that deletes fifty items and creates
        fifty more does not grow the dataset.


        `base_version` is required: the version the caller read, typically
        `data.dataset_version.version` from the item listing. If any id named in
        `items` or `delete_ids` has a revision (an edit, a delete or a
        re-create) committed above that version, the whole request is refused
        with a 409 whose reason is `DatasetItemStaleBaseVersion` and nothing is
        written, even when the batch would otherwise change nothing. The check
        is per item: an older `base_version` is still accepted for items that
        have not changed since it. A retry of a request whose response was lost
        therefore gets a 409; re-read the listing to see that the change was
        applied.
      operationId: bulkUpdateEvalsDatasetItemsV3
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkEvalDatasetItemsRequest'
      responses:
        '200':
          description: >-
            The batch was applied. The four id lists partition the ids the
            request named.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/BulkEvalDatasetItemsResponse'
        '400':
          description: >-
            The batch was rejected and nothing was written. Raised when the body
            names neither `items` nor `delete_ids`, when one item id is named
            more than once (including the same id in `items` and `delete_ids`),
            when `base_version` is missing or null, when a key is unknown, or
            when the creates would push the dataset over its item cap. When the
            body is otherwise valid and `items` plus `delete_ids` exceeds the
            bulk cap, `errors[0].reason` is `DatasetItemsBulkLimitExceeded`:
            split the change across several requests, each of which commits its
            own version.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '404':
          description: >-
            The dataset does not exist, a `delete_ids` entry names no live item
            of it — unknown, belonging to another dataset, or already deleted —
            or `base_version` names no committed version of this dataset. The
            whole batch is refused; no changes were made.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            The write conflicted and no changes were made; switch on
            `errors[0].reason` to decide whether to retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DatasetWriteConflictResponse'
        '500':
          $ref: '#/components/responses/500'
        '503':
          description: >-
            The data store was unavailable or too slow. No changes were made;
            retry with backoff, or send fewer items. `errors[0].reason` is
            `DatasetItemsWriteUnavailable`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DatasetItemsWriteUnavailableResponse'
components:
  schemas:
    BulkEvalDatasetItemsRequest:
      type: object
      description: >-
        One bulk add/update/delete. Both halves are optional, but at least one
        of them must be non-empty, and their combined length is capped (by
        default at the dataset item cap, 10,000). An item id may appear only
        once across both lists.
      required:
        - base_version
      properties:
        items:
          type: array
          description: >-
            Items to add or update. Each entry is the **whole item**, in exactly
            the shape the POST accepts — an absent field is an empty field, not
            "keep the current value". An entry with no `id`, or with an `id`
            that is not currently live, creates a new item.
          items:
            $ref: '#/components/schemas/EvalDatasetItemPayload'
        delete_ids:
          type: array
          description: >-
            Ids to delete. Every id must name a live item of this dataset; if
            any does not, the whole batch is refused with 404.
          items:
            type: string
            format: uuid
        base_version:
          allOf:
            - $ref: '#/components/schemas/DatasetVersionReference'
          description: >-
            Optimistic-concurrency check: the dataset version the caller read.
            The whole request is refused with 409 if any id it names has a
            revision committed above that version.
      additionalProperties: false
    ApiResponse:
      type: object
      description: |
        Response object for standard API responses.
      properties:
        api_version:
          type: string
          default: '3.0'
          enum:
            - '2.0'
            - '3.0'
          description: |
            API version.
        kind:
          type: string
          default: NORMAL
          enum:
            - NORMAL
          description: |
            Type of response, indicating a normal response.
    BulkEvalDatasetItemsResponse:
      type: object
      description: >-
        The outcome of a bulk request, per id rather than as a count: the four
        lists partition the ids the request named. An id in `unchanged_ids` was
        submitted with content identical to what was already stored, so no
        revision was written for it.
      required:
        - created_ids
        - updated_ids
        - deleted_ids
        - unchanged_ids
        - dataset_version
      properties:
        dataset_version:
          allOf:
            - $ref: '#/components/schemas/DatasetVersionCompact'
          description: >-
            The version this request committed, or, when it changed nothing, the
            current version it was checked against. Its `version` is safe as
            `base_version` only for the items this call named; re-read before
            editing others.
        created_ids:
          type: array
          description: >-
            Ids of items that came into existence, including the ids the server
            assigned to entries submitted without one.
          items:
            type: string
            format: uuid
        updated_ids:
          type: array
          description: Ids of live items that were given a new revision.
          items:
            type: string
            format: uuid
        deleted_ids:
          type: array
          description: Ids that were deleted.
          items:
            type: string
            format: uuid
        unchanged_ids:
          type: array
          description: >-
            Ids whose submitted content already matched what was stored. Nothing
            was written for them.
          items:
            type: string
            format: uuid
    ErrorResponse:
      type: object
      description: |
        Response object for errors returned by the API.
      properties:
        api_version:
          type: string
          default: '3.0'
          enum:
            - '2.0'
            - '3.0'
          description: |
            API version of the response.
        kind:
          type: string
          default: ERROR
          enum:
            - ERROR
          description: |
            Type of response, usually indicating an error.
        error:
          type: object
          properties:
            code:
              type: integer
              format: int32
              description: >
                Represents the code for this error, typically an HTTP response
                code.
              default: 400
              enum:
                - 400
                - 401
                - 403
                - 404
                - 409
                - 410
                - 422
                - 429
                - 500
                - 501
                - 503
            message:
              type: string
              description: >
                A human-readable message providing more details about the error.
                If there are multiple errors, it will be the message for the
                first error.
              example: Resource Not Found
            errors:
              type: array
              description: >
                Container for additional information regarding the error,
                especially for multiple errors.
              items:
                type: object
                properties:
                  reason:
                    type: string
                    description: >
                      Unique identifier for this error, different from the error
                      code.
                    example: ResourceNotFoundException
                  message:
                    type: string
                    description: >
                      A human-readable message providing more details about the
                      error. If there is only one error, this field will match
                      error.message.
                    example: Resource Not Found
                  help:
                    type: string
                    description: >
                      Link to support or documentation providing more
                      information on the error.
    DatasetWriteConflictResponse:
      description: >-
        Error body of a `409` from a dataset write. No changes were made.


        `errors[0].reason` is the machine-readable discriminator. Kinds of
        conflict need different handling, so switch on it rather than on the
        status code alone:


        * `DatasetVersionCommitRace` — **transient; safe to retry unattended.**
        The write took too long to commit and another write took its place. The
        request is still valid, and replaying it commits under a new version.


        * `DatasetVersionSaveInProgress` — **transient; retry with backoff.**
        Another save holds the dataset. The request is still valid; resend it
        unchanged.


        * `DatasetItemStaleBaseVersion` — **never retry automatically.** An item
        the request names has a revision committed after its `base_version`;
        replaying would overwrite that edit. `errors[]` has one entry per
        conflicting id, up to 100, and `message` gives their total. Re-read the
        dataset and reconcile before writing again.


        * `DatasetItemCreateCollision` — **never retry unchanged.** Only `POST
        /evals/datasets/{dataset_id}/items` returns it: an `id` in the request
        is a live item with different content, or was written while this request
        was in flight (including by an earlier attempt of this same request).
        `errors[]` has one entry per colliding id, up to 100. Re-read the items:
        they may already hold this content.


        Any other value — including `Conflict`, the default every other endpoint
        returns — carries no retry guidance and should be treated as a plain
        `409`.
      allOf:
        - $ref: '#/components/schemas/ErrorResponse'
    DatasetItemsWriteUnavailableResponse:
      description: >-
        Error body of a `503` from a dataset item write. `errors[0].reason` is
        `DatasetItemsWriteUnavailable`: the data store was unavailable or too
        slow, and no changes were made. Retry with backoff; for a batch, send
        fewer items.
      allOf:
        - $ref: '#/components/schemas/ErrorResponse'
    EvalDatasetItemPayload:
      type: object
      description: >-
        One dataset item. Only the keys listed here are accepted; an unknown key
        is a 400. The contents of the object fields are free-form.
      required:
        - inputs
      properties:
        id:
          type: string
          format: uuid
          description: >-
            The item's id, optional; the server assigns one when it is omitted.
            Unique within a dataset, so another dataset may reuse it, and named
            at most once per request. On `POST` it may name a live item only if
            the content is unchanged.
        inputs:
          type: object
          additionalProperties: true
          description: Flexible JSON field for nested input structures.
          example:
            question: What is the capital of France?
            context:
              - Paris is the capital.
        expected_outputs:
          type: object
          additionalProperties: true
          nullable: true
          description: Flexible JSON field for nested ground truth structures.
          example:
            answer: Paris
            rationale: Common knowledge.
        metadata:
          type: object
          additionalProperties: true
          nullable: true
          description: A JSON object for storing additional test case metadata.
          example:
            reviewer: Alice
            status: approved
        extras:
          type: object
          description: A JSON object for storing additional custom data
          additionalProperties: true
        source_name:
          type: string
          nullable: true
          description: An optional name identifying the source of the test case.
        source_id:
          type: string
          nullable: true
          description: An optional identifier for the source of the test case.
      additionalProperties: false
    DatasetVersionReference:
      description: >-
        A reference to a committed dataset version, in the spelling `?version=`
        accepts: the per-dataset version number.


        A JSON integer is accepted as well as a string and means the same
        version number, so `3` and `"3"` are the same reference. `true`/`false`
        are not.
      oneOf:
        - type: string
        - type: integer
    DatasetVersionCompact:
      type: object
      title: DatasetVersionCompact
      description: >
        Compact version of an evaluation dataset version which can be included
        in the response of relevant APIs.
      required:
        - id
        - version
        - tag
      properties:
        id:
          type: string
          format: uuid
          description: |
            Unique identifier of the dataset version.
        version:
          type: integer
          description: >
            Per-dataset version number, accepted by the `version` query
            parameter.
        tag:
          type: string
          nullable: true
          description: |
            Reserved for future version tagging; always null today.
  responses:
    '401':
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    '403':
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    '500':
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer

````