---
title: Update survey
description: "Updates metadata, targeting, and content variants. For published surveys, changes apply to a draft until publish in the UI. latest version is required and mu…"
product: general
lang: en
last_updated: 2026-10-27
token_estimate: 5493
---
# Update survey

> For AI agents: a documentation index is available at [/docs/llms.txt](/docs/llms.txt). Append `.md` to any page URL for markdown, or send `Accept: text/markdown`.

## Update survey

**PATCH** `/v1/projects/{project_id}/surveys/{survey_id}`

Full URL: `https://developer-api.amplitude.com/v1/projects/{project_id}/surveys/{survey_id}`

**Servers:**
- Production (US): `https://developer-api.amplitude.com/v1/projects/{project_id}/surveys/{survey_id}`
- Production (EU): `https://developer-api.eu.amplitude.com/v1/projects/{project_id}/surveys/{survey_id}`

Update survey

Updates metadata, targeting, and content variants. For published surveys,
changes apply to a draft until publish in the UI. `latest_version` is
required and must match the current draft, otherwise the update returns
`409`. The check runs before the write rather than atomically with it, so it
reduces but does not fully prevent lost updates from concurrent writers.
Publish, schedule, and test instrumentation are not
available via API in v1. Status fields on the response are derived read-only.
When `variants` is sent, it must list every existing variant by `id` with
its unchanged `variant` key; steps within a variant can be added, edited,
reordered, or removed. `tags` is not writable in v1 and returns `400`.

## Authorizations

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Authorization | string | Yes | — | http |

## Path parameters

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| project_id (path) | string | Yes | 12345 | Amplitude project identifier, backed by the canonical app ID. Constraints: pattern: ^[0-9]+$ |
| survey_id (path) | string | Yes | — | Survey nudge identifier. Constraints: pattern: ^[0-9]+$ |

## Header parameters

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| Idempotency-Key (header) | string | Yes | — | Required on write operations. Keys aren't stored yet, so retrying a write with the same key performs it again; a retried create makes another resource. Check whether the first attempt succeeded before you retry. Constraints: min length: 8, max length: 255 |

## Body (application/json)

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| title | string | No | — | Constraints: min length: 1 |
| description | string | No | — | Constraints: nullable |
| platform | string | No | — | Target platform. Guides and surveys without an explicit platform are returned as `web`. Allowed values: web, ios, android, react-native, desktop, flutter |
| priority | integer | No | — | Constraints: min: 1, max: 4 |
| page_target_segments | unknown[] | No | — | — |
| temporarily_hide_page_target_segments | unknown[] | No | — | — |
| hide_if_page_targeting_not_met | boolean | No | — | — |
| trigger_config | object | No | — | Trigger configuration object. |
| lifecycle | object | No | — | Lifecycle rules object. |
| dismissible | boolean | No | — | — |
| snoozable | boolean | No | — | — |
| snoozable_on_all_steps | boolean | No | — | — |
| snooze_duration | object | No | — | Snooze duration configuration. |
| snooze_label | string | No | — | Constraints: nullable |
| template_source | string | No | — | Constraints: nullable |
| show_step_counter | boolean | No | — | — |
| step_counter_format | string | No | — | Constraints: nullable |
| tags | string[] | No | — | — |
| variants | object[] | No | — | — |
| variants.id | string | No | — | — |
| variants.variant | string | Yes | — | Variant key within the nudge. |
| variants.display_title | string | No | — | Constraints: nullable |
| variants.display_description | string | No | — | Constraints: nullable |
| variants.snooze_label | string | No | — | Constraints: nullable |
| variants.done_label | string | No | — | Constraints: nullable |
| variants.steps | object[] | No | — | — |
| variants.steps.id | string | No | — | — |
| variants.steps.title | string | No | — | Constraints: nullable |
| variants.steps.form_factor | object | No | — | Layout object for a step. `type` selects the form factor; additional keys are layout-specific. |
| variants.steps.form_factor.type | string | Yes | — | Step presentation layout. Required layout keys and allowed values differ by form factor. Allowed values: banner, card, checklist, modal, pin, popover, tooltip |
| variants.steps.content | unknown | No | — | Step body content (structure varies by form factor). |
| variants.steps.sort_key | integer | No | — | Constraints: nullable |
| latest_version | integer | Yes | — | Expected `latest_version` from the last GET with `include_unpublished_changes=true`. |

