Update an ad set
Ad-set-level writes. Use this for ABO budget updates, ad-set-scoped
pause/resume, bid-strategy edits, Meta value-rule-set attach/detach, and
Meta-only post-launch delivery settings via platformSpecificData. At
least one updatable field is required.
Value rule sets (Meta only, see /v1/ads/value-rule-sets):
- ATTACH or REPLACE: send
valueRuleSetId. Attachment is driven by the id's presence, sovalueRulesApplied: trueis optional. Sending a different id replaces the previous association; there is no separate replace call. - DETACH: send
valueRulesApplied: falseand OMITvalueRuleSetId. - Sending
valueRulesApplied: falseTOGETHER withvalueRuleSetIdreturns 400mutually_exclusive_fields. This is deliberate: Meta attaches the rule set whenevervalue_rule_set_idis present, even withvalue_rules_appliedfalse, so echoing stored state while asking to detach would silently keep the bid adjustments live. - Eligibility: only ad sets on
LOWEST_COST_WITHOUT_CAPorCOST_CAP. Meta rejects the rest server-side. - Read back with
GET /v1/ads/ad-sets/{adSetId}?fields=value_rule_set_id. Meta does not documentvalue_rules_appliedas a readable ad-set field, so the boolean cannot be read back.
Bid strategy compatibility (per Meta's spec):
LOWEST_COST_WITHOUT_CAP: nobidAmount, noroasAverageFloor.LOWEST_COST_WITH_BID_CAP/COST_CAP:bidAmountREQUIRED (whole currency units).LOWEST_COST_WITH_MIN_ROAS:roasAverageFloorREQUIRED (decimal multiplier, e.g. 2.0 = 2.0x ROAS).- Meta only: send
bidAmountWITHOUTbidStrategyto change the cap amount on an ad set under a COST_CAP / LOWEST_COST_WITH_BID_CAP parent campaign, leaving the strategy itself (inherited from the campaign) untouched.roasAverageFloorwithoutbidStrategyis rejected (it has no meaning outside LOWEST_COST_WITH_MIN_ROAS).
Delivery settings are validated by Meta against the campaign objective; incompatible combinations (e.g. a billingEvent the optimization goal doesn't allow) surface as 400s from Meta.
When updating budget on an ABO campaign: if the parent campaign is
CBO, the response is 409 with code BUDGET_LEVEL_MISMATCH — route to
PUT /v1/ads/campaigns/{campaignId} instead.
API key authentication - use your Zernio API key as a Bearer token
In: header
Path Parameters
Platform ad set ID
"facebook" | "instagram" | "tiktok" | "linkedin" | "pinterest" | "google" | "twitter" | "openai"Omit if not updating budget
Omit if not toggling delivery state
"active" | "paused"Rename the ad set (Meta only; other platforms return 501). At least one of budget/status/bidStrategy/name is required.
length <= 255"LOWEST_COST_WITHOUT_CAP" | "LOWEST_COST_WITH_BID_CAP" | "COST_CAP" | "LOWEST_COST_WITH_MIN_ROAS"Bid cap in WHOLE currency units (USD: 5 = $5.00; JPY: 100 = ¥100). Required when bidStrategy is LOWEST_COST_WITH_BID_CAP or COST_CAP. Internally converted to Meta's smallest-denomination integer, or (on OpenAI) to micros (× 1,000,000). Meta only: may be sent alone, WITHOUT bidStrategy, to update the cap amount on an ad set whose parent campaign is COST_CAP or LOWEST_COST_WITH_BID_CAP (the strategy is inherited from the campaign and is left untouched).
Minimum ROAS as a decimal multiplier (2.0 = 2.0x). Required when bidStrategy is
LOWEST_COST_WITH_MIN_ROAS. Sent to Meta as bid_constraints.roas_average_floor × 10000.
Not supported on OpenAI (422).
Meta only (other platforms return 501). Value rule set to attach to this ad
set, from /v1/ads/value-rule-sets. Sending a different id replaces the
current association. To DETACH, send valueRulesApplied: false and omit
this field.
^\d+$Meta only (other platforms return 501). false DETACHES the ad set's value
rule set and must be sent WITHOUT valueRuleSetId; the combination returns
400. true is optional when attaching, since attachment is driven by
valueRuleSetId, and requires it to be present.
Platform-specific post-launch delivery settings. The platform is implied by the
platform body param. Meta only; other platforms return 400. Unknown keys are rejected.
Response Body
application/json
application/json
import Zernio from '@zernio/node';const zernio = new Zernio({ apiKey: process.env.ZERNIO_API_KEY });const { data } = await zernio.adcampaigns.updateAdSet({ path: { adSetId: 'adset_abc123', }, body: { platform: 'facebook', },});console.log(data);{
"budget": {
"amount": 0,
"type": "daily"
},
"budgetLevel": "adset",
"status": "active",
"statusUpdated": 0,
"statusSkipped": 0,
"bidStrategy": "LOWEST_COST_WITHOUT_CAP",
"bidAmount": 0,
"roasAverageFloor": 0,
"platformSpecificData": {}
}{
"error": "Unauthorized"
}Pause or resume a single ad set PUT
Ad-set-scoped pause/resume (doesn't touch sibling ad sets). Thin wrapper over PUT /v1/ads/ad-sets/{adSetId} for callers that only want the status toggle and prefer a symmetric URL to /v1/ads/campaigns/{campaignId}/status.
Pause or resume a single ad PUT
Ad-scoped pause/resume — touches ONLY this ad, never its parent ad set or campaign (so sibling ads keep running). Thin wrapper over the `status` field of PUT /v1/ads/{adId}, for callers that want a URL symmetric to /v1/ads/campaigns/{campaignId}/status and /v1/ads/ad-sets/{adSetId}/status. `{adId}` accepts the same identifier dialects as GET/PUT /v1/ads/{adId} (Zernio hex `_id`, Meta numeric `platformAdId`, or the creative's effective story/media IDs). `platform` is inferred from the ad, so it's not required in the body. Ads in terminal statuses (rejected, completed, cancelled) and no-op flips (already in the target state) are skipped.