---
title: "Create Dynamic Config Review"
method: POST
path: "/console/v1/dynamic_configs/{id}/reviews"
tags: ["Dynamic Configs"]
---

# Create Dynamic Config Review

`POST /console/v1/dynamic_configs/{id}/reviews`

## Path parameters

- `id` string, required

## Request body

- CreateDCReviewRequestDto — Request body for POST /console/v1/dynamic_configs/:id/reviews
  - `description` string, required — Human-readable description of the proposed change.
  - `reviewer_ids` string[] — User IDs to request review from.
  - `reviewer_group_ids` string[] — Reviewer group IDs to request review from.
  - `change` object, required — The proposed change. Provide exactly one change slot: the content bundle (`rules` and/or `default_value`), one verb/metadata field, or `restore`.
    - `rules` object[] — Proposed full rule set for the dynamic config. Same shape as the DC update contract.
      - `name` string, required — The name of this rule.
      - `passPercentage` number — Of the users that meet the conditions of this rule, what percent should return true.
      - `conditions` object[], required — An array of Condition objects.
        - `targetValue` union
          - string[]
          - number[]
          - string
          - number
        - `operator` string
        - `field` string, nullable
        - `customID` string, nullable
        - `type` 'app_version' | 'browser_name' | 'browser_version' | 'country' | 'custom_field' | 'email' | 'environment_tier' | 'fails_gate' | 'fails_segment' | 'ip_address' | 'locale' | 'os_name' | 'os_version' | 'passes_gate' | 'passes_segment' | 'public' | 'time' | 'unit_id' | 'user_id' | 'user_agent' | 'url' | 'javascript' | 'device_model' | 'target_app' | 'experiment_group', required
      - `environments` string[], nullable
      - `id` string — The Statsig ID of this rule.
      - `baseID` string — The base ID of this rule, i.e. without any added metadata. Will remain the exact same throughout
      - `returnValue` object
      - `completedAutomatedRollouts` object[] — Read-only: Automated rollout phases that have already completed.
        - `time` number
        - `passPercent` number, required
      - `pendingAutomatedRollouts` object[] — Read-only: Automated rollout phases that are scheduled but not yet complete.
        - `time` number
        - `passPercent` number, required
      - `returnValueJson5` string
      - `variants` object[]
        - `id` string
        - `name` string, required
        - `passPercentage` number, required
        - `returnValue` object
        - `returnValueJson5` string
    - `default_value` object — Proposed default value for the dynamic config as a JSON object.
    - `is_enabled` boolean — Proposed enabled state for the dynamic config. An explicit target, not a toggle.
    - `is_archived` boolean — Proposed archived state for the dynamic config. `true` archives, `false` unarchives.
    - `delete` true — Delete the dynamic config. Set to `true`.
    - `resalt` true — Re-randomize the dynamic config's salt. Set to `true`.
    - `disable_reviews_locally` true — Stop requiring review on this dynamic config. Set to `true`.
    - `restore` object — Revert to a prior committed snapshot (review type `rules`).
      - `snapshot_id` string, required — Snapshot ID (SUID) of the committed historical state to restore.
    - `release_pipeline_id` string, nullable — Set or clear the dynamic config's release pipeline (review type `update_release_pipeline`). Pass a pipeline ID to attach, or `null` to detach.
    - `id_type` string — Change the dynamic config's primary unit ID type (review type `edit_id_type`).
    - `allow_self_approval` boolean — Whether this dynamic config's reviews may be self-approved (review type `update_allow_self_approval`).
    - `target_app_ids` string[] — Replace the dynamic config's target applications (review type `update_target_applications`).
    - `allowed_reviewers` object — Set who may review this dynamic config (review type `allowed_reviewers`).
      - `user_ids` string[] — User IDs allowed to review. Replaces the existing set.
      - `group_ids` string[] — Reviewer group IDs allowed to review. Replaces the existing set.

## Response `201`

