---
title: "Validate Campaign"
method: POST
path: "/api/v1/google-ad-manager/campaigns/validate"
tags: ["googleAdCampaign"]
---

# Validate Campaign

`POST /api/v1/google-ad-manager/campaigns/validate`

## Request

- Base URL: `https://api.brandbooster.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.brandbooster.ai/api/v1/google-ad-manager/campaigns/validate`
- Auth: none declared

Dry-run the payload and return the blocking issues, without creating anything.

## Request body

- CampaignRequest
  - `client_id` string, required
  - `email` string, email, required
  - `objective` 'SALES' | 'LEADS' | 'WEBSITE_TRAFFIC' | 'APP_PROMOTION' | 'AWARENESS_AND_CONSIDERATION' | 'LOCAL_STORE_VISITS' | 'WITHOUT_GOAL': Campaign objective enum - maps to Google Ads campaign types and strategies
  - `goals` GoalConfiguration
    - `goal_types` GoalType[], required
    - `website_visits` WebsiteVisitsGoal
      - `url` string, required
      - `final_mobile_urls` string[], nullable
    - `phone_calls` PhoneCallsGoal
      - `phone_number` string, required
      - `country_code` string, required
    - `store_visits` StoreVisitsGoal
      - `placeholder` string, nullable
  - `campaign_type` string, nullable
  - `campaign` CampaignModel, required
    - `name` string, required
    - `status` 'PAUSED' | 'ENABLED' | 'REMOVED', required: Campaign status enum
    - `advertising_channel_type` 'SEARCH' | 'DISPLAY' | 'VIDEO' | 'SHOPPING' | 'PERFORMANCE_MAX' | 'DEMAND_GEN' | 'MULTI_CHANNEL' | 'LOCAL' | 'SMART' | 'HOTEL', required: Advertising channel type enum
    - `start_date` string, nullable
    - `end_date` string, nullable
    - `budget` CampaignBudgetModel, required
      - `name` string, nullable
      - `amount_micros` unknown
      - `total_amount_micros` integer, nullable
      - `period` 'DAILY' | 'CUSTOM_PERIOD': Budget period - DAILY uses amount_micros, CUSTOM_PERIOD uses total_amount_micros
      - `delivery_method` 'STANDARD' | 'ACCELERATED': Campaign budget delivery method enum
    - `bidding_strategy` BiddingStrategyModel, required
      - `type` 'MANUAL_CPC' | 'MAXIMIZE_CLICKS' | 'MAXIMIZE_CONVERSIONS' | 'MAXIMIZE_CONVERSION_VALUE' | 'TARGET_ROAS' | 'TARGET_CPA' | 'TARGET_IMPRESSION_SHARE' | 'TARGET_CPV' | 'MANUAL_CPV' | 'TARGET_CPM' | 'MANUAL_CPM', required: Bidding strategy type enum
      - `bidding_focus` 'CONVERSION' | 'CONVERSION_VALUE' | 'CLICKS' | 'IMPRESSION_VALUE' | 'IMPRESSIONS': Bidding focus - what to optimize for
      - `cpc_bid_ceiling_micros` integer, nullable
      - `target_cpa_micros` integer, nullable
      - `target_roas` number, nullable
      - `enhanced_cpc_enabled` boolean, nullable
    - `network_settings` NetworkSettingsModel
      - `target_google_search` boolean, required
      - `target_search_network` boolean, required
      - `target_content_network` boolean, required
      - `target_partner_search_network` boolean, required
    - `customer_acquisition` CustomerAcquisitionModel
      - `optimization_mode` 'TARGET_ALL_EQUALLY' | 'BID_HIGHER_FOR_NEW_CUSTOMER' | 'TARGET_NEW_CUSTOMER': Customer acquisition optimization mode enum
      - `new_customer_value` number, nullable
    - `eu_political_ads` boolean, nullable
    - `url_custom_parameters` UrlCustomParameter[], nullable
      - `key` string, required
      - `value` string, required
    - `campaign_goal` CampaignGoalConfiguration
      - `goal_type` 'CONVERSION' | 'CLICKS' | 'YOUTUBE_ENGAGEMENT': Campaign goal type for Demand Gen campaigns - what to optimize for
      - `conversion_goals` string[], nullable
      - `target_cpa_micros` integer, nullable
    - `brand_guidelines` BrandGuidelinesModel
      - `enabled` boolean, nullable
      - `main_color` string, nullable
      - `accent_color` string, nullable
      - `predefined_font_family` string, nullable
      - `font` string, nullable
    - `languages` string[], nullable
    - `ad_rotation_mode` 'OPTIMIZE' | 'ROTATE_FOREVER': Ad rotation mode - set on the ad group, not the campaign
    - `ad_schedule` union
      - AdScheduleSettings
        - `all_day` boolean, nullable
        - `day_of_week` 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY': Day of week for ad schedule criteria
        - `start_hour` integer, nullable
        - `start_minute` union
          - integer
          - 'ZERO' | 'FIFTEEN' | 'THIRTY' | 'FORTY_FIVE': Ad schedule minute - Google only accepts quarter-hour marks
        - `end_hour` integer, nullable
        - `end_minute` union
          - integer
          - 'ZERO' | 'FIFTEEN' | 'THIRTY' | 'FORTY_FIVE': Ad schedule minute - Google only accepts quarter-hour marks
      - AdScheduleSettings[]
        - `all_day` boolean, nullable
        - `day_of_week` 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY': Day of week for ad schedule criteria
        - `start_hour` integer, nullable
        - `start_minute` union
          - integer
          - 'ZERO' | 'FIFTEEN' | 'THIRTY' | 'FORTY_FIVE': Ad schedule minute - Google only accepts quarter-hour marks
        - `end_hour` integer, nullable
        - `end_minute` union
          - integer
          - 'ZERO' | 'FIFTEEN' | 'THIRTY' | 'FORTY_FIVE': Ad schedule minute - Google only accepts quarter-hour marks
    - `conversions` ConversionsSettings
      - `include_view_through_conversions` boolean, nullable
    - `shopping_setting` ShoppingSettingModel
      - `merchant_id` integer, required
      - `feed_label` string, nullable
      - `sales_country` string, nullable
      - `campaign_priority` integer, nullable
      - `enable_local` boolean, nullable
      - `listing_type` string, nullable
    - `ai_max` AiMaxSettingsModel
      - `enabled` boolean
      - `text_customization` boolean, nullable
      - `final_url_expansion` boolean, nullable
      - `brand_inclusions` AiMaxBrandsModel
        - `name` string, nullable
        - `brand_entity_ids` string[], required
      - `brand_exclusions` AiMaxBrandsModel
        - `name` string, nullable
        - `brand_entity_ids` string[], required
      - `url_exclusions` string[], nullable
    - `tracking_url_template` string, nullable
    - `final_url_suffix` string, nullable
    - `page_feed` PageFeedModel
      - `page_urls` string[], required
      - `domain_name` string, required
      - `name` string, nullable
      - `language_code` string
      - `use_supplied_urls_only` boolean, nullable
    - `asset_automations` object, nullable
    - `append_timestamp` boolean
  - `targeting` TargetingModel
    - `geo_targets` GeoTargetsModel, required
      - `locations` GeoLocationModel[], required
        - `geo_target_constant` string, required
        - `name` string, nullable
      - `excluded_locations` GeoLocationModel[], nullable
        - `geo_target_constant` string, required
        - `name` string, nullable
      - `proximities` ProximityModel[], nullable
        - `radius` number, required
        - `radius_units` 'KILOMETERS' | 'MILES': Radius units for proximity (radius) location targeting
        - `city_name` string, nullable
        - `country_code` string, nullable
        - `postal_code` string, nullable
        - `province_code` string, nullable
        - `street_address` string, nullable
      - `geo_target_type` 'PRESENCE_OR_INTEREST' | 'PRESENCE': Geo target type - how people are matched for targeted locations
      - `negative_geo_target_type` 'PRESENCE_OR_INTEREST' | 'PRESENCE': Geo target type - how people are matched for targeted locations
    - `audience_segments` AudienceSegmentsModel: Campaign-level audience segments, one list per criterion kind. user_lists was the only field here and it was required, which made Google's own in-market and affinity categories impossible to send even though the applier has always written them (campaign_common.AUDIENCE_SEGMENT_CRITERIA) and search_google_ads_audiences hands back their ids under exactly these keys. Every block is optional now, and at least one has to carry ids so an empty block is still a refusal rather than a campaign targeting nobody. Demand Gen takes the same block but applies it per ad group, as one Google Ads Audience built from user_lists, user_interests and custom_audiences. An Audience has no slot for a combined audience or a bid adjustment, and Demand Gen has no observation mode, so those three are refused there rather than dropped.
      - `user_lists` string[], nullable
      - `user_interests` string[], nullable
      - `custom_audiences` string[], nullable
      - `combined_audiences` string[], nullable
      - `bid_modifier` number, nullable
      - `targeting_mode` 'OBSERVATION' | 'TARGETING': How audience segments are used - mirrors Google's TargetRestriction.bid_only
    - `exclusions` ExclusionsModel: Campaign-level exclusions (Performance Max wizard: brand / demographic / your-data).
      - `brands` string[], nullable
      - `brand_list_name` string, nullable
      - `age_ranges` string[], nullable
      - `genders` string[], nullable
      - `parental_statuses` string[], nullable
      - `income_ranges` string[], nullable
      - `user_lists` string[], nullable
      - `devices` string[], nullable
  - `ad_groups` AdGroupModel[], nullable
    - `name` string, required
    - `status` 'PAUSED' | 'ENABLED' | 'REMOVED', required: Campaign status enum
    - `type` string
    - `cpc_bid_micros` integer, nullable
    - `disable_search_term_matching` boolean, nullable
    - `url_inclusions` string[], nullable
    - `channel_controls` DemandGenChannelControlsModel
      - `channel_config` 'CHANNEL_STRATEGY' | 'SELECTED_CHANNELS': How Demand Gen picks channels
      - `channel_strategy` 'ALL_CHANNELS' | 'ALL_OWNED_AND_OPERATED_CHANNELS': Demand Gen channel strategy
      - `selected_channels` DemandGenSelectedChannelsModel
        - `youtube_in_stream` boolean, nullable
        - `youtube_in_feed` boolean, nullable
        - `youtube_shorts` boolean, nullable
        - `discover` boolean, nullable
        - `gmail` boolean, nullable
        - `display` boolean, nullable
    - `optimized_targeting_enabled` boolean, nullable
    - `audience_segments` AudienceSegmentsModel: Campaign-level audience segments, one list per criterion kind. user_lists was the only field here and it was required, which made Google's own in-market and affinity categories impossible to send even though the applier has always written them (campaign_common.AUDIENCE_SEGMENT_CRITERIA) and search_google_ads_audiences hands back their ids under exactly these keys. Every block is optional now, and at least one has to carry ids so an empty block is still a refusal rather than a campaign targeting nobody. Demand Gen takes the same block but applies it per ad group, as one Google Ads Audience built from user_lists, user_interests and custom_audiences. An Audience has no slot for a combined audience or a bid adjustment, and Demand Gen has no observation mode, so those three are refused there rather than dropped.
      - `user_lists` string[], nullable
      - `user_interests` string[], nullable
      - `custom_audiences` string[], nullable
      - `combined_audiences` string[], nullable
      - `bid_modifier` number, nullable
      - `targeting_mode` 'OBSERVATION' | 'TARGETING': How audience segments are used - mirrors Google's TargetRestriction.bid_only
    - `geo_targets` GeoTargetsModel
      - `locations` GeoLocationModel[], required
        - `geo_target_constant` string, required
        - `name` string, nullable
      - `excluded_locations` GeoLocationModel[], nullable
        - `geo_target_constant` string, required
        - `name` string, nullable
      - `proximities` ProximityModel[], nullable
        - `radius` number, required
        - `radius_units` 'KILOMETERS' | 'MILES': Radius units for proximity (radius) location targeting
        - `city_name` string, nullable
        - `country_code` string, nullable
        - `postal_code` string, nullable
        - `province_code` string, nullable
        - `street_address` string, nullable
      - `geo_target_type` 'PRESENCE_OR_INTEREST' | 'PRESENCE': Geo target type - how people are matched for targeted locations
      - `negative_geo_target_type` 'PRESENCE_OR_INTEREST' | 'PRESENCE': Geo target type - how people are matched for targeted locations
    - `languages` string[], nullable
    - `keywords` KeywordModel[], nullable
      - `text` string, required
      - `match_type` 'EXACT' | 'PHRASE' | 'BROAD', required: Keyword match type enum
      - `cpc_bid_micros` integer, nullable
      - `final_url` string, nullable
    - `negative_keywords` NegativeKeywordModel[], nullable
      - `text` string, required
      - `match_type` 'EXACT' | 'PHRASE' | 'BROAD': Keyword match type enum
    - `ads` union[], nullable
      - union
        - ResponsiveSearchAd
          - `type` 'RESPONSIVE_SEARCH_AD'
          - `status` 'PAUSED' | 'ENABLED' | 'REMOVED', required: Campaign status enum
          - `final_urls` string[], required
          - `path1` string, nullable
          - `path2` string, nullable
          - `headlines` HeadlineModel[], required
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `descriptions` DescriptionModel[], required
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `final_mobile_urls` string[], nullable
          - `tracking_url_template` string, nullable
          - `final_url_suffix` string, nullable
          - `url_custom_parameters` UrlCustomParameter[], nullable
            - `key` string, required
            - `value` string, required
        - ResponsiveDisplayAd
          - `type` 'RESPONSIVE_DISPLAY_AD'
          - `status` 'PAUSED' | 'ENABLED' | 'REMOVED', required: Campaign status enum
          - `final_urls` string[], required
          - `business_name` string, required
          - `long_headline` HeadlineModel, required
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `headlines` HeadlineModel[], required
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `descriptions` DescriptionModel[], required
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `marketing_images` ImageAssetModelForAd[], nullable
            - `url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `base64_data` string, nullable
            - `name` string, nullable
          - `square_marketing_images` ImageAssetModelForAd[], nullable
            - `url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `base64_data` string, nullable
            - `name` string, nullable
          - `logo_images` ImageAssetModelForAd[], nullable
            - `url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `base64_data` string, nullable
            - `name` string, nullable
          - `youtube_videos` VideoAssetModelForAd[], nullable
            - `youtube_video_id` string, nullable
            - `youtube_url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `name` string, nullable
        - DemandGenMultiAssetAd: Demand Gen Multi Asset Ad model. Corresponds to 'DEMAND_GEN_MULTI_ASSET_AD' type.
          - `type` 'DEMAND_GEN_MULTI_ASSET_AD'
          - `status` 'PAUSED' | 'ENABLED' | 'REMOVED': Campaign status enum
          - `final_urls` string[], required
          - `final_mobile_urls` string[], nullable
          - `demand_gen_multi_asset_ad` DemandGenMultiAssetAdInfo, required: Inner structure for Demand Gen Multi-Asset Ad
            - `business_name` string, nullable
            - `call_to_action_text` 'LEARN_MORE' | 'SHOP_NOW' | 'SIGN_UP' | 'GET_QUOTE' | 'DOWNLOAD' | 'BOOK_NOW' | 'CONTACT_US' | 'SUBSCRIBE' | 'APPLY_NOW' | 'GET_OFFER' | 'REGISTER' | 'GET_INFO' | 'REQUEST_DEMO' | 'JOIN_NOW' | 'GET_STARTED': Call to action type enum
            - `headlines` HeadlineModel[], nullable
              - …
            - `descriptions` DescriptionModel[], nullable
              - …
            - `long_headlines` HeadlineModel[], nullable
              - …
            - `marketing_images` ImageAssetModelForAd[], nullable
              - …
            - `square_marketing_images` ImageAssetModelForAd[], nullable
              - …
            - `portrait_marketing_images` ImageAssetModelForAd[], nullable
              - …
            - `tall_portrait_marketing_images` ImageAssetModelForAd[], nullable
              - …
            - `logo_images` ImageAssetModelForAd[], nullable
              - …
            - `youtube_videos` VideoAssetModelForAd[], nullable
              - …
            - `call_to_action_assets` ImageAssetModelForAd[], nullable
              - …
            - `breadcrumb1` string, nullable
            - `breadcrumb2` string, nullable
            - `name` string, nullable
            - `lead_form_only` boolean, nullable
          - `asset_automations` object, nullable
        - DemandGenCarouselAd
          - `type` 'DEMAND_GEN_CAROUSEL_AD'
          - `status` 'PAUSED' | 'ENABLED' | 'REMOVED': Campaign status enum
          - `final_urls` string[], required
          - `final_mobile_urls` string[], nullable
          - `demand_gen_carousel_ad` DemandGenCarouselAdInfoModel, required
            - `business_name` string, required
            - `headline` HeadlineModel, required
              - …
            - `description` DescriptionModel, required
              - …
            - `carousel_cards` DemandGenCarouselCardModel[], required
              - …
            - `logo_image` ImageAssetModelForAd
              - …
            - `call_to_action_text` 'LEARN_MORE' | 'SHOP_NOW' | 'SIGN_UP' | 'GET_QUOTE' | 'DOWNLOAD' | 'BOOK_NOW' | 'CONTACT_US' | 'SUBSCRIBE' | 'APPLY_NOW' | 'GET_OFFER' | 'REGISTER' | 'GET_INFO' | 'REQUEST_DEMO' | 'JOIN_NOW' | 'GET_STARTED': Call to action type enum
          - `asset_automations` object, nullable
        - VideoAd
          - `type` 'VIDEO_TRUE_VIEW_IN_STREAM' | 'VIDEO_NON_SKIPPABLE_IN_STREAM' | 'VIDEO_BUMPER' | 'VIDEO_OUTSTREAM' | 'VIDEO_TRUE_VIEW_IN_DISPLAY' | 'VIDEO_RESPONSIVE', required
          - `status` 'PAUSED' | 'ENABLED' | 'REMOVED', required: Campaign status enum
          - `final_urls` string[], required
          - `final_mobile_urls` string[], nullable
          - `headlines` HeadlineModel[], required
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `long_headline` HeadlineModel
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `descriptions` DescriptionModel[], required
            - `text` string, required
            - `pinned_field` 'HEADLINE_1' | 'HEADLINE_2' | 'HEADLINE_3' | 'DESCRIPTION_1' | 'DESCRIPTION_2': Pinned position for a responsive search ad asset
          - `business_name` string, required
          - `marketing_images` ImageAssetModelForAd[], nullable
            - `url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `base64_data` string, nullable
            - `name` string, nullable
          - `square_marketing_images` ImageAssetModelForAd[], nullable
            - `url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `base64_data` string, nullable
            - `name` string, nullable
          - `logo_images` ImageAssetModelForAd[], nullable
            - `url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `base64_data` string, nullable
            - `name` string, nullable
          - `youtube_videos` VideoAssetModelForAd[], nullable
            - `youtube_video_id` string, nullable
            - `youtube_url` string, nullable
            - `asset_resource` string, nullable
            - `asset` string, nullable
            - `name` string, nullable
          - `call_to_action_text` string, nullable
        - ShoppingProductAd
          - `type` 'SHOPPING_PRODUCT_AD'
          - `status` 'PAUSED' | 'ENABLED' | 'REMOVED': Campaign status enum
          - `final_urls` string[], nullable
  - `ad_group_selection` AdGroupSelectionModel
    - `use_existing` boolean
    - `existing_ad_group_id` string, nullable
  - `asset_groups` AssetGroupModel[], nullable
    - `name` string, required
    - `final_urls` string[], required
    - `final_mobile_urls` string[], nullable
    - `headlines` TextAssetModel[], required
      - `text` string, required
    - `long_headlines` TextAssetModel[], required
      - `text` string, required
    - `descriptions` TextAssetModel[], required
      - `text` string, required
    - `business_name` string, required
    - `marketing_images` ImageAssetModel[], required
      - `url` string, nullable
      - `asset` string, nullable
      - `asset_resource` string, nullable
    - `square_marketing_images` ImageAssetModel[], required
      - `url` string, nullable
      - `asset` string, nullable
      - `asset_resource` string, nullable
    - `logo_images` ImageAssetModel[], nullable
      - `url` string, nullable
      - `asset` string, nullable
      - `asset_resource` string, nullable
    - `youtube_videos` VideoAssetModel[], nullable
      - `url` string, nullable
      - `youtube_video_id` string, nullable
      - `asset` string, nullable
      - `asset_resource` string, nullable
      - `asset_name` string, nullable
    - `call_to_actions` CallToActionType[], nullable
    - `audience_signals` AudienceSignalsModel
      - `user_lists` string[], nullable
      - `interests` string[], nullable
      - `demographics` object, nullable
    - `sitelinks` SitelinkExtension[], nullable
      - `link_text` string, required
      - `description1` string, nullable
      - `description2` string, nullable
      - `final_urls` string[], required
      - `final_mobile_urls` string[], nullable
      - `final_url_suffix` string, nullable
    - `search_themes` string[], nullable
    - `audiences` string[], nullable
    - `path1` string, nullable
    - `path2` string, nullable
  - `extensions` ExtensionsModel: Assets linked to the campaign itself, rather than to an ad or asset group. The brand blocks at the bottom are campaign assets in the same way sitelinks are, so they reach a Performance Max or Demand Gen campaign without going through an asset group. Two different logo field types, which is the thing that trips people up: `logos` and `landscape_logos` are LOGO / LANDSCAPE_LOGO, which Google refuses on SEARCH ("The specified field type is incompatible with the given campaign type"), while `business_logos` is BUSINESS_LOGO — the Business logo that Google's own Search campaign UI offers, read alongside business_name. There is still no images block: Google refuses AD_IMAGE as an asset link on any campaign type, measured against a live account.
    - `sitelinks` SitelinkExtension[], nullable
      - `link_text` string, required
      - `description1` string, nullable
      - `description2` string, nullable
      - `final_urls` string[], required
      - `final_mobile_urls` string[], nullable
      - `final_url_suffix` string, nullable
    - `callouts` CalloutExtension[], nullable
      - `text` string, required
    - `structured_snippets` StructuredSnippetExtension[], nullable
      - `header` string, required
      - `values` string[], required
    - `call_extensions` CallExtension[], nullable
      - `phone_number` string, required
      - `country_code` string, required
      - `call_tracking_enabled` boolean, nullable
      - `call_only` boolean, nullable
    - `location_extensions` LocationExtension[], nullable
      - `business_name` string, required
      - `address_line_1` string, required
      - `address_line_2` string, nullable
      - `city` string, required
      - `province` string, nullable
      - `postal_code` string, required
      - `country_code` string, required
      - `phone_number` string, nullable
      - `business_hours` object, nullable
    - `promotions` PromotionExtension[], nullable
      - `promotion_target` string, required
      - `final_urls` string[], required
      - `percent_off` number, nullable
      - `money_amount_off` MoneyModel
        - `amount_micros` integer, required
        - `currency_code` string, required
      - `discount_modifier` 'UP_TO': Promotion discount modifier
      - `promotion_code` string, nullable
      - `orders_over_amount` MoneyModel
        - `amount_micros` integer, required
        - `currency_code` string, required
      - `occasion` 'NEW_YEARS' | 'CHINESE_NEW_YEAR' | 'VALENTINES_DAY' | 'EASTER' | 'MOTHERS_DAY' | 'FATHERS_DAY' | 'LABOR_DAY' | 'BACK_TO_SCHOOL' | 'HALLOWEEN' | 'BLACK_FRIDAY' | 'CYBER_MONDAY' | 'CHRISTMAS' | 'BOXING_DAY' | 'INDEPENDENCE_DAY' | 'NATIONAL_DAY' | 'END_OF_SEASON' | 'WINTER_SALE' | 'SUMMER_SALE' | 'FALL_SALE' | 'SPRING_SALE' | 'RAMADAN' | 'EID_AL_FITR' | 'EID_AL_ADHA' | 'SINGLES_DAY' | 'WOMENS_DAY' | 'HOLI' | 'PARENTS_DAY' | 'ST_NICHOLAS_DAY' | 'CARNIVAL' | 'EPIPHANY' | 'ROSH_HASHANAH' | 'PASSOVER' | 'HANUKKAH' | 'DIWALI' | 'NAVRATRI' | 'SONGKRAN' | 'YEAR_END_GIFT': Promotion occasion
      - `language_code` string
      - `start_date` string, nullable
      - `end_date` string, nullable
    - `prices` PriceExtension[], nullable
      - `type` 'BRANDS' | 'EVENTS' | 'LOCATIONS' | 'NEIGHBORHOODS' | 'PRODUCT_CATEGORIES' | 'PRODUCT_TIERS' | 'SERVICES' | 'SERVICE_CATEGORIES' | 'SERVICE_TIERS', required: Price extension type
      - `price_offerings` PriceOfferingModel[], required
        - `header` string, required
        - `description` string, required
        - `price` MoneyModel, required
          - `amount_micros` integer, required
          - `currency_code` string, required
        - `final_url` string, required
        - `unit` 'PER_HOUR' | 'PER_DAY' | 'PER_WEEK' | 'PER_MONTH' | 'PER_YEAR' | 'PER_NIGHT': Price offering unit
      - `price_qualifier` 'FROM' | 'UP_TO' | 'AVERAGE': Price qualifier
      - `language_code` string
    - `apps` AppExtension[], nullable
      - `app_id` string, required
      - `app_store` 'APPLE_APP_STORE' | 'GOOGLE_APP_STORE', required: App store for a mobile app asset
      - `link_text` string, required
      - `final_urls` string[], required
    - `lead_forms` LeadFormExtension[], nullable
      - `business_name` string, required
      - `headline` string, required
      - `description` string, required
      - `privacy_policy_url` string, required
      - `fields` LeadFormFieldType[], required
      - `call_to_action_description` string, required
      - `call_to_action_type` 'LEARN_MORE' | 'GET_QUOTE' | 'APPLY_NOW' | 'SIGN_UP' | 'CONTACT_US' | 'SUBSCRIBE' | 'DOWNLOAD' | 'BOOK_NOW' | 'GET_OFFER' | 'REGISTER' | 'GET_INFO' | 'REQUEST_DEMO' | 'JOIN_NOW' | 'GET_STARTED': Lead form call to action
    - `logos` string[], nullable
    - `landscape_logos` string[], nullable
    - `business_logos` string[], nullable
    - `business_name` string, nullable
  - `negative_keywords` NegativeKeywordModel[], nullable
    - `text` string, required
    - `match_type` 'EXACT' | 'PHRASE' | 'BROAD': Keyword match type enum

## Response `200`

Successful Response

- GoogleAdCampaignValidationResponseDTO
  - `status` string
  - `valid` boolean, required
  - `issue_count` integer, required
  - `issues` GoogleAdCampaignIssueDTO[], required
    - `field` string, required
    - `message` string, required
  - `notes` string[]
  - `checks` object, required

## Other responses

- `422`: Validation Error

## Changes

> 37 revisions in range; 1 not diffed.

- **2026-09-30** `05ad3a41b4cf`: 2 info
  - added the new optional request property `ad_groups/anyOf[subschema #1]/items/negative_keywords`
  - added the new optional request property `negative_keywords`
- **2026-09-29** `ef659ddab5b1`: 3 breaking, 3 info
  - removed the enum value `OBSERVATION` of the request property `targeting/anyOf[subschema #1: TargetingModel]/audience_segments/anyOf[subschema #1: AudienceSegmentsModel]/targeting_mode`
  - removed the enum value `TARGETING` of the request property `targeting/anyOf[subschema #1: TargetingModel]/audience_segments/anyOf[subschema #1: AudienceSegmentsModel]/targeting_mode`
  - the `targeting/anyOf[subschema #1: TargetingModel]/audience_segments/anyOf[subschema #1: AudienceSegmentsModel]/targeting_mode` request property type changed from `string` to no type
  - added the new optional request property `ad_groups/anyOf[subschema #1]/items/audience_segments`
  - …2 more
- **2026-09-25** `29a2d8bd4091`: 1 info
  - added the new optional request property `extensions/anyOf[subschema #1: ExtensionsModel]/business_logos`
- …earlier changes not shown

[Operation history](https://skmtc.dev/brandbooster/apis/brandbooster-api/changes/api/v1/google-ad-manager/campaigns/validate/post.md)

---

[API](https://skmtc.dev/brandbooster/apis/brandbooster-api.md) - [All operations](https://skmtc.dev/brandbooster/apis/brandbooster-api/llms.txt) - [OpenAPI document](https://skmtc.dev/brandbooster/apis/brandbooster-api/revisions/02d28bde684c?raw)
