---
title: "Generate Google Ads assets"
method: POST
path: "/api/apps/{app_id}/google-ads/assets/generate-all"
---

# Generate Google Ads assets

`POST /api/apps/{app_id}/google-ads/assets/generate-all`

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

Writes ad copy and generates pictures for the app in one call, and returns them as previews.

Nothing reaches Google Ads here. Everything comes back as a preview you look at first, and only [Accept a generated Google Ads asset](/api-reference/accept-a-generated-google-ads-asset) puts one on a live campaign.

Which slots get filled follows `channel_type`. `SEARCH` gets `HEADLINE` and `DESCRIPTION` copy plus landscape and square pictures. `DISPLAY` gets the same pictures and adds `LONG_HEADLINE` copy. `PERFORMANCE_MAX` and `DEMAND_GEN` get that copy plus all four picture shapes, adding portrait and tall portrait. You cannot ask for individual slots on this endpoint.

The copy is written in the language of the app's own site, not the language you ask in, and the response reports which one in `language`.

Pictures take longer than copy, so the response returns as soon as the copy is ready. `images` holds only the pictures that finished in time and `background_image_count` says how many more are coming. Poll [List Google Ads generated assets](/api-reference/list-google-ads-generated-assets) with the returned `session_id` for the rest.

<Warning>Only one generation runs per app at a time. Calling this while one is already running returns a 200 carrying **that** run's `session_id` with `text` and `images` empty, and with `background_image_count` and `language` absent. That absence is how you tell it apart from a generation that genuinely produced nothing, and the right response is to poll the `session_id` you were given rather than to retry.</Warning>

Rate limits are per app and split across two pools. The copy costs 2 of 20 requests a minute. The pictures cost one of 10 requests a minute for each picture shape, so a `PERFORMANCE_MAX` call costs 4 and a `SEARCH` call costs 2. The picture pool runs out first, which puts a `PERFORMANCE_MAX` ceiling of about two calls a minute. A leg that has nothing to do costs nothing. Each leg can also retry once, as below, and the retry costs that leg the same again.

<Note>When Google refuses the page you pointed at, Base44 retries once on the app's own published URL, and that retry costs the same again. Pace requests against the doubled figure, not the single one, or a refusal-heavy app hits a 429 part-way through its own recovery.</Note>

<Note>Generating creative does not spend credits and is not billed. It is capped by rate limits instead, so a burst gets a 429 rather than a bill.</Note>

<Note>When one leg fails and the other produced something, you get a 200 with only the successful leg's assets. The failure is only raised when neither leg produced anything, so check `text` and `images` rather than assuming a 200 means both ran.</Note>

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

<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 whose Google Ads creative you want to generate or read.

## Request body

- object
  - `channel_type` string — Campaign type to generate for, which decides the slots that get filled. One of `PERFORMANCE_MAX`, `DEMAND_GEN`, `SEARCH` or `DISPLAY`.
  - `final_url` string — Page the pictures should be based on. Send this or `freeform_prompt`, not both.
  - `freeform_prompt` string — What the pictures should show, in your own words, up to 1500 characters. Send this or `final_url`, not both.

## Response `200`

The creative that was generated.

