Summary
The ads command group added in #32 (PR #34) is read-only (list/get). The asa-api-client library actually supports full ad CRUD — this issue tracks adding the write operations.
Ad creation was deliberately deferred from #32 because, unlike the other v5 resources, it's a real feature with meaningful UX decisions (creative type selection, CPP linking), not just a surfacing pass.
Library surface (already available)
client.campaigns(c).ad_groups(a).ads inherits base CRUD:
create(AdCreate) -> Ad
update(ad_id, AdUpdate) -> Ad
delete(ad_id) -> None
Models:
AdCreate: name: str
creative_type: CreativeType # CREATIVE_SET | CUSTOM_PRODUCT_PAGE | DEFAULT_PRODUCT_PAGE
status: AdStatus = ENABLED
product_page_id: str | None # required for CUSTOM_PRODUCT_PAGE
AdUpdate: name: str | None
status: AdStatus | None
Proposed commands
asa ads create -c <campaign> -a <ad-group> --name <name> --creative-type <type> [--product-page <id>] [--status ENABLED|PAUSED]
asa ads update <ad-id> -c <campaign> -a <ad-group> [--name <name>] [--status ...]
asa ads delete <ad-id> -c <campaign> -a <ad-group> [--yes]
Design considerations
- Creative type ↔ product page coupling.
CUSTOM_PRODUCT_PAGE requires --product-page <id>; DEFAULT_PRODUCT_PAGE/CREATIVE_SET must not take one. Validate this combination client-side with a clear error rather than letting the API 400.
- Discoverability.
--product-page ids come from asa product-pages list (already shipped) — cross-reference in help text. Consider validating the CPP belongs to the campaign's app.
- Confirmation + dry-run.
delete should confirm (reuse confirm_action, with --yes to skip); create could support --dry-run to preview the payload, consistent with optimize/translate.
CREATIVE_SET scope. Creative sets involve asset/media selection beyond a single id — confirm what the API expects before supporting that type, or restrict the first cut to the product-page creative types.
Acceptance criteria
Context
Follows #32 (read-only v5 surfacing) and #30 (asa-api-client 0.2.1 adoption).
Summary
The
adscommand group added in #32 (PR #34) is read-only (list/get). Theasa-api-clientlibrary actually supports full ad CRUD — this issue tracks adding the write operations.Ad creation was deliberately deferred from #32 because, unlike the other v5 resources, it's a real feature with meaningful UX decisions (creative type selection, CPP linking), not just a surfacing pass.
Library surface (already available)
client.campaigns(c).ad_groups(a).adsinherits base CRUD:create(AdCreate) -> Adupdate(ad_id, AdUpdate) -> Addelete(ad_id) -> NoneModels:
Proposed commands
asa ads create -c <campaign> -a <ad-group> --name <name> --creative-type <type> [--product-page <id>] [--status ENABLED|PAUSED]asa ads update <ad-id> -c <campaign> -a <ad-group> [--name <name>] [--status ...]asa ads delete <ad-id> -c <campaign> -a <ad-group> [--yes]Design considerations
CUSTOM_PRODUCT_PAGErequires--product-page <id>;DEFAULT_PRODUCT_PAGE/CREATIVE_SETmust not take one. Validate this combination client-side with a clear error rather than letting the API 400.--product-pageids come fromasa product-pages list(already shipped) — cross-reference in help text. Consider validating the CPP belongs to the campaign's app.deleteshould confirm (reuseconfirm_action, with--yesto skip);createcould support--dry-runto preview the payload, consistent withoptimize/translate.CREATIVE_SETscope. Creative sets involve asset/media selection beyond a single id — confirm what the API expects before supporting that type, or restrict the first cut to the product-page creative types.Acceptance criteria
create,update,deleteimplemented following existing typer/utilsconventionsdeleteconfirmation +--yes;create--dry-runmypy --strict,ruff, and tests green; help/registration tests addedContext
Follows #32 (read-only v5 surfacing) and #30 (asa-api-client 0.2.1 adoption).