{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/growomat-com/json-schema/growomat-com-ad-update-schema.json",
  "title": "AdUpdate",
  "description": "Partial update of an ad: any subset of `AdCreate` fields. Omitted fields keep their values.",
  "x-generated": "2026-11-10",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/_original/growomat-com-api-openapi.json#/components/schemas/AdUpdate",
  "type": "object",
  "properties": {
    "angleId": {
      "type": "string",
      "minLength": 1,
      "description": "The angle (claim) this ad argues. Results are reported per angle."
    },
    "conceptId": {
      "type": "string",
      "minLength": 1,
      "description": "The concept (way of making the claim) this ad is a rendition of."
    },
    "angleProvenance": {
      "type": "string",
      "enum": [
        "generated",
        "user",
        "inferred"
      ],
      "description": "Where the angle stamp came from: written by Growomat, set by you, or inferred from the copy. Defaults to `user` when you set `angleId` yourself."
    },
    "competitorSimilarityAck": {
      "type": "boolean",
      "description": "Save manual copy that the competitor similarity check flagged. Only honoured when the refusal said `overridable: true`; the decision is recorded on the ad."
    },
    "_native": {
      "$ref": "#/$defs/NativeExtensions"
    },
    "adGroupId": {
      "type": "string",
      "minLength": 1,
      "description": "The ad group this ad belongs to."
    },
    "campaignId": {
      "type": "string",
      "minLength": 1,
      "description": "The campaign of that ad group."
    },
    "type": {
      "type": "string",
      "enum": [
        "RESPONSIVE_SEARCH_AD",
        "RESPONSIVE_DISPLAY_AD",
        "PERFORMANCE_MAX_ASSET_GROUP",
        "VIDEO_AD",
        "REDDIT_TEXT_POST",
        "REDDIT_IMAGE_POST",
        "REDDIT_VIDEO_POST",
        "REDDIT_CAROUSEL_POST",
        "META_LINK_AD",
        "META_IMAGE_AD",
        "META_VIDEO_AD",
        "META_CAROUSEL_AD",
        "OPENAI_CHAT_CARD",
        "OPENAI_PRODUCT_AD_TEMPLATE",
        "LINKEDIN_SINGLE_IMAGE",
        "LINKEDIN_TEXT_AD",
        "LINKEDIN_VIDEO",
        "LINKEDIN_CAROUSEL",
        "LINKEDIN_DOCUMENT"
      ],
      "default": "RESPONSIVE_SEARCH_AD",
      "description": "Ad format. Defaults from the campaign type per platform; ads imported from a platform record the format that actually serves."
    },
    "creative": {
      "$ref": "#/$defs/AdCreative"
    },
    "headlinePart1": {
      "type": "string",
      "description": "First headline. Up to 30 characters on search platforms."
    },
    "headlinePart2": {
      "type": "string",
      "description": "Second headline. Up to 30 characters on search platforms."
    },
    "headlinePart3": {
      "type": "string",
      "description": "Third headline, optional. Up to 30 characters on search platforms."
    },
    "description": {
      "type": "string",
      "description": "First description line. Up to 90 characters on search platforms."
    },
    "description2": {
      "type": "string",
      "description": "Second description line, optional. Up to 90 characters on search platforms."
    },
    "finalUrl": {
      "type": "string",
      "format": "uri",
      "description": "The landing page."
    },
    "path1": {
      "type": "string",
      "maxLength": 15,
      "description": "First display-path segment shown after the domain in the ad."
    },
    "path2": {
      "type": "string",
      "maxLength": 15,
      "description": "Second display-path segment."
    },
    "status": {
      "type": "string",
      "enum": [
        "ENABLED",
        "PAUSED",
        "REMOVED"
      ],
      "default": "ENABLED",
      "description": "A paused ad is not shown."
    },
    "sitelinks": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Sitelink"
      },
      "description": "Extra links shown under the ad."
    },
    "callouts": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Short phrases shown under the ad, for example \"Free shipping\"."
    },
    "structuredSnippets": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/StructuredSnippet"
      },
      "description": "Labelled lists shown under the ad."
    },
    "customLabels": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Free-form labels for your own grouping and reporting."
    },
    "trackingUrlTemplate": {
      "type": "string",
      "description": "Tracking template for this ad; overrides the ad group's and the campaign's."
    },
    "finalUrlSuffix": {
      "type": "string",
      "description": "Query string appended to the final URL; overrides the ad group's and the campaign's."
    },
    "urlCustomParameters": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      },
      "description": "Custom `{_name}` parameters available to tracking templates."
    }
  },
  "$defs": {
    "AdCreative": {
      "type": "object",
      "description": "Instructions for platforms whose ad is a separate creative object, such as a promoted post. Platforms that build the ad from the headline and description fields ignore it.",
      "properties": {
        "format": {
          "type": "string",
          "description": "Ad format hint. Normally derived from the campaign type."
        },
        "mediaAssetIds": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Assets to build the creative from."
        },
        "body": {
          "type": "string",
          "description": "Post body. Defaults to the ad's remaining copy."
        },
        "imageUrl": {
          "type": "string",
          "format": "uri",
          "description": "Image to use, by URL."
        },
        "videoUrl": {
          "type": "string",
          "format": "uri",
          "description": "Video to use, by URL."
        },
        "thumbnailUrl": {
          "type": "string",
          "format": "uri",
          "description": "Still shown before a video plays. Required by platforms that mandate one."
        }
      }
    },
    "NativeExtensions": {
      "type": "object",
      "description": "Settings that exist on one platform only, keyed by platform id (for example `google-ads`). Each value is a free-form object that is stored and returned exactly as sent; keys Growomat does not know are kept. Absent by default.\n\nKeys read by platforms whose ad is a post (on the ad, with the campaign as fallback): `postType` (`TEXT` or `IMAGE`), `postTitle`, `postBody`, `callToAction`, `imageUrl`, `videoUrl`, `videoThumbnailUrl`, `carouselCards` (`[{ imageUrl, destinationUrl }]`), `communities`, `interests`.\n\nDelivery keys read on the campaign: `objective`, `goalType`, `startTime`, `endTime`, `optimizationGoal`, `conversionPixelId`.",
      "additionalProperties": {
        "type": "object",
        "additionalProperties": true
      },
      "properties": {
        "openai-ads": {
          "type": "object",
          "description": "ChatGPT Ads settings. Read on the campaign: `budgetKind`, `biddingType`, `startTime`, `endTime`, `platforms`, `customAudienceIds`, `excludedCustomAudienceIds`, `conversionEventSettingId`, `queryStringTemplate`, `description`, `imageUrl`, `postTitle`, `postBody`; on the ad group: `strategy`, `maxBid`, `cpmBid`, `description`; on the ad: `imageUrl`, `postTitle`, `postBody`, `imageCrop`, `price`. Unknown keys are kept.",
          "properties": {
            "budgetKind": {
              "type": "string",
              "enum": [
                "DAILY",
                "LIFETIME"
              ],
              "default": "DAILY",
              "description": "On the campaign: `LIFETIME` makes `budget` the total for the campaign's whole run instead of a day's. The lifetime minimum is 1 unit of the account currency; the daily minimum is per currency (EUR 15). One-way: once pushed, a lifetime budget can never become daily. Maximize-results strategies need `DAILY`."
            },
            "biddingType": {
              "type": "string",
              "enum": [
                "CLICKS",
                "IMPRESSIONS",
                "CONVERSIONS"
              ],
              "description": "On the campaign: What the campaign buys. Set once, at the first push. Defaults from `biddingStrategy` (clicks for a CPC strategy, conversions for a CPA strategy); `IMPRESSIONS` is reachable only here."
            },
            "startTime": {
              "type": "string",
              "format": "date-time",
              "description": "On the campaign: When delivery starts. Falls back to `startDate`; absent means as soon as it is enabled."
            },
            "endTime": {
              "type": "string",
              "format": "date-time",
              "description": "On the campaign: When delivery ends. Falls back to `endDate` (end of that day, UTC)."
            },
            "platforms": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "ios_app",
                  "android_app",
                  "web",
                  "desktop_web",
                  "ios_web",
                  "android_web"
                ]
              },
              "description": "On the campaign: The ChatGPT surfaces to deliver on. Absent means all. `web` covers every web surface, so it is never combined with the granular web values."
            },
            "customAudienceIds": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "On the campaign: Custom audiences to reach."
            },
            "excludedCustomAudienceIds": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "On the campaign: Custom audiences to exclude."
            },
            "conversionEventSettingId": {
              "type": "string",
              "description": "On the campaign: The conversion event setting a conversions campaign optimises for (required when `biddingType` is `CONVERSIONS`; fixed after the first push). Defaults to the connection's."
            },
            "queryStringTemplate": {
              "type": "string",
              "description": "On the campaign: Query parameters appended to every destination URL, for example `utm_source=chatgpt&utm_medium=cpc`. The platform's own click id is added by the platform and is dropped here."
            },
            "description": {
              "type": "string",
              "description": "On the campaign: An internal note on the campaign. On the ad group: An internal note on the ad group."
            },
            "imageUrl": {
              "type": "string",
              "format": "uri",
              "description": "On the campaign: One image for every chat card in the campaign that has none of its own. On the ad: The chat card's image (at least 640 × 640). Wins over an image bound through *Ad assets*; `creative.imageUrl` wins over this."
            },
            "postTitle": {
              "type": "string",
              "maxLength": 50,
              "description": "On the campaign: One title for every chat card that sets none of its own. On the ad: The card's title as it will read (3–50 characters). Defaults to the first headline."
            },
            "postBody": {
              "type": "string",
              "maxLength": 100,
              "description": "On the campaign: One body for every chat card that sets none of its own. On the ad: The card's body as it will read (up to 100 characters). Defaults to the first description."
            },
            "strategy": {
              "type": "string",
              "enum": [
                "fixed_bid",
                "maximize_clicks",
                "maximize_conversions"
              ],
              "description": "On the ad group: How the ad group bids. `fixed_bid` bids `cpcBid` (or `maxBid` / `cpmBid`); a `maximize_*` strategy needs a daily budget. Must suit the campaign's `biddingType`."
            },
            "maxBid": {
              "type": "number",
              "minimum": 0,
              "description": "On the ad group: The fixed bid in the account currency, when `cpcBid` does not apply (a CPA bid on a conversions campaign)."
            },
            "cpmBid": {
              "type": "number",
              "minimum": 0,
              "description": "On the ad group: For an `IMPRESSIONS` campaign: the bid per thousand impressions, in the account currency."
            },
            "imageCrop": {
              "type": "object",
              "required": [
                "x",
                "y",
                "width",
                "height"
              ],
              "properties": {
                "x": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                },
                "y": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                },
                "width": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                },
                "height": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              },
              "description": "On the ad: A square crop of the image, each value a fraction (0–1) of the source."
            },
            "price": {
              "type": "string",
              "maxLength": 100,
              "description": "On the ad: A price shown on the card, as written (for example `From €49`)."
            }
          },
          "additionalProperties": true
        }
      }
    },
    "Sitelink": {
      "type": "object",
      "description": "An extra link shown under the ad.",
      "properties": {
        "text": {
          "type": "string",
          "description": "Link text."
        },
        "url": {
          "type": "string",
          "description": "Where the link goes."
        },
        "description1": {
          "type": "string",
          "description": "First description line."
        },
        "description2": {
          "type": "string",
          "description": "Second description line."
        },
        "trackingUrlTemplate": {
          "type": "string",
          "description": "Tracking template for this link."
        },
        "urlCustomParameters": {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          },
          "description": "Custom `{_name}` parameters for the tracking template."
        }
      }
    },
    "StructuredSnippet": {
      "type": "object",
      "required": [
        "header",
        "values"
      ],
      "description": "A labelled list shown under the ad, for example \"Services: Repairs, Installation\".",
      "properties": {
        "header": {
          "type": "string",
          "description": "The list label, from the platform's fixed set (for example `Services`, `Brands`)."
        },
        "values": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "The list entries."
        }
      }
    }
  }
}