---
title: "Create Google Ads campaign"
method: POST
path: "/api/apps/{app_id}/google-ads/campaigns"
---

# Create Google Ads campaign

`POST /api/apps/{app_id}/google-ads/campaigns`

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Creates a campaign on the app's Google Ads account and starts serving it.

This spends money. The workspace needs a payment method on file and an account in good standing. Without either, the call returns a 402 and no campaign is created. A campaign is also created paused when the app's conversion tracking is not yet verified, so check `status` on the response rather than assuming it is serving.

Set `campaign_type` to `SMART` or `PERFORMANCE_MAX`. `daily_budget_micros` is in micros of the account currency and has a per-currency floor Google enforces. A budget below it comes back as a 400 carrying Google's reason, and the campaign is not created. Advertisers in the EU must declare whether the campaign carries political advertising. The call is rejected until that declaration is on file.

Google validates the campaign as it is created, so a rejected ad text, an unreachable landing page, or a budget below the floor comes back as a 400 with Google's own reason.

<Note>This endpoint accepts a personal API key. Workspace API keys are not authorized for it and are rejected with a 403.</Note>

<Warning>A 409 means the change may or may not have been applied. The request to Google Ads timed out after it was sent. Read the campaign back with [Get campaign](/api-reference/get-google-ads-campaign) before retrying, or you can end up applying it twice.</Warning>

<Warning>The response includes fields beyond the ones documented here. Don't rely on undocumented response fields, as they can change at any time. Send only the fields documented here. Other request fields are not supported and their behavior can change.</Warning>

## Path parameters

- `app_id` string, required — ID of the app to advertise.

## Request body

- object
  - `campaign_name` string, required — Name for the campaign.
  - `campaign_type` 'SMART' | 'PERFORMANCE_MAX' — Which campaign type to create.
  - `daily_budget_micros` integer, required — Daily budget in micros of the account currency, so `15000000` is 15.00. Google enforces a per-currency minimum and rejects anything below it with a 400.
  - `landing_page` string — URL the ads send clicks to. Google rejects the campaign if it cannot reach this page.
  - `logo_url` string — URL of the logo, at least 128×128. Required for a `PERFORMANCE_MAX` campaign and ignored for `SMART`. It follows the same hosting rules as `images[].url`, but unlike an image a logo Base44 cannot fetch fails the request instead of being left out. A logo that is not square is padded to square.
  - `images` object[] — Marketing images for a `PERFORMANCE_MAX` campaign, ignored for `SMART`. A Performance Max campaign needs at least one `MARKETING_IMAGE` and one `SQUARE_MARKETING_IMAGE`, and Google rejects the campaign without them. Base44 leaves out an image it cannot fetch, rather than rejecting the request. That includes an address on another host, a file over 5 MB, and one that does not respond. If that leaves a required slot empty, Google rejects the campaign for the missing image. An address that returns something other than an image is rejected outright.
    - `url` string, required — Address of the image. It has to be `https` on a host Base44 fetches images from, such as an address on `base44.com` or `base44.app`. Use a static PNG, JPEG, or GIF of 5 MB or less.
    - `field_type` 'MARKETING_IMAGE' | 'SQUARE_MARKETING_IMAGE' | 'PORTRAIT_MARKETING_IMAGE' | 'TALL_PORTRAIT_MARKETING_IMAGE' — Which slot the image fills. Base44 does not crop or resize, so the image has to match its slot's shape to within 1% already, or Google rejects it: - `MARKETING_IMAGE` is 1.91:1 landscape, at least 600×314. - `SQUARE_MARKETING_IMAGE` is 1:1, at least 300×300. - `PORTRAIT_MARKETING_IMAGE` is 4:5, at least 480×600. - `TALL_PORTRAIT_MARKETING_IMAGE` is 9:16, at least 600×1067. Defaults to `MARKETING_IMAGE`, and a value outside this list is treated as `MARKETING_IMAGE` too.
    - `name` string — Label for the image in Google Ads. Defaults to `image`.
  - `sitelinks` object[] — Extra links shown under a `PERFORMANCE_MAX` campaign's ads, up to 20. Ignored for `SMART`. A row with neither `text` nor `url` is dropped, a row with only one of them is rejected, and exact duplicates collapse to one.
    - `text` string, required — Link text. Google shows at most 25 characters, and Base44 cuts longer text down to 25 rather than rejecting it.
    - `url` string, required — Where the link goes, as an `http` or `https` address.
  - `keyword_themes` string[] — Themes to match searches on, for a `SMART` campaign.
  - `headlines` string[] — Ad headlines. Google reviews these against its advertising policies.
  - `descriptions` string[] — Ad description lines. Google reviews these against its advertising policies.
  - `geo_targets` string[] — Google Ads geo target constant IDs to target.
  - `business_name` string — Business name shown in the ad.
  - `phone_number` string — Phone number shown in the ad. On PERFORMANCE_MAX it becomes a call asset and on SMART it becomes `smartCampaignSettings.phone_number`; either way it must be in international format with the country code (e.g. +18506168085) — Google needs the country alongside the number, and any other format is rejected with a 400. Omit for no phone.
  - `contains_eu_political_advertising` boolean — Whether the campaign carries political advertising. Required before an EU advertiser can create a campaign.
  - `settings` object — Campaign settings. `language_code` is the only key this API commits to; anything else is passed through undocumented.
    - `language_code` string — Two-letter code for the language the ad copy is written in, which becomes the campaign's advertising language. English when absent or unsupported — `Accept-Language` does not affect it. Pass through `settings` from [Suggest Google Ads campaigns](/api-reference/suggest-google-ads-campaigns) to keep a generated campaign's targeting on its copy's language.

