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
| Method | Path | Purpose |
|---|---|---|
GET | /ads?ad_group_id=... | List ads for an ad group. |
POST | /ads | Create. |
GET | /ads/{id} | Retrieve one. |
POST | /ads/{id} | Update. |
POST | /ads/{id}/activate | Activate. |
POST | /ads/{id}/pause | Pause. |
POST | /ads/{id}/archive | Archive (irreversible). |
GET | /ads/{id}/insights | Performance at ad scope. |
Create-ad fields
| Field | Type | Required | Notes |
|---|---|---|---|
ad_group_id | string | Yes | Parent ad group. |
name | string | Yes | 3–1000 chars, non-space required. Internal label only — not shown to users. |
creative.type | string | Yes | Currently only chat_card. |
creative.title | string | Yes | 3–50 characters. |
creative.body | string | Yes | Maximum 100 characters. |
creative.target_url | string | Yes | Destination URL. |
creative.file_id | string | Yes | File ID returned by POST /upload (Chapter 18). |
status | string | Yes | active 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.