- GenerateAssetsResult — The creative one generation produced.
  - `session_id` string, required — ID of this generation. Pass it as `session_id` to [List Google Ads generated assets](/api-reference/list-google-ads-generated-assets) to poll for the images that are still coming.
  - `text` GeneratedAssetSummary[], required — The copy that was generated. Empty when the text engine produced nothing and when a generation for this app was already running.
    - `session_asset_id` string, required — ID of this asset within the session. Pass it as `session_asset_id` to [Accept a generated Google Ads asset](/api-reference/accept-a-generated-google-ads-asset).
    - `asset_field_type` string, required — Which slot on the ad this asset fills. Text assets are `HEADLINE`, `LONG_HEADLINE` or `DESCRIPTION`. Image assets are `MARKETING_IMAGE`, `SQUARE_MARKETING_IMAGE`, `PORTRAIT_MARKETING_IMAGE` or `TALL_PORTRAIT_MARKETING_IMAGE`.
    - `kind` string, required — Whether the asset is copy (`text`) or a picture (`image`).
    - `text` string, nullable, required — The generated copy, or `null` on an image asset.
    - `image_url` string, nullable, required — URL of the generated picture, or `null` on a text asset. It is a Base44 preview URL, not a Google one, and it stops resolving once the asset is cleaned up.
    - `source` string, required — Which engine wrote it. The value is `google` for Google's own asset generation and `inhouse` for the Base44 model that covers languages Google does not generate for, and that stands in when Google's call fails.
    - `language` string, nullable, required — Language of a text asset as a lowercase two-letter code, or `null` on an image, because image assets carry no copy.
    - `channel_type` string, required — Campaign type the asset was generated for, one of `SEARCH`, `PERFORMANCE_MAX`, `DISPLAY` or `DEMAND_GEN`.
    - `created_at` string, date-time, required — When the asset was generated.
  - `images` GeneratedAssetSummary[], required — The pictures that finished in time to be returned inline. The rest are counted in `background_image_count`.
    - `session_asset_id` string, required — ID of this asset within the session. Pass it as `session_asset_id` to [Accept a generated Google Ads asset](/api-reference/accept-a-generated-google-ads-asset).
    - `asset_field_type` string, required — Which slot on the ad this asset fills. Text assets are `HEADLINE`, `LONG_HEADLINE` or `DESCRIPTION`. Image assets are `MARKETING_IMAGE`, `SQUARE_MARKETING_IMAGE`, `PORTRAIT_MARKETING_IMAGE` or `TALL_PORTRAIT_MARKETING_IMAGE`.
    - `kind` string, required — Whether the asset is copy (`text`) or a picture (`image`).
    - `text` string, nullable, required — The generated copy, or `null` on an image asset.
    - `image_url` string, nullable, required — URL of the generated picture, or `null` on a text asset. It is a Base44 preview URL, not a Google one, and it stops resolving once the asset is cleaned up.
    - `source` string, required — Which engine wrote it. The value is `google` for Google's own asset generation and `inhouse` for the Base44 model that covers languages Google does not generate for, and that stands in when Google's call fails.
    - `language` string, nullable, required — Language of a text asset as a lowercase two-letter code, or `null` on an image, because image assets carry no copy.
    - `channel_type` string, required — Campaign type the asset was generated for, one of `SEARCH`, `PERFORMANCE_MAX`, `DISPLAY` or `DEMAND_GEN`.
    - `created_at` string, date-time, required — When the asset was generated.
  - `background_image_count` integer, nullable — How many more pictures are still being generated for this session. The response comes back as soon as the copy is done, so poll [List Google Ads generated assets](/api-reference/list-google-ads-generated-assets) with `session_id` for these. The field is absent when a generation for this app was already running, which is how you tell that case apart.
  - `language` string, nullable — Language the copy was written in, as a lowercase two-letter code. It comes from the app's own site rather than from anything you send. The field is absent when a generation for this app was already running.

## Other responses

- `400` — Google Ads rejected the generation request, for example a landing page it could not read. The response message carries Google's reason.
- `401` — Missing or invalid credentials.
- `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.
- `409` — The request to Google Ads timed out after being sent. Nothing was attached to a campaign, so retrying is safe.
- `422` — You sent both `final_url` and `freeform_prompt`, or `freeform_prompt` is longer than 1500 characters.
- `429` — The app has used up one of the creative rate limits, either 20 copy requests a minute or 10 picture requests a minute. Retry later.

---

[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-service-production.skmtc.workers.dev/v1/apis/base44/base44-app-management-api/revisions/173e4e9c63c2/schema)
