Section 3 — The Advertiser API · Last verified: MAY 2026

Ads (the Creative Resource)

Chapter 17 — Ads (the Creative Resource)

Ads sit inside an ad group and host the title, body, image, and destination URL that the user actually sees.

Endpoints

MethodPathPurpose
GET/ads?ad_group_id=...List ads for an ad group.
POST/adsCreate.
GET/ads/{id}Retrieve one.
POST/ads/{id}Update.
POST/ads/{id}/activateActivate.
POST/ads/{id}/pausePause.
POST/ads/{id}/archiveArchive (irreversible).
GET/ads/{id}/insightsPerformance at ad scope.

Create-ad fields

FieldTypeRequiredNotes
ad_group_idstringYesParent ad group.
namestringYes3–1000 chars, non-space required. Internal label only — not shown to users.
creative.typestringYesCurrently only chat_card.
creative.titlestringYes3–50 characters.
creative.bodystringYesMaximum 100 characters.
creative.target_urlstringYesDestination URL.
creative.file_idstringYesFile ID returned by POST /upload (Chapter 18).
statusstringYesactive or paused.

What the user sees

The chat_card creative is the only ad format currently supported. It renders below a ChatGPT response with:

  • The image (from file_id).
  • The title (≤50 chars).
  • The body (≤100 chars).
  • A click target that takes the user to target_url.

Total text surface: 150 characters. Plan creative around that ceiling. Title carries the offer, body carries the qualifier or hook.

Review pipeline

Every ad response includes review_status. New ads start in in_review and typically clear to approved in a few minutes.

A rejected ad violates one of OpenAI’s ad policies (openai.com/policies/ad-policies/). Edit the ad and it will be re-reviewed automatically.

Update behaviour

All fields are optional on update. If creative is included, send the full creative object — partial updates aren’t supported. status accepts active, paused, or archived. Updating any creative field re-triggers review. If you’ve been delivering on an approved ad and you update the creative, expect a brief return to in_review before the new variant is live.

Example: create an ad

curl -X POST "https://api.ads.openai.com/v1/ads" 
  -H "Authorization: Bearer $OPENAI_ADS_API_KEY" 
  -H "Content-Type: application/json" 
  -d '{
    "ad_group_id": "adgrp_301",
    "name": "Planner launch card",
    "status": "active",
    "creative": {
      "type": "chat_card",
      "title": "Try the new workspace planner",
      "body": "Coordinate tasks, docs, and meetings in one place.",
      "target_url": "https://example.com/workspace-planner",
      "file_id": "file_901"
    }
  }'

Example response

{
  "id": "ad_501",
  "name": "Planner launch card",
  "creative": {
    "type": "chat_card",
    "title": "Try the new workspace planner",
    "body": "Coordinate tasks, docs, and meetings in one place.",
    "file_id": "file_901",
    "image_url": "https://cdn.openai.com/ads/file_901.png",
    "target_url": "https://example.com/workspace-planner"
  },
  "status": "active",
  "review_status": "in_review"
}

creative.image_url is read-only and returned by the API after the ad is created — that’s the URL OpenAI’s CDN serves the image from. You don’t set it.

Internal name vs displayed copy

name is what you see in your reports and in Ads Manager. It is never shown to users. Use it for the version, the test variant, the iteration number — whatever helps you distinguish similar creatives in your own reporting.

The creative.title and creative.body are what users see. Optimise those. The name is for the operator.