---
title: "Edit Experiment Review"
method: PUT
path: "/console/v1/experiments/{id}/reviews/{reviewID}"
tags: ["Experiments"]
---

# Edit Experiment Review

`PUT /console/v1/experiments/{id}/reviews/{reviewID}`

## Path parameters

- `id` string, required
- `reviewID` string, required

## Request body

- EditExperimentReviewRequestDto — Request body for PUT /console/v1/experiments/:id/reviews/:reviewID
  - `description` string — New description. Omit to keep the current value.
  - `reviewer_ids` string[] — Replacement reviewer user IDs. Omit to keep the current set.
  - `reviewer_group_ids` string[] — Replacement reviewer group IDs. Omit to keep the current set.

## Response `200`

The updated experiment review.

- object
  - `message` string, required — A simple string explaining the result of the operation.
  - `data` object, required — A single result.
    - `review_id` string, required — Unique ID of the review.
    - `status` 'pending' | 'accepted' | 'rejected' | 'committed' | 'changes_requested' | 'pending_webhook_validation' | 'failed_webhook_validation' | 'approved_webhook_validation', required — Lifecycle status of the review.
    - `type` 'start' | 'stop' | 'pause' | 'restart' | 'abandon' | 'archive' | 'delete' | 'make_decision' | 'update_settings' | 'update_overrides' | 'update_target_applications' | 'update_allowed_reviewers' | 'update_default_impact_multiplier' | 'scheduled_start' | 'scheduled_start_edit' | 'disable_reviews_locally' | 'rollout' | 'schedule_rollout' | 'reallocate' | 'change_enabled_groups' | 'unarchive' | 'update_owners' | 'update_team', required — Kind of change the review proposes.
    - `author` object, required — The user who created the review.
      - `id` string, required
      - `email` string, nullable, required
    - `reviewers` object[], required — Requested reviewers (users and groups).
      - `id` string, required
      - `kind` 'user' | 'group', required
    - `description` string, required — Human-readable description of the proposed change.
    - `created_at` string, required — ISO-8601 timestamp of when the review was created.
    - `content` object, nullable — The proposed change this review would apply, as `{ current, proposed }` over exactly the fields committing the review would write. `current` is the live value read at request time; where commit treats an unset argument as "leave unchanged", `proposed` repeats the live value rather than a default. Populated on single-review responses only — list responses omit it so a page of reviews does not pay an extra read per row. When the review does propose something but it could not be read back, `content` is PRESENT with `unavailable_reason` set and both value objects empty, never `null` — so "this type proposes nothing" stays distinguishable from "we cannot tell you what this would do". This surface's reasons are `review_data_unavailable` (the stored change data is missing or does not match the type the review declares; expected on legacy rows) and `content_unreadable` (the data is present but the before/after could not be assembled; a logged server-side fault). `null` when the review type is a bare action with no recoverable proposed value: `stop`, `pause`, `restart`, `reallocate`, `delete`, `disable_reviews_locally` (always), `start` (unless the review carries a backdated start date that commit will actually write — analysis-only experiments on warehouse-native projects), `scheduled_start_edit` when `new_time` is `ignore` (commit is a no-op), and `update_settings` on an autotune (the stored settings have no experiment-contract shape). Every other type carries content, including `archive`, `unarchive`, `update_owners`, `update_team`, `change_enabled_groups` and `update_allowed_reviewers`, for which the Console currently shows no before/after. Keys by type: `archive`/`unarchive` -> `archived`, `allocation` (archiving a layer-bound experiment zeroes its allocation); `abandon` -> `decision_note_title`, `decision_reason`; `start` -> `start_time`; `scheduled_start`/`scheduled_start_edit` -> `start_time`; `rollout` -> `group_id`, `rollout_percentage`, `rollout_phases`, `has_upcoming_automated_rollout`; `schedule_rollout` -> `group_id`, `rollout_phases`; `make_decision` -> `winning_group_id`, `decision_note_title`, `decision_reason`, and on experiments `overrides`, `id_overrides`, `inline_targeting_rules_json`, `targeting_gate_id`; `update_overrides` -> `overrides`, `id_overrides`, `allow_overrides_in_pulse`; `update_target_applications` -> `target_app_ids`; `update_default_impact_multiplier` -> `default_impact_multiplier`; `update_owners` -> `owners`; `update_team` -> `team_id`, `allowed_reviewer_user_ids`, `allowed_reviewer_group_ids` (moving to a team whose approval mode is `admin_only`/`team_only` widens who may approve future reviews); `update_allowed_reviewers` -> `allowed_reviewer_user_ids`, `allowed_reviewer_group_ids`; `change_enabled_groups` -> `groups` (the full list, with the delta applied); `update_settings` -> a single `settings` object holding the full resolved settings set, including `overrides`, `idOverrides`, `allowOverridesInPulse` and `customScorecardSections`.
      - `type` 'start' | 'stop' | 'pause' | 'restart' | 'abandon' | 'archive' | 'delete' | 'make_decision' | 'update_settings' | 'update_overrides' | 'update_target_applications' | 'update_allowed_reviewers' | 'update_default_impact_multiplier' | 'scheduled_start' | 'scheduled_start_edit' | 'disable_reviews_locally' | 'rollout' | 'schedule_rollout' | 'reallocate' | 'change_enabled_groups' | 'unarchive' | 'update_owners' | 'update_team', required — Same value as the envelope `type`, repeated for self-containment.
      - `current` object, required — The entity's live value at read time, for each field this review type updates. Matches the Console's "Original Version (Before)" column for pending reviews. This is NOT status-dependent: for a committed or rejected review it is still the live entity as it stands now, which for a committed review normally equals `proposed`.
      - `proposed` object, required — The value this review proposes — what commit will apply. Carries exactly the same keys as `current`. Array-valued fields carry the full array on both sides, never only the changed elements.
      - `unavailable_reason` 'review_data_unavailable' | 'content_unreadable' — Present ONLY when the change could not be read back, in which case `current` and `proposed` are both empty objects and carry no meaning. This exists so that "this review type has nothing to propose" (`content: null`) is never confused with "we could not tell you what this review would do". `review_data_unavailable`: the review's stored change data is missing, or does not match the type the review declares — expected on legacy rows. `content_unreadable`: the data is present but the before/after could not be assembled; that is a server-side fault and is logged.

---

[API](https://skmtc.net/statsig/apis/console-api.md) · [All operations](https://skmtc.net/statsig/apis/console-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/statsig/console-api/revisions/edf696031d4a/schema)
