---
title: "Update a creative"
method: PATCH
path: "/api/v3/creatives/{creativeId}"
tags: ["V3 Creatives"]
---

# Update a creative

`PATCH /api/v3/creatives/{creativeId}`

## Request

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

Changes a creative. Read/write access to its workspace; an unknown or inaccessible `creativeId` answers **403**. Each group sent replaces the stored one as a whole (see `PatchCreativeRequest`); an empty body changes nothing.

**Status.** Publish with `status: inProgress`, pause with `paused`, close with `completed`, and reopen or resume with `inProgress`. A creative that was ever published can't go back to `draft`. Any status but `draft` must meet the publish rules of `POST /api/v3/creatives`, checked against the creative as it would be after the change, except for pausing or closing a published creative with a body that changes nothing else: taking it down works even when it no longer meets them (its last action was deleted, or its survey unlinked). In wind-down (the license does not include Creatives), only a body that sets nothing but `status` to `paused` or `completed` (with `expectedUpdatedAt` or without) is accepted; any other body, an empty one included, answers **403** `creatives_not_entitled`.

**Custom CSS.** Adding or editing `styling.theme.customCss` follows the rules of `POST /api/v3/creatives`; removing it, or sending it back unchanged, needs no plan and is not processed again.

An archived creative is read-only: restore it first, or the request answers **422**.

**Concurrent changes.** The change applies to the creative as it is stored when the request runs, so a pause, close or archive made meanwhile is never undone by a request that doesn't mention it. Send `expectedUpdatedAt` (the `updatedAt` you last read) to have the change refused with **409** instead when the creative changed since your read.

**Its survey.** Changing or removing `destination` succeeds even when this creative is the last one that opens a live (`inProgress`) app survey with no actions of its own; that survey then shows nowhere until a creative or an action opens it again. Check before relinking.

## Path parameters

- `creativeId` string, cuid2, required

## Request body