## Response `200`

Successful Response

- CampaignResource — The campaign fields this API commits to.
  - `id` string, required — Base44's ID for the campaign. Pass this as `campaign_id` on the other campaign endpoints.
  - `google_campaign_id` string, required — The campaign's ID in Google Ads. Empty while a just-created campaign is still being pushed to Google.
  - `campaign_name` string, required — Name shown for the campaign.
  - `campaign_type` 'SMART' | 'PERFORMANCE_MAX' | 'SEARCH' | 'DISPLAY' | 'SHOPPING' | 'VIDEO' | 'DEMAND_GEN' | 'LOCAL' | 'UNKNOWN', required — Campaign type. Base44 creates `SMART` and `PERFORMANCE_MAX`. The other values appear only on campaigns created outside Base44 and synced in.
  - `status` 'ENABLED' | 'PAUSED' | 'REMOVED' | 'UNKNOWN', required — Serving state in Base44's cache. A status of `REMOVED` is a deleted campaign, which Google keeps for reporting.
  - `daily_budget_micros` integer, required — Daily budget in micros of the account currency, where 1,000,000 micros is one unit, so `15000000` is 15.00.
  - `landing_page` string, required — URL the ads send clicks to.
  - `geo_targets` string[], required — Google Ads geo target constant IDs the campaign targets.
  - `phone_number` string, required — Campaign phone number in E.164, empty when the campaign has none. Both channel types store the normalized form Google holds: a call asset on PERFORMANCE_MAX, `smartCampaignSettings.phone_number` on SMART.
  - `learning_ends_at` string, date-time, nullable — When Smart Bidding's learning period is expected to end, about 14 days after creation, or `null` on a campaign that has not started learning.
  - `review_status` string, required — Google's policy review status, passed through as Google reports it (`REVIEWED`, `UNDER_REVIEW`, …). Empty until the first sync after creation.
  - `serving_status` string, required — Google's serving status, passed through as Google reports it. Can still report review gating after policy review clears, so read it alongside `review_status`.
  - `primary_status` string, required — Google's summary of whether the campaign is serving well, passed through as Google reports it (`ELIGIBLE`, `LIMITED`, `NOT_SERVING`, …).
  - `primary_status_reasons` string[], required — Google's reasons behind `primary_status`, for example why a campaign is limited. Empty when there is nothing to explain.
  - `created_date` string, date-time, required — When the campaign was created in Base44.
  - `updated_date` string, date-time, required — When Base44 last changed its record of the campaign.

## Other responses

- `400` — Google Ads rejected the request, for example ad text that breaks its policies or a budget below the currency's minimum. The response message carries Google's reason.
- `401` — Missing or invalid credentials.
- `402` — No payment method on file, or the workspace has an unpaid balance.
- `403` — You don't have access to this app, the app does not exist, or you used a workspace API key. A missing app and an app you cannot reach are deliberately the same answer.
- `404` — The app has no connected Google Ads account, or there is no campaign with this ID.
- `409` — The request to Google Ads timed out after being sent, so the change may or may not have been applied. Read the campaign back before retrying.
- `422` — Validation Error
- `429` — Google Ads is rate limiting the account. Retry later.

## Changes

- **2026-09-23** `1191e1b252ee` — 2 info
  - added the new optional request property `images`
  - added the new optional request property `sitelinks`

[Change history](https://skmtc.dev/base44/apis/base44-app-management-api/changes/api/apps/:app_id/google-ads/campaigns/post.md)

---

[API](https://skmtc.dev/base44/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/base44/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/base44/apis/base44-app-management-api/revisions/cf164639a9bf?raw)
