---
title: "Edit survey blocks"
method: PATCH
path: "/api/v3/surveys/{surveyId}/blocks"
tags: ["V3 Surveys"]
---

# Edit survey blocks

`PATCH /api/v3/surveys/{surveyId}/blocks`

## Request

- Base URL: `https://app.formbricks.com`
- URL: `https://app.formbricks.com/api/v3/surveys/{surveyId}/blocks`
- Auth: one of:
  - API key in cookie `next-auth.session-token`
  - API key in header `x-api-key`
  - HTTP bearer

Edits a survey's blocks in place — update, insert or remove whole blocks without resending the ones you are not changing. Operations apply in order against a single snapshot and are applied atomically: either all of them land or none do.

Blocks are addressed by id, never by position, so a concurrent edit cannot silently redirect an operation onto a different block. An `update` replaces the target block entirely, the same whole-subtree rule `PATCH /api/v3/surveys/{surveyId}` uses, and the replacement must carry every language the survey has configured.

Pass `expectedUpdatedAt` (the `updatedAt` from your last read) to make the write conditional; see the **409** response. Session cookie or x-api-key.

## Path parameters

- `surveyId` string, cuid2, required

## Request body

- EditSurveyBlocksRequest
  - `ops` SurveyBlockOperation[], required: Operations applied in order against a single snapshot, atomically — either all of them land or none do. Each operation resolves against the state left by the previous one, so an insert may anchor after a block an earlier operation inserted, and a remove followed by an insert of the same id is legal.
    - union: A single block operation.
      - SurveyBlockUpdateOperation: Replace one existing block, addressed by id.
        - `op` 'update', required
        - `id` string, required: Block to replace.
        - `block` CreateSurveyBlock, required: Block accepted by `POST /api/v3/surveys`. `id` may be omitted and will be generated by the server. Provide an explicit cuid2 id when logic in the same request needs to jump to this block. For normal sequential flow, omit `logic` and `logicFallback`. `logicFallback` is only valid when this same block has at least one `logic` rule.
          - `id` string, cuid2: Optional stable block id. Generated when omitted.
          - `name` string, required
          - `elements` SurveyElement[], required
            - union: Survey element/question inside a block. Element ids are stable public identifiers used by logic, recall strings, response data, quotas, integrations, and analysis. `type` selects the allowed shape; unsupported fields are rejected instead of ignored.
              - …
          - `logic` SurveyBlockLogic[]
            - `id` string, cuid2, required
            - `conditions` SurveyConditionGroup, required
              - …
            - `actions` SurveyLogicAction[], required
              - …
          - `logicFallback` string, cuid2: Block or ending id used when no logic condition matches. Only valid when this same block has at least one `logic` rule; omit it for normal sequential flow.
          - `buttonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
          - `backButtonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
      - SurveyBlockInsertOperation: Add a new block at an anchored position.
        - `op` 'insert', required
        - `block` CreateSurveyBlock, required: Block accepted by `POST /api/v3/surveys`. `id` may be omitted and will be generated by the server. Provide an explicit cuid2 id when logic in the same request needs to jump to this block. For normal sequential flow, omit `logic` and `logicFallback`. `logicFallback` is only valid when this same block has at least one `logic` rule.
          - `id` string, cuid2: Optional stable block id. Generated when omitted.
          - `name` string, required
          - `elements` SurveyElement[], required
            - union: Survey element/question inside a block. Element ids are stable public identifiers used by logic, recall strings, response data, quotas, integrations, and analysis. `type` selects the allowed shape; unsupported fields are rejected instead of ignored.
              - …
          - `logic` SurveyBlockLogic[]
            - `id` string, cuid2, required
            - `conditions` SurveyConditionGroup, required
              - …
            - `actions` SurveyLogicAction[], required
              - …
          - `logicFallback` string, cuid2: Block or ending id used when no logic condition matches. Only valid when this same block has at least one `logic` rule; omit it for normal sequential flow.
          - `buttonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
          - `backButtonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
        - `position` union, required: Where an inserted block goes. Anchored to a block id, never to a positional index.
          - object
            - `type` 'start', required: Insert before every existing block.
          - object
            - `type` 'end', required: Insert after every existing block.
          - object
            - `type` 'after', required
            - `blockId` string, required: Block to insert after. May be a block inserted by an earlier operation in the same request, since operations are applied in order.
      - SurveyBlockRemoveOperation: Delete one existing block, addressed by id.
        - `op` 'remove', required
        - `id` string, required: Block to delete, along with every element in it. Answers already collected for those elements are orphaned and the API cannot undo that.
  - `expectedUpdatedAt` string, date-time: Optimistic-concurrency precondition: the survey's `updatedAt` from your last read. If the survey changed since, the write is rejected with **409** and the response carries the current value. Omit it to accept last-write-wins.

