Update Ad Campaign
PUT /ad-campaigns/{campaign_id}
Edit a LIVE campaign: budget, schedule, creative, keywords, ad copy, targeting, pause or resume.
Omitted fields are left alone; an unknown field is a 422 (the app’s model
forbids extras, so a typo cannot silently do nothing). Read
GET /ad-campaigns/{campaign_id}/editable first - the platform refuses
some changes on some campaign types and states.
A 200 is NOT blanket success: the response status is partial whenever
any single change failed, and changes[] says which.
Authorizations
Parameters
Path Parameters
The ad campaign’s id.
The ad campaign’s id.
Header Parameters
Request Body required
Body for PUT /campaigns/{id} and POST /campaigns/{id}/edit-preview.
extra="forbid" is load-bearing (PRD hazard H8): the model used to inherit
Pydantic’s default extra="ignore", so the wizard could POST a field the
backend had never wired, get a 200, and render a green “Campaign updated”
toast for an edit that reached nothing. An unknown field is now a 422 —
a phantom control is structurally impossible to ship.
List-shaped fields (keywords, rsa_headlines, rsa_descriptions,
geo_targets) are COMPLETE desired lists, never deltas. Google replaces
repeated fields wholesale, so a partial list silently deletes the omitted
entries; the handler read-modify-writes against the platform’s current state.
None means “not provided / unchanged” — an empty list is a real request
to clear, and is rejected where clearing would break the ad.
object
object
object
Responses
200
Successful Response
object
One ad-platform object, or one handler response.
object
object
Whether there are more pages
Items per page
Current page number (1-indexed)
Total number of items
422
Validation Error