The created dynamic config 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` 'rules' | 'toggle_enabled' | 'archive' | 'delete' | 'resalt' | 'disable_reviews_locally' | 'update_team' | 'update_release_pipeline' | 'edit_id_type' | 'update_allow_self_approval' | 'update_target_applications' | 'update_owners' | 'allowed_reviewers', 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, as a `current` / `proposed` pair over only the fields this review type updates. `null` means — and only ever means — that this review type carries no proposed value (`delete`, `resalt`, `disable_reviews_locally`); those are fully described by `type`. When the change exists but could not be read back, `content` is present with an `unavailable_reason` instead, so the two cases stay distinguishable. Only populated on single-review responses (get / create / edit / approve / reject); the list endpoint omits it entirely rather than paying a snapshot read per row.
      - `type` 'rules' | 'toggle_enabled' | 'archive' | 'delete' | 'resalt' | 'disable_reviews_locally' | 'update_team' | 'update_release_pipeline' | 'edit_id_type' | 'update_allow_self_approval' | 'update_target_applications' | 'update_owners' | 'allowed_reviewers', 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`.
        - `rules` object[] — The FULL rule array for this side, not just the rules that changed — commit replaces the array wholesale and rule order is evaluation-significant. Rules are serialized exactly as the entity's own read endpoint returns them, so this can be diffed against it with no translation: gates match `GET /gates/{id}` (no `returnValue`/`returnValueJson5`/`variants` — a gate rule has no return value), dynamic configs match `GET /dynamic_configs/{id}` and do carry those three.
          - `name` string, required — The name of this rule.
          - `passPercentage` number, required — Of the users that meet the conditions of this rule, what percent should return true.
          - `conditions` object[], required — An array of Condition objects.
            - `targetValue` union
              - …
            - `operator` string
            - `field` string, nullable
            - `customID` string, nullable
            - `type` 'app_version' | 'browser_name' | 'browser_version' | 'country' | 'custom_field' | 'email' | 'environment_tier' | 'fails_gate' | 'fails_segment' | 'ip_address' | 'locale' | 'os_name' | 'os_version' | 'passes_gate' | 'passes_segment' | 'public' | 'time' | 'unit_id' | 'user_id' | 'user_agent' | 'url' | 'javascript' | 'device_model' | 'target_app' | 'experiment_group', required
          - `environments` string[], nullable
          - `id` string — The Statsig ID of this rule.
          - `baseID` string — The base ID of this rule, i.e. without any added metadata. Will remain the exact same throughout
          - `returnValue` object
          - `completedAutomatedRollouts` object[] — Read-only: Automated rollout phases that have already completed.
            - `time` number
            - `passPercent` number, required
          - `pendingAutomatedRollouts` object[] — Read-only: Automated rollout phases that are scheduled but not yet complete.
            - `time` number
            - `passPercent` number, required
          - `returnValueJson5` string
          - `variants` object[]
            - `id` string
            - `name` string, required
            - `passPercentage` number, required
            - `returnValue` object
            - `returnValueJson5` string
        - `is_enabled` boolean
        - `default_value` unknown
        - `is_launched` boolean — Dynamic configs only. Whether the config is serving its launched payload to every user, bypassing rules. Derived: a dynamic config is launched when it is disabled AND has a launched payload. This is the dynamic-config equivalent of a gate's `default_value: true`, and it is what a dynamic config `toggle_enabled` review actually moves — `default_value` plays no part in that decision.
        - `launched_payload` unknown
        - `default_value_gradual_rollout` object, nullable — Dynamic configs only. The in-progress partial rollout of a new default value, or `null` when there is none. Omitted for secret dynamic configs: the target value is stored unencrypted inside the snapshot, so it is suppressed for the same reason as `launched_payload`.
          - `id` string, required
          - `target_value` unknown
          - `percentage_pass` number, double, required
          - `salt` string, required
          - `rollouts` object[], nullable, required
            - `time` number, required
            - `pass_percent` number, required
            - `is_complete` boolean, required
        - `salt` string — The bucketing salt. Present when committing would change it — which re-buckets every user in every percentage rollout on this config, even though no rule text moved. A `restore` review that reverts past a resalt is the case to watch for.
        - `description` string
        - `show_dev_rules` boolean
        - `show_staging_rules` boolean
        - `subscribers` object[] — Who is notified about alerts on this config (users, teams, Slack channels, PagerDuty on-calls).
          - `type` string, required
          - `id` string, required
        - `analytics_enabled` boolean
        - `scheduled_reload` object — Gates only. The DWH-native scheduled-reload settings, which commit writes as a unit. Absent on non-warehouse-native projects, where none of it is set on either side.
          - `hour` number, double, nullable, required
          - `days` number[], nullable, required
          - `reload_type` 'incremental' | 'full', required
          - `turbo_mode` boolean, nullable, required
        - `is_archived` boolean — Present on `archive` reviews. Archive and unarchive share the external type `archive`, so this field is what distinguishes them.
        - `id_type` string
        - `secondary_id_type` string, nullable
        - `identity_resolution_source_id` string, nullable
        - `target_app_ids` string[]
        - `owners` object[]
          - `owner_id` string, required
          - `owner_type` string, required
        - `team_id` string, nullable
        - `allow_self_approval` boolean
        - `release_pipeline_id` string, nullable
        - `allowed_reviewers` object — Who may approve reviews on this config. Carried by `allowed_reviewers` reviews, which set it outright, and ALSO by `update_team` reviews, which can widen it as a side effect: moving a config onto a team whose review-approval mode is `admin_only` appends that team's admins to `user_ids`, and `team_only` appends the team itself to `group_ids`. Identical values on both sides of an `update_team` review mean that move grants no new approval rights.
          - `user_ids` string[], required
          - `group_ids` string[], required
        - `schema` string, nullable
        - `monitoring_metrics` object[]
          - `name` string, required
          - `type` string, required
        - `monitoring_metric_tags` object[]
          - `id` string, required
        - `real_time_metrics` object[]
          - `name` string, required
          - `type` string, required
        - `overrides` object
          - `id_overrides` object[], required
            - `ids` string[], required
            - `groupID` string, required
            - `environment` string, nullable
            - `unitID` string, nullable
          - `custom_id_overrides` object[], required
            - `ids` string[], required
            - `groupID` string, required
            - `environment` string, nullable
            - `unitID` string, nullable
      - `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.
        - `rules` object[] — The FULL rule array for this side, not just the rules that changed — commit replaces the array wholesale and rule order is evaluation-significant. Rules are serialized exactly as the entity's own read endpoint returns them, so this can be diffed against it with no translation: gates match `GET /gates/{id}` (no `returnValue`/`returnValueJson5`/`variants` — a gate rule has no return value), dynamic configs match `GET /dynamic_configs/{id}` and do carry those three.
          - `name` string, required — The name of this rule.
          - `passPercentage` number, required — Of the users that meet the conditions of this rule, what percent should return true.
          - `conditions` object[], required — An array of Condition objects.
            - `targetValue` union
              - …
            - `operator` string
            - `field` string, nullable
            - `customID` string, nullable
            - `type` 'app_version' | 'browser_name' | 'browser_version' | 'country' | 'custom_field' | 'email' | 'environment_tier' | 'fails_gate' | 'fails_segment' | 'ip_address' | 'locale' | 'os_name' | 'os_version' | 'passes_gate' | 'passes_segment' | 'public' | 'time' | 'unit_id' | 'user_id' | 'user_agent' | 'url' | 'javascript' | 'device_model' | 'target_app' | 'experiment_group', required
          - `environments` string[], nullable
          - `id` string — The Statsig ID of this rule.
          - `baseID` string — The base ID of this rule, i.e. without any added metadata. Will remain the exact same throughout
          - `returnValue` object
          - `completedAutomatedRollouts` object[] — Read-only: Automated rollout phases that have already completed.
            - `time` number
            - `passPercent` number, required
          - `pendingAutomatedRollouts` object[] — Read-only: Automated rollout phases that are scheduled but not yet complete.
            - `time` number
            - `passPercent` number, required
          - `returnValueJson5` string
          - `variants` object[]
            - `id` string
            - `name` string, required
            - `passPercentage` number, required
            - `returnValue` object
            - `returnValueJson5` string
        - `is_enabled` boolean
        - `default_value` unknown
        - `is_launched` boolean — Dynamic configs only. Whether the config is serving its launched payload to every user, bypassing rules. Derived: a dynamic config is launched when it is disabled AND has a launched payload. This is the dynamic-config equivalent of a gate's `default_value: true`, and it is what a dynamic config `toggle_enabled` review actually moves — `default_value` plays no part in that decision.
        - `launched_payload` unknown
        - `default_value_gradual_rollout` object, nullable — Dynamic configs only. The in-progress partial rollout of a new default value, or `null` when there is none. Omitted for secret dynamic configs: the target value is stored unencrypted inside the snapshot, so it is suppressed for the same reason as `launched_payload`.
          - `id` string, required
          - `target_value` unknown
          - `percentage_pass` number, double, required
          - `salt` string, required
          - `rollouts` object[], nullable, required
            - `time` number, required
            - `pass_percent` number, required
            - `is_complete` boolean, required
        - `salt` string — The bucketing salt. Present when committing would change it — which re-buckets every user in every percentage rollout on this config, even though no rule text moved. A `restore` review that reverts past a resalt is the case to watch for.
        - `description` string
        - `show_dev_rules` boolean
        - `show_staging_rules` boolean
        - `subscribers` object[] — Who is notified about alerts on this config (users, teams, Slack channels, PagerDuty on-calls).
          - `type` string, required
          - `id` string, required
        - `analytics_enabled` boolean
        - `scheduled_reload` object — Gates only. The DWH-native scheduled-reload settings, which commit writes as a unit. Absent on non-warehouse-native projects, where none of it is set on either side.
          - `hour` number, double, nullable, required
          - `days` number[], nullable, required
          - `reload_type` 'incremental' | 'full', required
          - `turbo_mode` boolean, nullable, required
        - `is_archived` boolean — Present on `archive` reviews. Archive and unarchive share the external type `archive`, so this field is what distinguishes them.
        - `id_type` string
        - `secondary_id_type` string, nullable
        - `identity_resolution_source_id` string, nullable
        - `target_app_ids` string[]
        - `owners` object[]
          - `owner_id` string, required
          - `owner_type` string, required
        - `team_id` string, nullable
        - `allow_self_approval` boolean
        - `release_pipeline_id` string, nullable
        - `allowed_reviewers` object — Who may approve reviews on this config. Carried by `allowed_reviewers` reviews, which set it outright, and ALSO by `update_team` reviews, which can widen it as a side effect: moving a config onto a team whose review-approval mode is `admin_only` appends that team's admins to `user_ids`, and `team_only` appends the team itself to `group_ids`. Identical values on both sides of an `update_team` review mean that move grants no new approval rights.
          - `user_ids` string[], required
          - `group_ids` string[], required
        - `schema` string, nullable
        - `monitoring_metrics` object[]
          - `name` string, required
          - `type` string, required
        - `monitoring_metric_tags` object[]
          - `id` string, required
        - `real_time_metrics` object[]
          - `name` string, required
          - `type` string, required
        - `overrides` object
          - `id_overrides` object[], required
            - `ids` string[], required
            - `groupID` string, required
            - `environment` string, nullable
            - `unitID` string, nullable
          - `custom_id_overrides` object[], required
            - `ids` string[], required
            - `groupID` string, required
            - `environment` string, nullable
            - `unitID` string, nullable
      - `unavailable_reason` 'snapshot_not_found' | 'snapshot_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". `snapshot_not_found`: the review's snapshot no longer exists — expected for old reviews, whose snapshots are pruned as the config accumulates newer ones. `snapshot_unreadable`: the snapshot exists but could not be read or serialized; 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)