## Response `200`

Blocks updated; returns the full survey resource.

- object
  - `data` SurveyResource, required: The three fields every `SurveyListItem` and `SurveyResource` carries, merged into both via `allOf`. All required, always present.
    - `id` string, required
    - `workspaceId` string, required
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `archivedAt` string, date-time, nullable, required: Soft-delete/archive marker (ISO 8601); `null` when the survey is active.
    - `name` string, required
    - `type` 'link' | 'app', required
    - `status` 'draft' | 'inProgress' | 'paused' | 'completed', required
    - `metadata` SurveyMetadata, required: Arbitrary JSON survey context for customer- or operation-specific metadata. v3 preserves arbitrary metadata values as-is. If present, `title` and `description` are treated as translatable text maps and returned with real locale-code keys.
      - `title` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
      - `description` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
    - `defaultLanguage` string, required: Emitted language code/tag for the survey default language. The internal `default` translation key is never exposed.
    - `languages` SurveyLanguage[], required
      - `code` string, required: Server-emitted survey language code/tag used as the translatable map key.
      - `alias` string, nullable: Optional configured alias accepted by `?lang` for compatibility and agent discovery.
      - `default` boolean, required: Whether this is the default authoring language.
      - `enabled` boolean, required: Whether this language is enabled for respondent-facing delivery.
    - `showLanguageSwitch` boolean, nullable, required: Show respondents a language switch on multi-language surveys. `null` and `false` both mean off.
    - `autoSelectLanguage` boolean, nullable, required: Open link and app surveys in the respondent's browser language when it matches an enabled survey language; otherwise the default language is used. `null` and `false` both mean off.
    - `welcomeCard` SurveyWelcomeCard, required: Optional card shown before the first survey block.
      - `enabled` boolean, required
      - `headline` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
      - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
      - `buttonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
      - `fileUrl` string
      - `videoUrl` string
      - `timeToFinish` boolean
      - `showResponseCount` boolean
    - `blocks` SurveyBlock[], required
      - `id` string, cuid2, required: Stable block id.
      - `name` string, required
      - `elements` SurveyElement[], required
        - union: Survey element/question inside a block. Element ids are stable public identifiers used by logic, recall strings, response data, quotas, integrations, and analysis. `type` selects the allowed shape; unsupported fields are rejected instead of ignored.
          - SurveyOpenTextElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'openText', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `placeholder` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `longAnswer` boolean
            - `inputType` 'text' | 'email' | 'url' | 'number' | 'phone'
            - `insightsEnabled` boolean
            - `charLimit` SurveyCharLimit: Optional `openText` character limit configuration.
              - …
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyConsentElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'consent', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `label` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyMultipleChoiceSingleElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'multipleChoiceSingle', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `choices` SurveyChoice[], required
              - …
            - `shuffleOption` 'none' | 'all' | 'exceptLast' | 'reverseOrderOccasionally' | 'reverseOrderExceptLast'
            - `otherOptionPlaceholder` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `displayType` 'list' | 'row' | 'dropdown'
          - SurveyMultipleChoiceMultiElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'multipleChoiceMulti', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `choices` SurveyChoice[], required
              - …
            - `shuffleOption` 'none' | 'all' | 'exceptLast' | 'reverseOrderOccasionally' | 'reverseOrderExceptLast'
            - `otherOptionPlaceholder` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
            - `displayType` 'list' | 'row' | 'dropdown'
          - SurveyNpsElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'nps', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `lowerLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `upperLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `isColorCodingEnabled` boolean
          - SurveyCtaElement: If `buttonExternal` is true, `buttonUrl` and `ctaButtonLabel` are required.
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'cta', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `buttonExternal` boolean
            - `buttonUrl` string
            - `ctaButtonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
          - SurveyRatingElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'rating', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `scale` 'number' | 'smiley' | 'star', required
            - `range` 3 | 4 | 5 | 6 | 7 | 10, required
            - `lowerLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `upperLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `isColorCodingEnabled` boolean
          - SurveyPictureSelectionElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'pictureSelection', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `allowMulti` boolean
            - `choices` SurveyPictureChoice[], required
              - …
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyDateElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'date', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `html` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `format` 'M-d-y' | 'd-M-y' | 'y-M-d', required
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyFileUploadElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'fileUpload', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `allowMultipleFiles` boolean, required
            - `maxSizeInMB` number
            - `allowedFileExtensions` string[]
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyCalElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'cal', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `calUserName` string, required
            - `calHost` string
          - SurveyMatrixElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'matrix', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `rows` SurveyChoice[], required
              - …
            - `columns` SurveyChoice[], required
              - …
            - `shuffleOption` 'none' | 'all' | 'exceptLast' | 'reverseOrderOccasionally' | 'reverseOrderExceptLast'
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyAddressElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'address', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `addressLine1` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `addressLine2` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `city` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `state` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `zip` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `country` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyRankingElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'ranking', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `choices` SurveyChoice[], required
              - …
            - `otherOptionPlaceholder` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `shuffleOption` 'none' | 'all' | 'exceptLast' | 'reverseOrderOccasionally' | 'reverseOrderExceptLast'
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyContactInfoElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'contactInfo', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `firstName` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `lastName` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `email` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `phone` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `company` SurveyToggleInputConfig, required: Field config for address and contact info elements.
              - …
            - `validation` SurveyValidation: Optional element-level validation rules.
              - …
          - SurveyCsatElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'csat', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `scale` 'number' | 'smiley' | 'star', required
            - `range` 5, required
            - `lowerLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `upperLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `isColorCodingEnabled` boolean
          - SurveyCesElement
            - `id` string, required: Stable element id. Avoid spaces and reserved ids.
            - `type` 'ces', required
            - `headline` TranslatableText, required: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `required` boolean, required
            - `imageUrl` string
            - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `videoUrl` string
            - `isDraft` boolean: Draft marker used by the editor and future update rules.
            - `scale` 'number' | 'smiley' | 'star', required
            - `range` 5 | 7, required
            - `lowerLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `upperLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
            - `isColorCodingEnabled` boolean
      - `logic` SurveyBlockLogic[]
        - `id` string, cuid2, required
        - `conditions` SurveyConditionGroup, required
          - `id` string, cuid2, required
          - `connector` 'and' | 'or', required
          - `conditions` union[], required
            - union
              - …
        - `actions` SurveyLogicAction[], required
          - union: Logic action. Keep referenced ids stable: `calculate.variableId` points to a variable id, `requireAnswer.target` points to an element id, and `jumpToBlock.target` points to a block id or ending id.
            - SurveyCalculateAction: Updates a survey variable when the logic rule matches.
              - …
            - SurveyRequireAnswerAction: Requires an element/question to be answered before continuing.
              - …
            - SurveyJumpToBlockAction: Jumps to another block or ending when the logic rule matches.
              - …
      - `logicFallback` string, cuid2: Block or ending id used when no logic condition matches. Only valid when this same block has at least one `logic` rule; omit it for normal sequential flow.
      - `buttonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
      - `backButtonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
    - `endings` SurveyEnding[], required
      - union: Ending reached after the last block or a jump action. `type` selects the allowed shape; unsupported fields are rejected instead of ignored.
        - SurveyEndScreenEnding: Visual end screen displayed after survey completion.
          - `id` string, cuid2, required: Stable ending id. `jumpToBlock.target` may point to this id.
          - `type` 'endScreen', required
          - `headline` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
          - `subheader` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
          - `buttonLabel` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
          - `buttonLink` string
          - `imageUrl` string
          - `imageAltText` TranslatableText: Multilingual text map keyed by the emitted `languages[].code` values for this survey.
          - `videoUrl` string
          - `hideDefaultIcon` boolean: Hides the default checkmark icon rendered above the headline when the ending carries no image or video. Omit to keep the icon.
        - SurveyRedirectEnding: Redirects the respondent to a URL after survey completion. External redirects require the organization's external URL permission; otherwise write endpoints return `403 Forbidden`.
          - `id` string, cuid2, required: Stable ending id. `jumpToBlock.target` may point to this id.
          - `type` 'redirectToUrl', required
          - `url` string, uri, required: External redirect URL. Requires the organization's external URL permission.
          - `label` string: Optional internal label for redirect endings.
    - `hiddenFields` SurveyHiddenFields, required: Hidden fields, sometimes called embedded data in other survey products. Field ids are stable public identifiers and may be referenced by logic, recall, quotas, integrations, and response data. **Naming rule for new field ids** — the same rule the survey editor applies (ENG-2539): a new id must start with a lowercase letter and then contain only lowercase letters, numbers and underscores (`^[a-z][a-z0-9_]*$`), and must not take a reserved name. Reserved are the link-survey system params and internal ids — `userId`, `source`, `suid`, `end`, `start`, `welcomeCard`, `hidden`, `verifiedEmail`, `multiLanguage`, `embed`, `verify`, `suToken`, `lang`, `preview`, `startAt`, `skipPrefilled`, `offlineSupport` (matched case-insensitively) — and the names of auto-captured system fields, which every survey can already read without declaring them: `source`, `url`, `country`, `action`, `browser`, `os`, `deviceType`, `ipAddress`, `finished`, `language`, `locale`, `responseId`, `surveyId`, `durationSeconds`, `startedAt`, `finishedAt`, `pagePath`, `pageReferrer`, `utmSource`, `utmMedium`, `utmCampaign`, `utmTerm`, `utmContent`, `screenWidth`, `screenHeight`, `viewportWidth`, `viewportHeight`, `timezone`, `visitPagesViewed`, `visitUniquePagesViewed`, `visitTimeOnSite`, `visitEntryReferrer`, `visitUrls`, `openedByCreativeId`, `openedByCreativeName`. **Ids a survey already declares are grandfathered**: they always load, and re-sending the survey unchanged never fails validation — only *adding* such a name as a new field is refused. Deleting a grandfathered field spends the reprieve: once it is gone from the saved survey, the name can no longer be re-added. Note this means re-creating a survey from an exported document can fail with a 400 when the export declares a name the rule refuses; rename the field in the payload before importing. The `pattern` below describes what stored surveys may hold (the pre-existing lenient charset), not what a new id may look like.
      - `enabled` boolean, required: Derived, not stored: `true` whenever the survey declares at least one hidden field. A value sent on create or update is ignored; to turn hidden fields off, remove them from `fieldIds`.
      - `fieldIds` string[]
    - `variables` SurveyVariable[], required
      - union: Survey variable. Variable ids are stable references used by logic and calculation actions. Variable names are human-readable labels and must be unique within the survey.
        - SurveyNumberVariable: Number variable. Used by `calculate` logic actions with numeric operators such as `add`, `subtract`, `multiply`, `divide`, or `assign`.
          - `id` string, cuid2, required: Stable variable id referenced from logic.
          - `name` string, required: Unique variable name. `pattern` is the charset of a *stored* name; a newly declared one is held to more than that, and the extra rules split into two groups that behave differently. **400 `forbidden_identifier`, grandfathered.** A new name must match `^[a-z][a-z0-9_]*$` (no leading digit or underscore) and must not take a reserved name — the link-survey system params and internal ids (`userId`, `source`, `suid`, `end`, `start`, `welcomeCard`, `hidden`, `verifiedEmail`, `multiLanguage`, `embed`, `verify`, `suToken`, `lang`, `preview`, `startAt`, `skipPrefilled`, `offlineSupport`) or an auto-captured system field name (`country`, `browser`, `deviceType`, …; `SurveyHiddenFields` carries the full list, and the two sets are the same there). Names the survey already declares are grandfathered against these, so re-sending an existing document never trips them. **400 `duplicate_identifier`, not grandfathered.** A variable name that collides case-insensitively with a hidden field id on the same survey. This is checked by reference validation over the whole merged document rather than against the incoming names, so a survey that already holds such a clash is refused on **every** patch — including one that touches neither collection — until one side is renamed.
          - `type` 'number', required
          - `value` number, required: Default numeric value.
        - SurveyTextVariable: Text variable. Used by `calculate` logic actions with text operators such as `assign` or `concat`.
          - `id` string, cuid2, required: Stable variable id referenced from logic.
          - `name` string, required: Unique variable name. `pattern` is the charset of a *stored* name; a newly declared one is held to more than that, and the extra rules split into two groups that behave differently. **400 `forbidden_identifier`, grandfathered.** A new name must match `^[a-z][a-z0-9_]*$` (no leading digit or underscore) and must not take a reserved name — the link-survey system params and internal ids (`userId`, `source`, `suid`, `end`, `start`, `welcomeCard`, `hidden`, `verifiedEmail`, `multiLanguage`, `embed`, `verify`, `suToken`, `lang`, `preview`, `startAt`, `skipPrefilled`, `offlineSupport`) or an auto-captured system field name (`country`, `browser`, `deviceType`, …; `SurveyHiddenFields` carries the full list, and the two sets are the same there). Names the survey already declares are grandfathered against these, so re-sending an existing document never trips them. **400 `duplicate_identifier`, not grandfathered.** A variable name that collides case-insensitively with a hidden field id on the same survey. This is checked by reference validation over the whole merged document rather than against the incoming names, so a survey that already holds such a clash is refused on **every** patch — including one that touches neither collection — until one side is renamed.
          - `type` 'text', required
          - `value` string, required: Default text value.
    - `distribution` SurveyDistribution: App-survey runtime/display settings. Only valid for `type: app`; rejected for link surveys. **Replacement semantics (destructive):** when `distribution` is provided on PATCH it fully replaces the stored object — any sub-field you omit is reset to its default, NOT preserved. In particular, omitting `triggers` removes ALL existing triggers, and omitting `displayOption` resets it to `displayOnce`. To change one setting, send the complete desired distribution. To leave distribution untouched, omit the whole `distribution` key.
      - `displayOption` 'displayOnce' | 'displayMultiple' | 'respondMultiple' | 'displaySome': How often the survey may be shown to a contact. `displaySome` shows it up to `displayLimit` times (or until the contact responds, whichever comes first).
      - `displayPercentage` number, nullable: Independent throttle: show the survey to only this percentage of triggered contacts. Optional and valid with any `displayOption`; null/omitted means no throttle (shown to everyone).
      - `displayLimit` integer, nullable: Maximum number of times the survey is shown to a single contact. Required (must be >= 1) when `displayOption` is `displaySome`; otherwise optional.
      - `recontactDays` integer, nullable: Days to wait before showing this survey again to the same contact. Null uses the workspace default.
      - `autoClose` integer, nullable: Seconds of inactivity after which the survey widget auto-closes. Null disables auto-close.
      - `keepEndingCardOpen` boolean: Keep the ending card on screen until the respondent closes the survey. When false, the survey widget closes 3 seconds after the ending card appears. Has no effect on a survey with no ending card (it closes immediately) or whose first ending redirects to a URL. Independent of `autoClose`.
      - `autoComplete` integer, nullable: Automatically stop collecting responses after this many completed responses. Null disables it.
      - `delay` integer: Seconds to wait after a trigger fires before showing the survey.
      - `showConditions` SurveyShowConditionGroup: A group of show conditions. `and` means every condition must hold; `or` means one is enough. A group can hold one more group, no deeper. An empty group is stored as `null`.
        - `id` string, required: Client-generated id (cuid2), unique within the survey's conditions.
        - `connector` 'and' | 'or', required
        - `conditions` union[], required
          - union
            - SurveyShowCondition: One check, read like a sentence: what to look at (`leftOperand`), how to compare (`operator`) and what to compare with (`rightOperand`). Text comparisons ignore upper and lower case. | `leftOperand.type` | `leftOperand.value` | Operators | | --- | --- | --- | | `page` | `currentUrl` (full URL, query included) | `pathIsAnyOf`, `pathIsNoneOf`, `containsAnyOf`, `containsNoneOf`, `equals`, `doesNotEqual`, `contains`, `doesNotContain`, `startsWith`, `endsWith` | | `page` | `pageReferrer`, `entryReferrer` (first page of the visit) | `equals`, `doesNotEqual`, `contains`, `doesNotContain`, `startsWith`, `endsWith`, `containsAnyOf`, `containsNoneOf` | | `page` | `queryParam` (name in `meta.key`) | `equals`, `doesNotEqual`, `contains`, `doesNotContain`, `startsWith`, `endsWith`, `isSet`, `isNotSet` | | `visit` | `pagesViewed`, `uniquePagesViewed`, `timeOnSite` (seconds) | `equals`, `isGreaterThan`, `isLessThan`, `isGreaterThanOrEqual`, `isLessThanOrEqual` | | `visit` | `visitedUrls` (pages seen in this visit, the current one included) | `includes`, `doesNotInclude` | | `device` | `deviceType` (`phone`, `tablet`, `desktop`), `browser` (`chrome`, `safari`, `firefox`, `edge`, `opera`, `samsung`, `other`) | `equals`, `doesNotEqual` | | `device` | `screenWidth` (browser window width, CSS px) | `equals`, `isGreaterThan`, `isLessThan`, `isGreaterThanOrEqual`, `isLessThanOrEqual` | `pathIsAnyOf` / `pathIsNoneOf` take a list of page paths, each compared exactly with the URL's path: case, a trailing slash, the query string and the `#hash` are ignored, and a full URL is reduced to its path. `/plans` matches `/plans?ref=email` but not `/plans/compare`. `containsAnyOf` / `containsNoneOf` take a list of fragments; a line passes when the URL contains it anywhere, so `/plans` also matches `/plans/compare`. `visitedUrls` takes one page path, compared exactly like a `pathIsAnyOf` line. `uniquePagesViewed` takes at most 200, the number of different pages a visit remembers. `isSet` / `isNotSet` take no `rightOperand`. A visit is one browser tab; if the browser blocks storage, visit conditions fail.
              - …
            - SurveyShowConditionGroup (recursive)
      - `triggers` SurveyTrigger[]: Action classes that trigger the survey. Every id must reference an existing workspace action class. On PATCH this list fully replaces the survey's triggers — omitting it (or sending `[]`) removes all existing triggers.
        - `actionClassId` string, cuid2, required: Id of an action class in the same workspace.
    - `targeting` SurveyTargeting: App-survey contact targeting. Only valid for `type: app`. `filters: []` targets everyone. Setting or changing non-empty filters requires the Contacts entitlement; otherwise create/patch returns 403. `attribute` filters reference workspace contact-attribute keys (discover them via `GET /api/v3/contact-attribute-keys`) and `segment` filters reference other segment ids — both are workspace-scoped resources you must obtain before constructing filters (an invalid key/id targets no one rather than erroring). See `SegmentFilter` for the per-`root.type` operator sets.
      - `filters` object[], required: Contact targeting filter tree. An empty array targets everyone. Each node joins the previous one via its `connector` (`and`/`or`; the first node's connector is null). A node's `resource` is either a single filter condition or a nested filter group (enabling parenthesized `and`/`or` logic).
        - `id` string, cuid2, required
        - `connector` 'and' | 'or' | 'null', nullable, required: Logical connector joining this node to the previous one. Null for the first node.
        - `resource` union, required: A single filter condition, or a nested filter group for grouped logic.
          - union: A single targeting condition. `root.type` selects the subject and determines the valid `qualifier.operator` set: `attribute` (a workspace contact-attribute key), `person` (a built-in person identifier such as `userId`/`email`), `segment` (membership in another segment), `device`, or `surveyInteraction` (how the contact interacted with surveys). Each variant is one member of this union; the matching member is chosen by `root.type`.
            - object: Matches on a workspace contact-attribute value.
              - …
            - object: Matches on a built-in person identifier.
              - …
            - object: Matches on membership in another segment.
              - …
            - object: Matches on the contact's device type.
              - …
            - object: Matches on how the contact interacted with surveys within a time window. `surveyIds` only names surveys the caller may see; ids of other surveys the segment targets are left out.
              - …
          - SegmentFilters (recursive)
    - `customCss` CustomCssInput, required: Custom CSS **source** as a caller writes it (ENG-3641). Both keys are required. `light` is base CSS that applies in both appearances; `dark` adds overrides on top of it when the survey renders dark. `null`, an empty string or whitespace means "no CSS" for that field. Source only: compiled output and the processor version are computed by the server on every write, and a request that supplies either is rejected. The combined source is limited to 100 000 UTF-8 bytes for a workspace and 20 000 for a survey; larger CSS is a **422** with error code `source_too_large`.
      - `light` string, nullable, required: Base CSS, applied in light and dark appearance.
      - `dark` string, nullable, required: Additional CSS applied only in dark appearance.
    - `visibility` 'restricted' | 'workspace', required: `restricted`: readable by the owner and the organisation's owners and managers only. The owner's access is conditional on their workspace access, level for level: they read the survey only while they can read the workspace, and edit it only while they can write to it — being the owner grants nothing the workspace does not. `workspace`: readable by everyone with access to the workspace — today's behaviour.
    - `owner` SurveyOwner, required: The authorization owner — the person whose restricted surveys these are. Distinct from `creator`, which is attribution only and is never rewritten. Display only, like `creator`: no user id is exposed, because `access.via === "owner"` already answers "is this mine" and `filter[owner][in]=me` filters server-side. Ownership transfer can add an identifier later, additively. Durable source: `Survey.ownerId` in PostgreSQL, projected to `survey#owner@user`; the graph never holds ownership alone, so a rebuild from an empty graph restores it.
      - `name` string, required
    - `access` SurveyAccess, required: Why **this caller** can see the survey, and whether they may change its visibility. Derived by the server per request; a rendering hint only — every mutation is re-authorised on the server.
      - `via` string, required: Why this caller can see the survey. Known values today: `workspace` (the survey is workspace-visible and the caller has workspace read — always the value for API keys), `owner` (restricted, the caller owns it), `organizationRole` (restricted, the caller reaches it only as an organisation owner or manager — the case that shows the admin banner). **Open set, deliberately not an enum**: named person and team sharing will add values, so clients treat an unknown string as "some other access path" and never branch exhaustively. Explanatory metadata, not authorization truth — the server re-authorises every call.
      - `canManageVisibility` boolean, required: Permission only: `true` when this caller holds `survey.change_visibility` — owner or organisation owner/manager, feature enabled for the organisation and deployment. It can be `true` while `allowedTargets` is empty (blockers, or no owner): it answers "may this person manage visibility at all", which is what shows or hides the controls; `allowedTargets` on `GET …/visibility` answers which transitions would succeed now. Stays `true` for an organisation manager on an ownerless restricted survey.

## Other responses

- `400`: Bad Request — malformed JSON, invalid query/body/params, duplicate name, or unsupported field.
- `401`: Not authenticated (no valid session or API key).
- `403`: Forbidden — no workspace access, or resource does not exist (404 not used; avoids existence leak).
- `409`: The survey changed since the `expectedUpdatedAt` you supplied. Nothing was written. The problem's `details` carries `expectedUpdatedAt` and the live `currentUpdatedAt`, so a client can re-read and retry without guessing.
- `422`: The request is well-formed but could not be applied. `invalid_params[].name` points at the operation that failed — `ops.<i>.…` — including for problems found while validating the resulting document. The one exception is a block the request did not touch: those are reported at `blocks.<i>`, where `<i>` is the block's index in the stored survey — the same index `GET` returns, even when an earlier operation inserted or removed blocks before it — because the problem is in the stored survey rather than in any operation. A `stored_survey_invalid` response uses stored-survey paths throughout for the same reason. Common codes: `dangling_reference` (an id that is not on the survey), `duplicate_identifier` (inserting an id that already exists), `missing_required_field` (an inserted block whose `id` is present but empty — omitting `id` entirely is fine, the server generates one), `immutable_identifier` (`block.id` contradicting the op's `id`), and `stored_survey_invalid` when the stored survey itself fails the document contract. The edit is also refused when it newly *introduces* a loop in the conditional logic — jumps, fallbacks and next blocks leading back on themselves, so a respondent could never reach an ending — reported at the `logic` of each block a new looping step leaves. A survey that already loops stays editable.
- `429`: Rate limit exceeded.
- `500`: Internal Server Error.

