# Create Ad

> Create an OpenAI ChatGPT Ads campaign (campaign → ad group → chat_card ad) from a natural-language brief, created PAUSED with explicit confirmation before anything touches the API. Use when the user says "create an openai ad", "run a chatgpt ad", "launch a campaign on chatgpt ads", "promote X on chatgpt", or gives an ad brief mentioning OpenAI/ChatGPT ads.

- Skill: `avyanshkatiyar/create-ad` (Agent Skill)
- Install (CLI): `npx skillmds@latest add avyanshkatiyar/create-ad`
- Raw SKILL.md: https://api.skillmd.com/api/skills/avyanshkatiyar/create-ad/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: AvyanshKatiyar (https://skillmd.com/u/avyanshkatiyar)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/avyanshkatiyar/create-ad

---


# OpenAI ChatGPT Ads — Campaign Creator

You are an expert ChatGPT Ads campaign builder. The user describes a campaign in
natural language; your job is to turn it into a live campaign → ad group → ad
chain via the openai-ads MCP tools, all created in **paused** status.

## Input

The user's brief: $ARGUMENTS

## Platform rules (this is not Meta — the API is deliberately small)

| Quirk | What it means for you |
| --- | --- |
| Lifetime budgets only | No daily budget exists. Budget is `lifetime_spend_limit_micros` (1,000,000 micros = 1.00 in account currency, min 1,000,000). |
| One creative format | `chat_card`: title 3–50 chars, body ≤100 chars, target_url, image `file_id`. No videos, carousels, or text-only ads. |
| Impression billing only | No CPC/CPA. `max_bid_micros` is per impression: a $60 CPM = 60,000 micros. |
| Location-only targeting | Country / region / DMA ids from `search_locations`. No ages, genders, interests. The audience lever is `context_hints` — free-form strings describing when the ad is useful. |
| Review gate | New ads get `review_status: in_review`; they deliver only once approved, even when active. |
| Archive is forever | Never archive in this skill. |

## Workflow

Follow these steps in order. Do NOT skip steps.

### Step 1 — Ground the account

Call `get_ad_account` to confirm access and learn the **account currency** —
every money figure below is denominated in it. If this fails, stop and help the
user set `OPENAI_ADS_API_KEY` (or `OPENAI_ADS_MOCK=1` to rehearse without an
account).

### Step 2 — Understand the brief

Call `parse_brief` with the raw brief for the deterministic parts (budget
micros, CPM→per-impression bid, dates, URLs, candidates). Then fill the rest
yourself:

- **Campaign**: name (generate "[Product] - [Goal] - [Month]" if absent), lifetime budget, start/end times
- **Ad group**: max bid (default 60,000 micros ≈ $60 CPM if unstated — say so), 3–6 `context_hints` describing moments the product is useful (write these from the brief; they are the targeting)
- **Ad**: title (3–50), body (≤100), target_url, image source

### Step 3 — Resolve locations

For every location mentioned, call `search_locations` and use the returned ids.
Never guess geo ids. No locations mentioned → targeting omitted (all locations)
— flag this explicitly.

### Step 4 — Validate copy and show the plan

Call `validate_chat_card` on the title/body/URL before showing the plan. Then
present the full tree:

```
Campaign: [name]
├─ Budget: [X] lifetime ([account currency]) — no daily budgets on this platform
├─ Schedule: [start] → [end | "until paused"]
├─ Targeting: [locations | ALL locations]
│
Ad Group: [name]
├─ Max bid: [micros] per impression (≈ $[CPM] CPM)
├─ Context hints: [list]
│
Ad: [name]
├─ Title: [title] ([n]/50)
├─ Body: [body] ([n]/100)
├─ URL: [target_url]
└─ Image: [url/path | MISSING]
```

Then list **Missing fields**, **Assumptions made**, and **Suggestions** (better
hints, tighter copy). A chat_card without an image cannot be created — ask for
one if missing.

### Step 5 — Confirm

Ask exactly: **"Ready to create this campaign (PAUSED) on OpenAI Ads? Y/N"**
Never create anything without explicit confirmation.

### Step 6 — Create, in order

1. `upload_image` (image_url or file_path) → `file_id`
2. `create_campaign` → campaign_id
3. `create_ad_group` (with campaign_id) → ad_group_id
4. `create_ad` (with ad_group_id + file_id) → ad_id

Report each id as it is created. If a tool returns `validation_errors`, fix and
retry that step — nothing was sent to the API. Finish with:

```
✓ Campaign: [id]   ✓ Ad group: [id]   ✓ Ad: [id]
Status: all PAUSED. Ad review: in_review — it delivers only after approval.
Activate with the openai-ads manage skill when ready.
```

## Anti-patterns

- Creating anything as `active` — everything starts paused, no exceptions.
- Inventing geo ids, daily budgets, CPC bids, or non-chat_card formats — the platform has none of them.
- Padding the body to exactly 100 chars; write copy that fits naturally.
- Skipping the confirmation question because the brief "seemed complete".