## Response (application/json)

**200** — Survey updated.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| data | object | Yes | — | — |
| data.id | string | Yes | — | Numeric nudge identifier. Constraints: pattern: ^[0-9]+$ |
| data.object | string | Yes | — | — |
| data.project_id | string | Yes | — | Constraints: pattern: ^[0-9]+$ |
| data.type | string | Yes | — | — |
| data.platform | string | Yes | — | Target platform. Guides and surveys without an explicit platform are returned as `web`. Allowed values: web, ios, android, react-native, desktop, flutter |
| data.title | string | Yes | — | Constraints: nullable |
| data.description | string | No | — | Constraints: nullable |
| data.is_archived | boolean | Yes | — | — |
| data.priority | integer | Yes | — | Trigger precedence (4 = urgent, 1 = low). Constraints: min: 1, max: 4 |
| data.status | string | Yes | — | Derived rollout state. Read-only on API responses. Allowed values: draft, published, testing, scheduled, scheduled-active, scheduled-inactive, experiment-running, experiment-inactive, archived |
| data.status_description | string | Yes | — | — |
| data.key | string | Yes | — | Feature flag key that controls delivery. Matches the `[Guides-Surveys] Key` property on SDK-tracked guide and survey events, so use it to join events to this guide or survey. Constraints: nullable |
| data.start_at | string | Yes | — | Scheduled start of the live flag. `null` when no start is scheduled. Constraints: format: date-time, nullable |
| data.end_at | string | Yes | — | Scheduled end of the live flag. `null` when no end is scheduled. Constraints: format: date-time, nullable |
| data.url | string | Yes | — | Admin URL for the guide or survey. Constraints: format: uri |
| data.page_target_segments | unknown[] | No | — | Page URL targeting rules. Empty means globally eligible. |
| data.tags | string[] | No | — | — |
| data.created_by | string | No | — | Constraints: nullable |
| data.last_modified_by | string | No | — | Constraints: nullable |
| data.created_at | string | Yes | — | Constraints: format: date-time, nullable |
| data.updated_at | string | Yes | — | Constraints: format: date-time, nullable |
| data.latest_version | integer | Yes | — | Monotonic version for optimistic concurrency. Send the value from the latest GET on PATCH; a stale value returns 409. |
| data.temporarily_hide_page_target_segments | unknown[] | No | — | — |
| data.hide_if_page_targeting_not_met | boolean | No | — | — |
| data.trigger_config | unknown | No | — | When and how the nudge triggers. |
| data.lifecycle | unknown | No | — | Frequency and display lifecycle rules. |
| data.dismissible | boolean | No | — | — |
| data.snoozable | boolean | No | — | — |
| data.snoozable_on_all_steps | boolean | No | — | — |
| data.snooze_duration | unknown | No | — | Snooze duration configuration. |
| data.snooze_label | string | No | — | Constraints: nullable |
| data.template_source | string | No | — | Constraints: nullable |
| data.show_step_counter | boolean | No | — | — |
| data.step_counter_format | string | No | — | Constraints: nullable |
| data.theme_id | string | No | — | Theme applied to this guide or survey. `null` means the project's default theme for the platform. Fetch it with the Themes API. Constraints: nullable, pattern: ^[0-9]+$ |
| data.variants | object[] | No | — | — |
| data.variants.id | string | Yes | — | — |
| data.variants.variant | string | Yes | — | Variant key within the nudge. |
| data.variants.display_title | string | No | — | Constraints: nullable |
| data.variants.display_description | string | No | — | Constraints: nullable |
| data.variants.snooze_label | string | No | — | Constraints: nullable |
| data.variants.done_label | string | No | — | Constraints: nullable |
| data.variants.steps | object[] | No | — | — |
| data.variants.steps.id | string | Yes | — | — |
| data.variants.steps.title | string | No | — | Constraints: nullable |
| data.variants.steps.form_factor | object | No | — | Layout object for a step. `type` selects the form factor; additional keys are layout-specific. |
| data.variants.steps.form_factor.type | string | Yes | — | Step presentation layout. Required layout keys and allowed values differ by form factor. Allowed values: banner, card, checklist, modal, pin, popover, tooltip |
| data.variants.steps.content | unknown | No | — | Step body content (structure varies by form factor). |
| data.variants.steps.content_v2 | object | No | — | Block-builder layout: a tree of `layout` containers whose `children` are containers or content blocks, including the step's `title` block. Present only on steps built in the block builder. When present, the dashboard and SDK render this tree, not `title` and `content`. Not accepted on create or update. |
| data.variants.steps.sort_key | integer | No | — | Constraints: nullable |
| data.experiment_variants | object[] | No | — | Read-only experiment variant keys when the nudge is experiment-backed. |
| data.experiment_variants.key | string | Yes | — | — |
| data.experiment_variants.name | string | No | — | Constraints: nullable |
| data.experiment_variants.description | string | No | — | Constraints: nullable |
| data.experiment_variants.payload | unknown | No | — | Optional JSON payload associated with the experiment variant. |
| data.flag_config | oneOf | No | — | The Experiment feature flag that delivers this nudge, in the same shape as the Feature Flags API. Includes audience targeting (`target_segments`) and rollout. With `include_unpublished_changes=true`, draft rollout and targeting settings are applied over the live flag. Constraints: object, null |
| data.flag_config.id | string | No | — | — |
| data.flag_config.project_id | string | No | — | Constraints: pattern: ^[0-9]+$ |
| data.flag_config.key | string | No | — | — |
| data.flag_config.name | string | No | — | — |
| data.flag_config.description | string | No | — | Constraints: nullable |
| data.flag_config.deployments | string[] | No | — | Deployment IDs associated with this flag. Managed via the create/update deployment fields, not set directly on this field. |
| data.flag_config.enabled | boolean | No | — | — |
| data.flag_config.evaluation_mode | string | No | — | Allowed values: local, remote |
| data.flag_config.variants | object[] | No | — | — |
| data.flag_config.variants.key | string | Yes | — | Stable variant key. The value `off` is reserved. Constraints: pattern: ^[A-Za-z0-9_-]+$ |
| data.flag_config.variants.name | string | No | — | Constraints: nullable |
| data.flag_config.variants.description | string | No | — | Constraints: nullable |
| data.flag_config.variants.payload | unknown | No | — | Optional JSON payload returned by evaluation. |
| data.flag_config.bucketing_key | string | No | — | Bucketing key used for assignment. Never null in responses; defaults to `amplitude_id` when not explicitly set. |
| data.flag_config.bucketing_salt | string | No | — | Constraints: nullable |
| data.flag_config.bucketing_unit | string | No | — | Constraints: nullable |
| data.flag_config.rollout_percentage | integer | No | — | Constraints: min: 0, max: 100 |
| data.flag_config.rollout_weights | object | No | — | Variant-keyed rollout weights. Values may be normalized to sum to 100 (percentages) or expressed as unnormalized relative weights (for example `{ "control": 1, "treatment": 1 }` for an even split). Weights are non-negative and may be fractional. |
| data.flag_config.target_segments | object[] | No | — | — |
| data.flag_config.target_segments.name | string | No | — | Constraints: nullable |
| data.flag_config.target_segments.conditions | object[] | Yes | — | — |
| data.flag_config.target_segments.conditions.group_type | string | No | — | Constraints: nullable |
| data.flag_config.target_segments.conditions.prop | string | Yes | — | Property name or cohort identifier being targeted. Constraints: min length: 1 |
| data.flag_config.target_segments.conditions.prop_type | string | No | — | Namespace of the targeted property, for example `user`, `event`, or `group`. Omitted for conditions that target a cohort rather than a property. Constraints: nullable |
| data.flag_config.target_segments.conditions.op | string | Yes | — | Targeting operator applied to the property values. Allowed values: is, is not, contains, does not contain, less, less or equal, greater, greater or equal, set is, set is not, set contains, set does not contain, glob match, glob does not match |
| data.flag_config.target_segments.conditions.type | string | Yes | — | Condition type, for example `property` or `cohort`. |
| data.flag_config.target_segments.conditions.values | string[] | Yes | — | At least one value to match against. Conditions with no values are rejected. |
| data.flag_config.target_segments.percentage | integer | No | — | Segment rollout percentage. Constraints: nullable, min: 0, max: 100 |
| data.flag_config.target_segments.rollout_weights | object | No | — | Variant-keyed rollout weights. Values may be normalized to sum to 100 (percentages) or expressed as unnormalized relative weights (for example `{ "control": 1, "treatment": 1 }` for an even split). Weights are non-negative and may be fractional. |
| data.flag_config.target_segments.bucketing_key | string | No | — | Constraints: nullable |
| data.flag_config.testers | object[] | No | — | — |
| data.flag_config.testers.variant_key | string | Yes | — | — |
| data.flag_config.testers.values | string[] | Yes | — | User IDs, device IDs, or cohort identifiers included in this variant. At most 2000 entries per variant (the limit is 10 when the entries are cohort identifiers). |
| data.flag_config.owners | string[] | No | — | — |
| data.flag_config.tags | string[] | No | — | — |
| data.flag_config.created_by | string | No | — | Constraints: nullable |
| data.flag_config.last_modified_by | string | No | — | Constraints: nullable |
| data.flag_config.created_at | string | No | — | Constraints: format: date-time, nullable |
| data.flag_config.updated_at | string | No | — | Constraints: format: date-time, nullable |
| data.flag_config.parent_dependencies | object | No | — | — |
| data.flag_config.parent_dependencies.operator | string | Yes | — | Allowed values: all, any |
| data.flag_config.parent_dependencies.flags | object[] | Yes | — | — |
| data.flag_config.parent_dependencies.flags.flag_id | string | Yes | — | — |
| data.flag_config.parent_dependencies.flags.allowed_variants | string[] | No | — | — |
| data.flag_config.links | object[] | No | — | — |
| data.flag_config.links.url | string | Yes | — | Constraints: format: uri |
| data.flag_config.links.title | string | Yes | — | — |
| data.flag_config.version | integer | No | — | Server-managed config version used for optimistic concurrency. |
| data.flag_config.archived | boolean | No | — | Whether the resource is archived. Set via the archive (DELETE) operation. |
| data.flag_config.url | string | No | — | Constraints: format: uri, nullable |
| data.flag_config.object | string | No | — | Resource-type discriminator. Always `feature_flag`. |