## Changes

- **2026-11-02** `25335c959a13`: 2 warning, 4 info
  - added the new `row` enum value to the `data/allOf[subschema #1]/blocks/items/elements/items/oneOf[#/components/schemas/SurveyMultipleChoiceMultiElement]/allOf[subschema #2]/displayType` response property for the response status `200`
  - added the new `row` enum value to the `data/allOf[subschema #1]/blocks/items/elements/items/oneOf[#/components/schemas/SurveyMultipleChoiceSingleElement]/allOf[subschema #2]/displayType` response property for the response status `200`
  - added the new `row` enum value to the request property `ops/items/oneOf[#/components/schemas/SurveyBlockInsertOperation]/block/allOf[#/components/schemas/CreateSurveyBlock]/elements/items/oneOf[#/components/schemas/SurveyMultipleChoiceMultiElement]/allOf[subschema #2]/displayType`
  - added the new `row` enum value to the request property `ops/items/oneOf[#/components/schemas/SurveyBlockInsertOperation]/block/allOf[#/components/schemas/CreateSurveyBlock]/elements/items/oneOf[#/components/schemas/SurveyMultipleChoiceSingleElement]/allOf[subschema #2]/displayType`
  - …2 more
- **2026-10-29** `82c0afd2df39`: 1 breaking
  - added `subschema #5: SurveyInteractionFilter` to the `data/allOf[subschema #1]/targeting/allOf[#/components/schemas/SurveyTargeting]/filters/items/resource/oneOf[#/components/schemas/SegmentFilter]/` response property `oneOf` list for the response status `200`
- …earlier changes not shown

[Operation history](https://skmtc.dev/formbricks/apis/formbricks-api-v3/changes/api/v3/surveys/:surveyId/blocks/patch.md)

---

[API](https://skmtc.dev/formbricks/apis/formbricks-api-v3.md) - [All operations](https://skmtc.dev/formbricks/apis/formbricks-api-v3/llms.txt) - [OpenAPI document](https://skmtc.dev/formbricks/apis/formbricks-api-v3/revisions/25335c959a13?raw)