- PatchCreativeRequest: Changes to a creative. Each top-level field is a group that **replaces** the stored one as a whole: send the complete `content`, `styling`, `destination`, `distribution` or `schedule` you want, and omit a group to leave it untouched. `defaultLanguage` and `languages` replace the languages; the stored texts must still fit them, so send `content` alongside when they no longer do. `content` and `styling` must have the shape of the creative's own `type`, which never changes; `type` itself is not accepted. Publish, pause, close and reopen by setting `status`. Unknown fields are rejected with **400**.
  - `name` string
  - `status` 'draft' | 'inProgress' | 'paused' | 'completed': The author's intent, and the only status a write sets: `draft` (never published), `inProgress` (published), `paused` (paused by its author) or `completed` (closed by its author). The same values as a survey's `status`. What visitors get is `displayStatus`, which the server derives from this value, `archivedAt`, the schedule and the Destination survey. Nothing writes `status` on its own: a schedule ending or a survey pausing changes `displayStatus` only.
  - `defaultLanguage` string: Canonical locale code accepted by v3 survey APIs, for example `en-US`, `de-DE`, or `zh-Hans-CN`.
  - `languages` CreativeLanguageInput[]
    - `code` string, required: Canonical locale code accepted by v3 survey APIs, for example `en-US`, `de-DE`, or `zh-Hans-CN`.
    - `enabled` boolean, required: Whether visitors in this language see this translation. Ignored for `defaultLanguage`, which is always enabled.
  - `autoSelectLanguage` boolean, nullable: Show the texts in the visitor's browser language when the site sets none with `setLanguage` and it matches the default or an enabled language; otherwise the default language is used. `null` (never chosen) and `false` both mean off. Omit to keep the stored value.
  - `content` union
    - FeedbackButtonContent: What a feedback button shows.
      - `label` CreativeText, required: Plain text per language, keyed by locale code. Must hold `defaultLanguage`; every other key must be declared in `languages`. A visitor whose language is missing sees the default language.
      - `icon` 'messageSquare' | 'messageCircle' | 'megaphone' | 'sparkles' | 'null', nullable, required: An icon before the label, or `null` for none.
    - BannerContent: What a banner shows.
      - `message` CreativeRichText, required: Formatted text per language, keyed by locale code: each value is the text as a list of runs. Must hold `defaultLanguage`; every other key must be declared in `languages`.
      - `button` BannerButton, required: The button inside a banner. Pressing it opens the creative's Destination.
        - `label` CreativeText, required: Plain text per language, keyed by locale code. Must hold `defaultLanguage`; every other key must be declared in `languages`. A visitor whose language is missing sees the default language.
      - `dismissible` boolean, required: Whether visitors can close the banner. A dismissed banner stays closed for the rest of the visit, in that browser tab; a new tab shows it again.
      - `accessibleName` CreativeText, required: Plain text per language, keyed by locale code. Must hold `defaultLanguage`; every other key must be declared in `languages`. A visitor whose language is missing sees the default language.
  - `styling` union
    - FeedbackButtonStyling: A feedback button's position and custom styles. The position applies whether or not custom styles are on.
      - `position` object, required
        - `desktop` FeedbackButtonPlacement, required: Where a feedback button sits: an edge of the page plus an offset along it, in percent, that places the button's centre. On the left and right edges the offset runs from the top; on the bottom edge, from the left. 50 centres the button on its edge. Near either end the button stops at the end of the edge instead, so it stays fully on screen: 0 puts its top (or left) end at the start of the edge and 100 its bottom (or right) end at the end.
          - `edge` 'left' | 'right' | 'bottom', required
          - `offset` integer, required
        - `phone` FeedbackButtonPlacement, required: Where a feedback button sits: an edge of the page plus an offset along it, in percent, that places the button's centre. On the left and right edges the offset runs from the top; on the bottom edge, from the left. 50 centres the button on its edge. Near either end the button stops at the end of the edge instead, so it stays fully on screen: 0 puts its top (or left) end at the start of the edge and 100 its bottom (or right) end at the end.
          - `edge` 'left' | 'right' | 'bottom', required
          - `offset` integer, required
      - `theme` FeedbackButtonTheme, required: The feedback button's custom styles. With `customStyles` off the button follows the workspace Look & Feel (the survey button) and the values below are kept but not applied. With it on, each value overrides the workspace one; `null` keeps the workspace value. A colour has a `light` value and an optional `dark` one for the visitor's dark appearance. Without a `dark` value: when the background or the text colour is set, both keep their light values in dark appearance so their contrast holds, a background set without a text colour gets readable text (`#0f172a` or `#ffffff`) in each appearance, and a border keeps its light value. Colours left to the workspace follow its dark palette when the visitor's appearance is dark. Sizes and the position apply in both appearances.
        - `customStyles` boolean, required: The "Add custom styles" switch.
        - `backgroundColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
          - `light` string, required
          - `dark` string, nullable
        - `textColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
          - `light` string, required
          - `dark` string, nullable
        - `borderColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
          - `light` string, required
          - `dark` string, nullable
        - `borderRadius` integer, nullable, required: Corner radius in px.
        - `fontWeight` 400 | 500 | 600 | 700 | null, nullable, required
        - `fontSize` CreativeFontSize, required: Font size in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
          - `desktop` integer, nullable, required
          - `phone` integer, nullable, required
        - `paddingX` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
          - `desktop` integer, nullable, required
          - `phone` integer, nullable, required
        - `paddingY` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
          - `desktop` integer, nullable, required
          - `phone` integer, nullable, required
        - `pageFont` boolean, nullable: Page font: `true` renders in the host page's font, `false` in the survey font, `null` (or absent) follows the workspace's Page font setting. Applies only with `customStyles` on.
        - `customCss` CustomCssInput: 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.
    - BannerStyling: A banner's position and custom styles. The position applies whether or not custom styles are on.
      - `position` object, required
        - `desktop` union, required: Where a banner sits and how it lays out. A bottom banner is always an overlay.
          - BannerTopPlacement: A banner at the top of the page, either `inPage` (in the page flow, scrolling away with it) or `overlay` (fixed and always visible).
            - `placement` 'top', required
            - `layout` 'inPage' | 'overlay', required
          - BannerBottomPlacement: A banner at the bottom of the page, which is always `overlay`.
            - `placement` 'bottom', required
            - `layout` 'overlay', required
        - `phone` union, required: Where a banner sits and how it lays out. A bottom banner is always an overlay.
          - BannerTopPlacement: A banner at the top of the page, either `inPage` (in the page flow, scrolling away with it) or `overlay` (fixed and always visible).
            - `placement` 'top', required
            - `layout` 'inPage' | 'overlay', required
          - BannerBottomPlacement: A banner at the bottom of the page, which is always `overlay`.
            - `placement` 'bottom', required
            - `layout` 'overlay', required
      - `theme` BannerTheme, required: The banner's custom styles. With `customStyles` off the banner follows the workspace Look & Feel (the survey card, with the survey button inside) and the values below are kept but not applied. With it on, each value overrides the workspace one; `null` keeps the workspace value. A colour has a `light` value and an optional `dark` one for the visitor's dark appearance. Without a `dark` value: when the background or the text colour is set, both keep their light values in dark appearance so their contrast holds, a background set without a text colour gets readable text (`#0f172a` or `#ffffff`) in each appearance, and a border keeps its light value. Colours left to the workspace follow its dark palette when the visitor's appearance is dark. Sizes and the position apply in both appearances. The banner's button always looks like the survey button.
        - `customStyles` boolean, required: The "Add custom styles" switch.
        - `backgroundColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
          - `light` string, required
          - `dark` string, nullable
        - `textColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
          - `light` string, required
          - `dark` string, nullable
        - `borderColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
          - `light` string, required
          - `dark` string, nullable
        - `fontWeight` 400 | 500 | 600 | 700 | null, nullable, required
        - `fontSize` CreativeFontSize, required: Font size in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
          - `desktop` integer, nullable, required
          - `phone` integer, nullable, required
        - `paddingX` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
          - `desktop` integer, nullable, required
          - `phone` integer, nullable, required
        - `paddingY` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
          - `desktop` integer, nullable, required
          - `phone` integer, nullable, required
        - `pageFont` boolean, nullable: Page font: `true` renders in the host page's font, `false` in the survey font, `null` (or absent) follows the workspace's Page font setting. Applies only with `customStyles` on.
        - `customCss` CustomCssInput: 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.
  - `destination` union: What the creative opens when pressed: a survey or a link. A creative opens exactly one Destination; many creatives may open the same survey.
    - CreativeSurveyDestinationInput: Open a survey. It must be in the creative's workspace, visible to the whole workspace (never Restricted, and no visibility change pending), and neither single-use nor PIN-protected; anything else answers **422**. Email verification is fine.
      - `type` 'survey', required
      - `surveyId` string, cuid2, required
    - CreativeLinkDestinationInput: Open an `http` or `https` link in a new tab.
      - `type` 'link', required
      - `url` string, web-url, required: An absolute `http://` or `https://` URL with a real host: `localhost`, an IP address, or a domain whose labels are letters, digits and hyphens and whose top-level domain has at least two letters (punycode allowed). `https://example.` and `https://example` are refused. `web-url` names this rule; `pattern` states the part of it a regular expression can.
  - `distribution` CreativeDistribution: When the creative shows. `showOn: pageView` shows it on every page view; `showOn: action` only when one of `triggers` fires, and publishing needs at least one. `triggers` must be empty with `pageView`. A creative never falls back to every page view. `conditions` (Show when) narrows either, and `displayPercentage` (Share of visitors) shows it to that share of visitors, each decided once and kept on every page; `null` means everyone.
    - `showOn` 'pageView' | 'action', required
    - `triggers` CreativeTrigger[], required: Each id must name an action class in the creative's workspace, at most once; an unknown or repeated id answers **422**.
      - `actionClassId` string, cuid2, required: Id of an action class in the creative's workspace.
    - `conditions` ShowConditionGroup, required: Show when: the page, visit and device conditions that must hold, joined by `connector`. The same conditions surveys use. At most 20 conditions in all, groups nested at most two levels deep, and 10 240 characters of JSON; a set beyond those answers **400**. Empty groups are dropped on write, and a top-level group left empty is stored as `null` (always show).
      - `id` string, cuid2, required
      - `connector` 'and' | 'or', required
      - `conditions` union[], required
        - union
          - ShowCondition: One condition on the page, the visit or the device: `leftOperand` `operator` `rightOperand`. The operand names its family in `leftOperand.type` (`page`: `currentUrl`, `pageReferrer`, `entryReferrer`, `queryParam`; `visit`: `pagesViewed`, `uniquePagesViewed`, `timeOnSite`, `visitedUrls`; `device`: `deviceType`, `browser`, `screenWidth`), and each operand accepts only its own operators. `queryParam` names its parameter in `leftOperand.meta.key`. `isSet` and `isNotSet` take no `rightOperand`; list operators (`containsAnyOf`, `containsNoneOf`, and the `currentUrl`-only `pathIsAnyOf`, `pathIsNoneOf`, which compare exact page paths) take a non-empty list; numeric operands take a number of 0 or more (`uniquePagesViewed` at most 200); `deviceType` takes `phone`, `tablet` or `desktop`. A condition that breaks one of these rules answers **400**. Matching is case-insensitive.
            - `id` string, cuid2, required
            - `leftOperand` object, required
              - …
            - `operator` 'equals' | 'doesNotEqual' | 'contains' | 'doesNotContain' | 'startsWith' | 'endsWith' | 'containsAnyOf' | 'containsNoneOf' | 'pathIsAnyOf' | 'pathIsNoneOf' | 'isGreaterThan' | 'isLessThan' | 'isGreaterThanOrEqual' | 'isLessThanOrEqual' | 'includes' | 'doesNotInclude' | 'isSet' | 'isNotSet', required
            - `rightOperand` object
              - …
          - ShowConditionSubgroup: A group of conditions inside the top-level group. Groups nest at most two levels deep.
            - `id` string, cuid2, required
            - `connector` 'and' | 'or', required
            - `conditions` ShowCondition[], required
              - …
    - `displayPercentage` number, nullable, required
  - `schedule` CreativeSchedule: When a published creative shows, to the minute. Before `startAt` it is `scheduled`; from `endAt` on it is `closed`. `null` leaves that side open. `endAt` must be after `startAt`, or the write answers **422**.
    - `startAt` string, date-time, nullable, required
    - `endAt` string, date-time, nullable, required
  - `expectedUpdatedAt` string, date-time: Optimistic-concurrency precondition: the creative's `updatedAt` from your last read. The change is applied only if the creative hasn't changed since; otherwise nothing is written and the request answers **409**. Omit it to apply the change to the creative as it is stored when the request runs.