```json
{
  "data": {
    "id": "string",
    "object": "survey",
    "project_id": "string",
    "type": "SURVEY",
    "platform": "web",
    "title": "string",
    "description": "string",
    "is_archived": true,
    "priority": 1,
    "status": "draft",
    "status_description": "string",
    "key": "string",
    "start_at": "2024-01-01T00:00:00Z",
    "end_at": "2024-01-01T00:00:00Z",
    "url": "https://example.com",
    "page_target_segments": [
      null
    ],
    "tags": [
      "string"
    ],
    "created_by": "string",
    "last_modified_by": "string",
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-01T00:00:00Z",
    "latest_version": 0,
    "temporarily_hide_page_target_segments": [
      null
    ],
    "hide_if_page_targeting_not_met": true,
    "trigger_config": null,
    "lifecycle": null,
    "dismissible": true,
    "snoozable": true,
    "snoozable_on_all_steps": true,
    "snooze_duration": null,
    "snooze_label": "string",
    "template_source": "string",
    "show_step_counter": true,
    "step_counter_format": "string",
    "theme_id": "string",
    "variants": [
      {
        "id": "string",
        "variant": "string",
        "display_title": "string",
        "display_description": "string",
        "snooze_label": "string",
        "done_label": "string",
        "steps": [
          {
            "id": "string",
            "title": "string",
            "form_factor": {
              "type": "banner"
            },
            "content": null,
            "content_v2": {},
            "sort_key": 0
          }
        ]
      }
    ],
    "experiment_variants": [
      {
        "key": "string",
        "name": "string",
        "description": "string",
        "payload": null
      }
    ],
    "flag_config": {
      "id": "string",
      "project_id": "string",
      "key": "string",
      "name": "string",
      "description": "string",
      "deployments": [
        "string"
      ],
      "enabled": true,
      "evaluation_mode": "local",
      "variants": [
        {
          "key": "string",
          "name": "string",
          "description": "string",
          "payload": null
        }
      ],
      "bucketing_key": "string",
      "bucketing_salt": "string",
      "bucketing_unit": "string",
      "rollout_percentage": 0,
      "rollout_weights": {},
      "target_segments": [
        {
          "name": "string",
          "conditions": [
            {
              "group_type": "string",
              "prop": "string",
              "prop_type": "string",
              "op": "is",
              "type": "string",
              "values": [
                "string"
              ]
            }
          ],
          "percentage": 0,
          "rollout_weights": {},
          "bucketing_key": "string"
        }
      ],
      "testers": [
        {
          "variant_key": "string",
          "values": [
            "string"
          ]
        }
      ],
      "owners": [
        "string"
      ],
      "tags": [
        "string"
      ],
      "created_by": "string",
      "last_modified_by": "string",
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-01T00:00:00Z",
      "parent_dependencies": {
        "operator": "all",
        "flags": [
          {
            "flag_id": "string",
            "allowed_variants": [
              "string"
            ]
          }
        ]
      },
      "links": [
        {
          "url": "https://example.com",
          "title": "string"
        }
      ],
      "version": 0,
      "archived": true,
      "url": "https://example.com",
      "object": "feature_flag"
    }
  }
}
```

**400**

**401**

**403**

**404**

**409**

**429**

**500**

## Code samples

### cURL

```bash
curl -X PATCH "https://developer-api.amplitude.com/v1/projects/12345/surveys/{survey_id}" \
  -H "Content-Type: application/json" \
  -H "Authorization: YOUR_API_KEY"
```

### Python

```python
import requests

response = requests.patch(
    "https://developer-api.amplitude.com/v1/projects/12345/surveys/{survey_id}",
    headers={
        "Content-Type": "application/json",
        "Authorization": "YOUR_API_KEY"
    }
)
data = response.json()
```

### JavaScript

```javascript
const response = await fetch("https://developer-api.amplitude.com/v1/projects/12345/surveys/{survey_id}", {
  method: "PATCH",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "YOUR_API_KEY"
  }
});
const data = await response.json();
```

### PHP

```php
<?php
$ch = curl_init("https://developer-api.amplitude.com/v1/projects/12345/surveys/{survey_id}");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Content-Type: application/json",
    "Authorization: YOUR_API_KEY"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
```

### Go

```go
package main

import (
  "bytes"
  "net/http"
)

func main() {
req, _ := http.NewRequest("PATCH", "https://developer-api.amplitude.com/v1/projects/12345/surveys/{survey_id}", nil)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "YOUR_API_KEY")
  client := &http.Client{}
  resp, _ := client.Do(req)
  defer resp.Body.Close()
}
```

### Java

```java
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://developer-api.amplitude.com/v1/projects/12345/surveys/{survey_id}"))
      .method("PATCH", HttpRequest.BodyPublishers.noBody())
.header("Content-Type", "application/json")
      .header("Authorization", "YOUR_API_KEY")
      .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
```

### Ruby

```ruby
require "net/http"
require "json"

uri = URI("https://developer-api.amplitude.com/v1/projects/12345/surveys/{survey_id}")
request = Net::HTTP::Patch.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end
```