## Response `200`

Creative updated

- object
  - `data` union, required: A creative: a page element the web SDK renders on the customer's site next to surveys, with its own content, look, display rules and schedule. `type` selects the `content` and `styling` shape: switch on it. The writable groups are `name`, `status`, `defaultLanguage` with `languages`, `autoSelectLanguage`, `content`, `styling`, `destination`, `distribution` and `schedule`; a `PATCH` replaces each group it sends as a whole. `displayStatus`, `displayStatusReason`, `warnings`, the timestamps, `creator` and `destination.opensAs` are read-only.
    - FeedbackButtonCreative: A feedback button.
      - `id` string, cuid2, required
      - `workspaceId` string, cuid2, required
      - `name` string, required: Internal name, shown to authors only. Never shown or announced to visitors.
      - `type` 'feedbackButton', required: The kind of creative, which fixes its `content` and `styling` shape. A `feedbackButton` is a tab on an edge of the page that always opens its Destination; a `banner` is a bar across the top or bottom of the page with a message and an optional button. Fixed at creation: it can never change.
      - `status` 'draft' | 'inProgress' | 'paused' | 'completed', required: The author's intent, and the only status a write sets: `draft` (never published), `inProgress` (published), `paused` (paused by its author) or `completed` (closed by its author). The same values as a survey's `status`. What visitors get is `displayStatus`, which the server derives from this value, `archivedAt`, the schedule and the Destination survey. Nothing writes `status` on its own: a schedule ending or a survey pausing changes `displayStatus` only.
      - `displayStatus` 'draft' | 'scheduled' | 'active' | 'paused' | 'closed' | 'archived', required: What the creative is doing now, derived in this order: `archived` when archived; `draft` and `closed` (status `completed`) when the author said so; `closed` when the schedule's `endAt` has passed; `paused` when the author paused it; `scheduled` before the schedule's `startAt`; `paused` when its Destination survey isn't active (not `inProgress`, or archived); otherwise `active`.
      - `displayStatusReason` 'surveyNotActive' | 'scheduleEnded' | 'destinationMissing' | 'actionMissing' | 'null', nullable, required: Why `displayStatus` differs from what `status` alone would give: `surveyNotActive` on a `paused` creative whose Destination survey isn't active ("Paused with its survey": it comes back by itself when the survey is active again), `scheduleEnded` on a `closed` creative whose `endAt` has passed, `destinationMissing` on a `paused` creative that needs a Destination (a feedback button, or a banner with a button) and has none, and `actionMissing` on a `paused` creative that shows on an action and has none. Sites never show a creative paused for either of the last two until it gets what it lacks (see `warnings`). `null` otherwise. New values may be added.
      - `createdAt` string, date-time, required
      - `updatedAt` string, date-time, required
      - `publishedAt` string, date-time, nullable, required: When the creative was first published; `null` while it has never been.
      - `archivedAt` string, date-time, nullable, required: When the creative was archived; `null` unless it is archived.
      - `creator` object, nullable, required: The user who created the creative, or `null` for one created with an API key.
        - `name` string, required
      - `defaultLanguage` string, required: Canonical locale code accepted by v3 survey APIs, for example `en-US`, `de-DE`, or `zh-Hans-CN`.
      - `languages` CreativeLanguage[], required: Every language the texts are written in, the default first.
        - `code` string, required: Canonical locale code accepted by v3 survey APIs, for example `en-US`, `de-DE`, or `zh-Hans-CN`.
        - `default` boolean, required: Whether this is `defaultLanguage`. Exactly one entry is the default.
        - `enabled` boolean, required: Whether visitors in this language see this translation. The default language is always enabled; a disabled or missing translation falls back to the default language.
      - `autoSelectLanguage` boolean, nullable, required: Show the texts in the visitor's browser language when the site sets none with `setLanguage` and it matches the default or an enabled language; otherwise the default language is used. `null` (never chosen) and `false` both mean off.
      - `destination` union, required: What the creative opens when pressed, with the read-only `opensAs`. A write takes `CreativeDestinationInput`, which carries neither `opensAs` nor `surveyName`.
        - CreativeSurveyDestination: The survey the creative opens.
          - `type` 'survey', required
          - `surveyId` string, cuid2, required
          - `surveyName` string, required
          - `opensAs` 'popup' | 'newTab', required: Follows the survey's type: an app survey opens as a popup in its own placement, a link survey in a new tab.
        - CreativeLinkDestination: The link the creative opens.
          - `type` 'link', required
          - `url` string, required
          - `opensAs` 'newTab', required: A link always opens in a new tab.
      - `distribution` CreativeDistribution, required: When the creative shows. `showOn: pageView` shows it on every page view; `showOn: action` only when one of `triggers` fires, and publishing needs at least one. `triggers` must be empty with `pageView`. A creative never falls back to every page view. `conditions` (Show when) narrows either, and `displayPercentage` (Share of visitors) shows it to that share of visitors, each decided once and kept on every page; `null` means everyone.
        - `showOn` 'pageView' | 'action', required
        - `triggers` CreativeTrigger[], required: Each id must name an action class in the creative's workspace, at most once; an unknown or repeated id answers **422**.
          - `actionClassId` string, cuid2, required: Id of an action class in the creative's workspace.
        - `conditions` ShowConditionGroup, required: Show when: the page, visit and device conditions that must hold, joined by `connector`. The same conditions surveys use. At most 20 conditions in all, groups nested at most two levels deep, and 10 240 characters of JSON; a set beyond those answers **400**. Empty groups are dropped on write, and a top-level group left empty is stored as `null` (always show).
          - `id` string, cuid2, required
          - `connector` 'and' | 'or', required
          - `conditions` union[], required
            - union
              - …
        - `displayPercentage` number, nullable, required
      - `schedule` CreativeSchedule, required: When a published creative shows, to the minute. Before `startAt` it is `scheduled`; from `endAt` on it is `closed`. `null` leaves that side open. `endAt` must be after `startAt`, or the write answers **422**.
        - `startAt` string, date-time, nullable, required
        - `endAt` string, date-time, nullable, required
      - `warnings` CreativeWarning[], required
        - `code` 'destinationMissing' | 'destinationNotAllowed' | 'actionMissing', required
        - `message` string, required: The same warning in English, for people.
      - `content` FeedbackButtonContent, required: What a feedback button shows.
        - `label` CreativeText, required: Plain text per language, keyed by locale code. Must hold `defaultLanguage`; every other key must be declared in `languages`. A visitor whose language is missing sees the default language.
        - `icon` 'messageSquare' | 'messageCircle' | 'megaphone' | 'sparkles' | 'null', nullable, required: An icon before the label, or `null` for none.
      - `styling` FeedbackButtonStyling, required: A feedback button's position and custom styles. The position applies whether or not custom styles are on.
        - `position` object, required
          - `desktop` FeedbackButtonPlacement, required: Where a feedback button sits: an edge of the page plus an offset along it, in percent, that places the button's centre. On the left and right edges the offset runs from the top; on the bottom edge, from the left. 50 centres the button on its edge. Near either end the button stops at the end of the edge instead, so it stays fully on screen: 0 puts its top (or left) end at the start of the edge and 100 its bottom (or right) end at the end.
            - `edge` 'left' | 'right' | 'bottom', required
            - `offset` integer, required
          - `phone` FeedbackButtonPlacement, required: Where a feedback button sits: an edge of the page plus an offset along it, in percent, that places the button's centre. On the left and right edges the offset runs from the top; on the bottom edge, from the left. 50 centres the button on its edge. Near either end the button stops at the end of the edge instead, so it stays fully on screen: 0 puts its top (or left) end at the start of the edge and 100 its bottom (or right) end at the end.
            - `edge` 'left' | 'right' | 'bottom', required
            - `offset` integer, required
        - `theme` FeedbackButtonTheme, required: The feedback button's custom styles. With `customStyles` off the button follows the workspace Look & Feel (the survey button) and the values below are kept but not applied. With it on, each value overrides the workspace one; `null` keeps the workspace value. A colour has a `light` value and an optional `dark` one for the visitor's dark appearance. Without a `dark` value: when the background or the text colour is set, both keep their light values in dark appearance so their contrast holds, a background set without a text colour gets readable text (`#0f172a` or `#ffffff`) in each appearance, and a border keeps its light value. Colours left to the workspace follow its dark palette when the visitor's appearance is dark. Sizes and the position apply in both appearances.
          - `customStyles` boolean, required: The "Add custom styles" switch.
          - `backgroundColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
            - `light` string, required
            - `dark` string, nullable
          - `textColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
            - `light` string, required
            - `dark` string, nullable
          - `borderColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
            - `light` string, required
            - `dark` string, nullable
          - `borderRadius` integer, nullable, required: Corner radius in px.
          - `fontWeight` 400 | 500 | 600 | 700 | null, nullable, required
          - `fontSize` CreativeFontSize, required: Font size in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
            - `desktop` integer, nullable, required
            - `phone` integer, nullable, required
          - `paddingX` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
            - `desktop` integer, nullable, required
            - `phone` integer, nullable, required
          - `paddingY` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
            - `desktop` integer, nullable, required
            - `phone` integer, nullable, required
          - `pageFont` boolean, nullable: Page font: `true` renders in the host page's font, `false` in the survey font, `null` (or absent) follows the workspace's Page font setting. Applies only with `customStyles` on.
          - `customCss` CustomCssInput: 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.
    - BannerCreative: A banner.
      - `id` string, cuid2, required
      - `workspaceId` string, cuid2, required
      - `name` string, required: Internal name, shown to authors only. Never shown or announced to visitors.
      - `type` 'banner', required: The kind of creative, which fixes its `content` and `styling` shape. A `feedbackButton` is a tab on an edge of the page that always opens its Destination; a `banner` is a bar across the top or bottom of the page with a message and an optional button. Fixed at creation: it can never change.
      - `status` 'draft' | 'inProgress' | 'paused' | 'completed', required: The author's intent, and the only status a write sets: `draft` (never published), `inProgress` (published), `paused` (paused by its author) or `completed` (closed by its author). The same values as a survey's `status`. What visitors get is `displayStatus`, which the server derives from this value, `archivedAt`, the schedule and the Destination survey. Nothing writes `status` on its own: a schedule ending or a survey pausing changes `displayStatus` only.
      - `displayStatus` 'draft' | 'scheduled' | 'active' | 'paused' | 'closed' | 'archived', required: What the creative is doing now, derived in this order: `archived` when archived; `draft` and `closed` (status `completed`) when the author said so; `closed` when the schedule's `endAt` has passed; `paused` when the author paused it; `scheduled` before the schedule's `startAt`; `paused` when its Destination survey isn't active (not `inProgress`, or archived); otherwise `active`.
      - `displayStatusReason` 'surveyNotActive' | 'scheduleEnded' | 'destinationMissing' | 'actionMissing' | 'null', nullable, required: Why `displayStatus` differs from what `status` alone would give: `surveyNotActive` on a `paused` creative whose Destination survey isn't active ("Paused with its survey": it comes back by itself when the survey is active again), `scheduleEnded` on a `closed` creative whose `endAt` has passed, `destinationMissing` on a `paused` creative that needs a Destination (a feedback button, or a banner with a button) and has none, and `actionMissing` on a `paused` creative that shows on an action and has none. Sites never show a creative paused for either of the last two until it gets what it lacks (see `warnings`). `null` otherwise. New values may be added.
      - `createdAt` string, date-time, required
      - `updatedAt` string, date-time, required
      - `publishedAt` string, date-time, nullable, required: When the creative was first published; `null` while it has never been.
      - `archivedAt` string, date-time, nullable, required: When the creative was archived; `null` unless it is archived.
      - `creator` object, nullable, required: The user who created the creative, or `null` for one created with an API key.
        - `name` string, required
      - `defaultLanguage` string, required: Canonical locale code accepted by v3 survey APIs, for example `en-US`, `de-DE`, or `zh-Hans-CN`.
      - `languages` CreativeLanguage[], required: Every language the texts are written in, the default first.
        - `code` string, required: Canonical locale code accepted by v3 survey APIs, for example `en-US`, `de-DE`, or `zh-Hans-CN`.
        - `default` boolean, required: Whether this is `defaultLanguage`. Exactly one entry is the default.
        - `enabled` boolean, required: Whether visitors in this language see this translation. The default language is always enabled; a disabled or missing translation falls back to the default language.
      - `autoSelectLanguage` boolean, nullable, required: Show the texts in the visitor's browser language when the site sets none with `setLanguage` and it matches the default or an enabled language; otherwise the default language is used. `null` (never chosen) and `false` both mean off.
      - `destination` union, required: What the creative opens when pressed, with the read-only `opensAs`. A write takes `CreativeDestinationInput`, which carries neither `opensAs` nor `surveyName`.
        - CreativeSurveyDestination: The survey the creative opens.
          - `type` 'survey', required
          - `surveyId` string, cuid2, required
          - `surveyName` string, required
          - `opensAs` 'popup' | 'newTab', required: Follows the survey's type: an app survey opens as a popup in its own placement, a link survey in a new tab.
        - CreativeLinkDestination: The link the creative opens.
          - `type` 'link', required
          - `url` string, required
          - `opensAs` 'newTab', required: A link always opens in a new tab.
      - `distribution` CreativeDistribution, required: When the creative shows. `showOn: pageView` shows it on every page view; `showOn: action` only when one of `triggers` fires, and publishing needs at least one. `triggers` must be empty with `pageView`. A creative never falls back to every page view. `conditions` (Show when) narrows either, and `displayPercentage` (Share of visitors) shows it to that share of visitors, each decided once and kept on every page; `null` means everyone.
        - `showOn` 'pageView' | 'action', required
        - `triggers` CreativeTrigger[], required: Each id must name an action class in the creative's workspace, at most once; an unknown or repeated id answers **422**.
          - `actionClassId` string, cuid2, required: Id of an action class in the creative's workspace.
        - `conditions` ShowConditionGroup, required: Show when: the page, visit and device conditions that must hold, joined by `connector`. The same conditions surveys use. At most 20 conditions in all, groups nested at most two levels deep, and 10 240 characters of JSON; a set beyond those answers **400**. Empty groups are dropped on write, and a top-level group left empty is stored as `null` (always show).
          - `id` string, cuid2, required
          - `connector` 'and' | 'or', required
          - `conditions` union[], required
            - union
              - …
        - `displayPercentage` number, nullable, required
      - `schedule` CreativeSchedule, required: When a published creative shows, to the minute. Before `startAt` it is `scheduled`; from `endAt` on it is `closed`. `null` leaves that side open. `endAt` must be after `startAt`, or the write answers **422**.
        - `startAt` string, date-time, nullable, required
        - `endAt` string, date-time, nullable, required
      - `warnings` CreativeWarning[], required
        - `code` 'destinationMissing' | 'destinationNotAllowed' | 'actionMissing', required
        - `message` string, required: The same warning in English, for people.
      - `content` BannerContent, required: What a banner shows.
        - `message` CreativeRichText, required: Formatted text per language, keyed by locale code: each value is the text as a list of runs. Must hold `defaultLanguage`; every other key must be declared in `languages`.
        - `button` BannerButton, required: The button inside a banner. Pressing it opens the creative's Destination.
          - `label` CreativeText, required: Plain text per language, keyed by locale code. Must hold `defaultLanguage`; every other key must be declared in `languages`. A visitor whose language is missing sees the default language.
        - `dismissible` boolean, required: Whether visitors can close the banner. A dismissed banner stays closed for the rest of the visit, in that browser tab; a new tab shows it again.
        - `accessibleName` CreativeText, required: Plain text per language, keyed by locale code. Must hold `defaultLanguage`; every other key must be declared in `languages`. A visitor whose language is missing sees the default language.
      - `styling` BannerStyling, required: A banner's position and custom styles. The position applies whether or not custom styles are on.
        - `position` object, required
          - `desktop` union, required: Where a banner sits and how it lays out. A bottom banner is always an overlay.
            - BannerTopPlacement: A banner at the top of the page, either `inPage` (in the page flow, scrolling away with it) or `overlay` (fixed and always visible).
              - …
            - BannerBottomPlacement: A banner at the bottom of the page, which is always `overlay`.
              - …
          - `phone` union, required: Where a banner sits and how it lays out. A bottom banner is always an overlay.
            - BannerTopPlacement: A banner at the top of the page, either `inPage` (in the page flow, scrolling away with it) or `overlay` (fixed and always visible).
              - …
            - BannerBottomPlacement: A banner at the bottom of the page, which is always `overlay`.
              - …
        - `theme` BannerTheme, required: The banner's custom styles. With `customStyles` off the banner follows the workspace Look & Feel (the survey card, with the survey button inside) and the values below are kept but not applied. With it on, each value overrides the workspace one; `null` keeps the workspace value. A colour has a `light` value and an optional `dark` one for the visitor's dark appearance. Without a `dark` value: when the background or the text colour is set, both keep their light values in dark appearance so their contrast holds, a background set without a text colour gets readable text (`#0f172a` or `#ffffff`) in each appearance, and a border keeps its light value. Colours left to the workspace follow its dark palette when the visitor's appearance is dark. Sizes and the position apply in both appearances. The banner's button always looks like the survey button.
          - `customStyles` boolean, required: The "Add custom styles" switch.
          - `backgroundColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
            - `light` string, required
            - `dark` string, nullable
          - `textColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
            - `light` string, required
            - `dark` string, nullable
          - `borderColor` CreativeColor, required: A custom colour per appearance, `#rrggbb`, as the survey styling stores its colours. `light` applies in light appearance. `dark` applies when the visitor's appearance is dark; `null` (or absent) derives it as the theme describes.
            - `light` string, required
            - `dark` string, nullable
          - `fontWeight` 400 | 500 | 600 | 700 | null, nullable, required
          - `fontSize` CreativeFontSize, required: Font size in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
            - `desktop` integer, nullable, required
            - `phone` integer, nullable, required
          - `paddingX` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
            - `desktop` integer, nullable, required
            - `phone` integer, nullable, required
          - `paddingY` CreativePadding, required: Padding in px, per device. `phone` applies below 768 px viewport width; `null` there uses the `desktop` value, and `null` on `desktop` uses the workspace Look & Feel.
            - `desktop` integer, nullable, required
            - `phone` integer, nullable, required
          - `pageFont` boolean, nullable: Page font: `true` renders in the host page's font, `false` in the survey font, `null` (or absent) follows the workspace's Page font setting. Applies only with `customStyles` on.
          - `customCss` CustomCssInput: 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.

## 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, one of two codes. `forbidden`: the caller lacks the workspace access the operation needs, or the creative does not exist (404 is not used, so creative ids cannot be probed for existence). `creatives_not_entitled`: Creatives is not available on this instance (Formbricks Cloud, or a self-hosted license that does not include it). It is checked only after the caller's own access, so it says nothing about a workspace the caller cannot see. A workspace that still has creatives is in wind-down: listing, reading, stats, a PATCH that sets nothing but `status` to `paused` or `completed`, pausing a survey's creatives (`POST /api/v3/creatives/pause`), and DELETE keep working, and everything else answers this. A workspace without creatives answers it on every operation.
- `409`: Conflict — `expectedUpdatedAt` did not match the stored creative, so it changed since your read. Nothing was written. `details` carries `expectedUpdatedAt` and the live `currentUpdatedAt`, so a client can re-read and retry without guessing.
- `422`: Unprocessable Content — semantic validation failed or the requested lifecycle transition is invalid.
- `429`: Rate limit exceeded.
- `500`: Internal Server Error.

## Changes

- **2026-11-02** `03d5b9b896e2`: 3 info
  - added the new optional request property `autoSelectLanguage`
  - added the required property `data/oneOf[#/components/schemas/BannerCreative]/allOf[#/components/schemas/CreativeResourceBase]/autoSelectLanguage` to the response with the `200` status
  - added the required property `data/oneOf[#/components/schemas/FeedbackButtonCreative]/allOf[#/components/schemas/CreativeResourceBase]/autoSelectLanguage` to the response with the `200` status
- **2026-10-28** `84820a01e550`: 21 warning
  - added the new `chart_in_use` enum value to the `code` response property for the response status `400`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `401`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `403`
  - added the new `chart_in_use` enum value to the `code` response property for the response status `409`
  - …17 more
- **2026-10-27** `aad5dc1d8236`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/formbricks/apis/formbricks-api-v3/changes/api/v3/creatives/:creativeId/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)
