Start a mutation
Starts a change on a live advertiser and answers immediately.
The change does not happen during this request. The answer carries a workflowId. Poll GET /mutations/{id} with it to find out how the change ended. A Mutation is durable, so the id stays valid across retries and restarts.
A refused request starts nothing. AdCrunch refuses a body that does not match, an advertiser that is not yours, an advertiser with no usable connection, and an advertiser connected without write access before a Mutation exists. So a failed call leaves no row in the history.
This operation checks the credential first and the body second. A missing or unusable credential answers 401 even when the body is wrong as well. A body that does not match then answers 400 with error of invalid_request, and issues names each field.
A create never starts delivery: a campaign, an ad set and an ad all arrive paused, and so does a copy of a campaign or an ad set. This API also cannot delete, so meta_set_status with ARCHIVED is how an object is retired.
/mutationsAuthorizationBearer token · headerrequiredSend Authorization: Bearer <credential>.
Use an API key (acr_…), from the AdCrunch console under Settings → API keys.
The credential names the organization, and no operation takes an organization parameter.
See https://docs.adcrunch.dev/api/authentication.
application/jsonactionobjectrequiredWhat to do. The kind field selects the action, and each kind takes its own fields.
Show propertiesHide properties
idstringrequiredThe Meta id of the object to change: the native id, digits only, not an AdCrunch id. The object must be in the ad account of the advertiser, else the change ends with not_found.
kindstringrequiredmeta_set_statuslevelstringrequiredWhich object the id refers to.
campaignadsetadstatusstringrequiredThe status to set. ACTIVE starts delivery and starts spend. PAUSED stops delivery and can be reversed. ARCHIVED retires the object, and on Meta it is close to one-way: you cannot make an archived object active again from this API. Archive is the only way to retire an object, because this API never deletes one.
ACTIVEPAUSEDARCHIVEDdailyBudgetnumberThe amount to spend each day. The amount is in whole units of the ad account currency: 10.5 is 10.50. Meta refuses more decimals than the currency has, and it counts some currencies, such as JPY and HUF, with none. Give a daily budget or a lifetime budget, not both. To change a daily budget to a lifetime budget, first set an end time with meta_update_schedule, then set the lifetime budget. To change a lifetime budget to a daily budget, first set the daily budget, then remove the end time with meta_update_schedule. Meta refuses a lifetime budget with no end time.
idstringrequiredThe Meta id of the campaign or ad set to change: the native id, digits only, not an AdCrunch id. The object must be in the ad account of the advertiser, else the change ends with not_found.
kindstringrequiredmeta_update_budgetlevelstringrequiredWhich object the id refers to. An ad has no budget of its own.
campaignadsetlifetimeBudgetnumberThe amount to spend across the whole schedule. The amount is in whole units of the ad account currency: 10.5 is 10.50. Meta refuses more decimals than the currency has, and it counts some currencies, such as JPY and HUF, with none. A lifetime budget needs an end time on the ad set. To change a daily budget to a lifetime budget, first set an end time with meta_update_schedule, then set the lifetime budget. To change a lifetime budget to a daily budget, first set the daily budget, then remove the end time with meta_update_schedule. Meta refuses a lifetime budget with no end time.
endTimestring | nullWhen delivery stops, as an ISO 8601 timestamp in the future, for example 2026-12-31T23:59:00+01:00. Send null for no end. An ad set with a lifetime budget must keep an end time. A later end time adds days of spend, so the total spend of a daily budget increases. With no end, the ad set spends until you pause it, up to 7 times its daily budget in one week. With a lifetime budget, the total spend stays within the lifetime budget. An ACTIVE ad set that has ended delivers again when it gets a new end time or no end, with no status change. To change a daily budget to a lifetime budget, first set an end time with meta_update_schedule, then set the lifetime budget. To change a lifetime budget to a daily budget, first set the daily budget, then remove the end time with meta_update_schedule. Meta refuses a lifetime budget with no end time.
idstringrequiredThe Meta id of the ad set to change: the native id, digits only, not an AdCrunch id. The ad set must be in the ad account of the advertiser, else the change ends with not_found. A campaign has no schedule that this API can change.
kindstringrequiredmeta_update_schedulestartTimestringWhen delivery starts, as an ISO 8601 timestamp. Meta gets it as you send it, also on an ad set that has started, and Meta decides what it does. Give startTime, endTime, or both.
adsetBudgetSharingbooleanLet the ad sets share their budgets. Only when both campaign budgets are omitted; false when omitted. Each ad set can then share up to 20 % of its daily budget with the other ad sets of the campaign. Sharing works with daily budgets only. It needs a bidStrategy, and it locks that bid strategy for the life of the campaign. Sharing cannot be turned on later.
bidStrategystringHow Meta bids. LOWEST_COST_WITHOUT_CAP ("Highest volume" in Ads Manager) gets the most results for the budget and takes no amount. LOWEST_COST_WITH_BID_CAP ("Bid cap") takes bidCap. COST_CAP ("Cost per result goal") takes costCap. LOWEST_COST_WITH_MIN_ROAS ("ROAS goal") takes roasFloor, and needs the optimization goal VALUE. Give exactly the amount that the strategy takes, and no other amount. A higher bid cap, a higher cost cap or a lower ROAS floor can make an ad set spend its full budget, never more. On a campaign, give only the strategy. It applies when the campaign carries a budget, or when adsetBudgetSharing is true, which requires it. Give the amount of a bid cap, a cost cap or a ROAS goal on each ad set, with the same bidStrategy. Omit it to let Meta apply its default strategy.
LOWEST_COST_WITHOUT_CAPLOWEST_COST_WITH_BID_CAPCOST_CAPLOWEST_COST_WITH_MIN_ROASdailyBudgetnumberThe amount the campaign spends each day, shared across its ad sets. The amount is in whole units of the ad account currency: 10.5 is 10.50. Meta refuses more decimals than the currency has, and it counts some currencies, such as JPY and HUF, with none. Give one of the two budgets, or neither. When each ad set carries its own budget, for example one ad set for each Line Item, omit both budgets.
kindstringrequiredmeta_create_campaignlifetimeBudgetnumberThe amount the campaign spends across its whole schedule, shared across its ad sets. The amount is in whole units of the ad account currency: 10.5 is 10.50. Meta refuses more decimals than the currency has, and it counts some currencies, such as JPY and HUF, with none. Give one of the two budgets, or neither. When each ad set carries its own budget, for example one ad set for each Line Item, omit both budgets.
namestringrequiredThe campaign name. It is visible in Meta Ads Manager.
objectivestringrequiredThe result the campaign optimizes for. It cannot be changed after the campaign is created, and it limits which optimization goals the ad sets below it can use.
OUTCOME_AWARENESSOUTCOME_ENGAGEMENTOUTCOME_LEADSOUTCOME_SALESOUTCOME_TRAFFICOUTCOME_APP_PROMOTIONspecialAdCategoriesstring[]requiredDeclare a regulated category when the campaign advertises one: EMPLOYMENT, HOUSING, CREDIT, ISSUES_ELECTIONS_POLITICS, ONLINE_GAMBLING_AND_GAMING, or FINANCIAL_PRODUCTS_SERVICES. Meta restricts targeting for each of them, and a wrong declaration breaks the advertiser policy agreement. Send an empty array or NONE when none applies. Do not guess: ask the advertiser.
ageMaxintegerThe oldest age to target, from 13 to 65. Omit it to target every age above the minimum. 65 and above is one group on Meta.
bidCapnumberThe highest bid Meta places in an auction. Only with LOWEST_COST_WITH_BID_CAP. A bid is per optimization event, for example per purchase, and per 1,000 impressions when the optimization goal is IMPRESSIONS or REACH. The amount is in whole units of the ad account currency: 2.5 is 2.50. Meta refuses more decimals than the currency has.
costCapnumberThe average cost per result that Meta tries to keep. Only with COST_CAP. A bid is per optimization event, for example per purchase, and per 1,000 impressions when the optimization goal is IMPRESSIONS or REACH. The amount is in whole units of the ad account currency: 2.5 is 2.50. Meta refuses more decimals than the currency has. A cost cap can stop the ad set before it spends its full budget.
roasFloornumberThe lowest return on ad spend that Meta bids for, as a ratio: 1.5 means purchase value of 1.5 times the spend. Only with LOWEST_COST_WITH_MIN_ROAS. From 0.01 to 1000, with at most 4 decimals.
bidStrategystringHow Meta bids. LOWEST_COST_WITHOUT_CAP ("Highest volume" in Ads Manager) gets the most results for the budget and takes no amount. LOWEST_COST_WITH_BID_CAP ("Bid cap") takes bidCap. COST_CAP ("Cost per result goal") takes costCap. LOWEST_COST_WITH_MIN_ROAS ("ROAS goal") takes roasFloor, and needs the optimization goal VALUE. Give exactly the amount that the strategy takes, and no other amount. A higher bid cap, a higher cost cap or a lower ROAS floor can make an ad set spend its full budget, never more. When the campaign carries the budget, or shares the ad set budgets, the campaign holds the strategy: give the same bidStrategy here, with the amount for this ad set. Omit it, with every amount, to let Meta apply its default strategy.
LOWEST_COST_WITHOUT_CAPLOWEST_COST_WITH_BID_CAPCOST_CAPLOWEST_COST_WITH_MIN_ROASageMinintegerrequiredThe youngest age to target, from 13 to 65. This field is required, and it is the one targeting field with no default. Many advertisers must not show ads to people under 18, and a default would spend their money on an audience they cannot legally address. State the age deliberately: send 18 to exclude minors.
campaignIdstringrequiredThe Meta id of the campaign this ad set belongs to, digits only. Create the campaign first and use the id it returns.
countriesstring[]requiredThe countries to target, as two-letter ISO 3166-1 alpha-2 codes, for example US or GB. Give at least one.
customEventTypestringThe conversion the pixel reports, for example PURCHASE. Required with a conversion optimization goal, and it must be sent together with pixelId.
PURCHASELEADCOMPLETE_REGISTRATIONADD_TO_CARTINITIATED_CHECKOUTADD_PAYMENT_INFOVIEW_CONTENTSEARCHSUBSCRIBESTART_TRIALCONTACTOTHERdailyBudgetnumberThe amount this ad set spends each day. The amount is in whole units of the ad account currency: 10.5 is 10.50. Meta refuses more decimals than the currency has, and it counts some currencies, such as JPY and HUF, with none. Omit both budgets when the campaign carries one. When the campaign carries none, give exactly one.
endTimestringWhen delivery stops, as an ISO 8601 timestamp. Required with a lifetime budget.
gendersstringrequiredWhich genders to target. The default targets everybody.
allmenwomenkindstringrequiredmeta_create_adsetlifetimeBudgetnumberThe amount this ad set spends across its whole schedule. The amount is in whole units of the ad account currency: 10.5 is 10.50. Meta refuses more decimals than the currency has, and it counts some currencies, such as JPY and HUF, with none. It needs an end time.
namestringrequiredThe ad set name. It is visible in Meta Ads Manager.
optimizationGoalstringrequiredWhat Meta optimizes delivery for. The campaign objective limits which goals are valid. A conversion goal also needs pixelId and customEventType. The billing event follows from this goal, so there is no separate field for it.
IMPRESSIONSREACHLINK_CLICKSLANDING_PAGE_VIEWSOFFSITE_CONVERSIONSPOST_ENGAGEMENTTHRUPLAYLEAD_GENERATIONVALUEpixelIdstringThe Meta pixel that reports conversions. Required with a conversion optimization goal. AdCrunch can list the pixels this ad account can use.
startTimestringWhen delivery starts, as an ISO 8601 timestamp. Omit it to start when the ad set becomes active. The ad set is created paused either way.
adsetIdstringrequiredThe Meta id of the ad set this ad runs in, digits only. Create the ad set first and use the id it returns.
creativeIdstringrequiredThe Meta id of the creative this ad shows, digits only. Create the creative first with meta_create_creative and use the id it returns. One creative can be used by more than one ad.
kindstringrequiredmeta_create_adnamestringrequiredThe ad name. It is visible in Meta Ads Manager.
assetIdstringrequiredThe AdCrunch Asset to build the creative from, as the ast_ id that Asset registration returned. The Asset must already be registered to this advertiser. Do not send a Meta image hash or video id. Whether the creative becomes an image or a video follows from the Asset.
callToActionstringrequiredThe label on the button, for example SHOP_NOW.
LEARN_MORESHOP_NOWSIGN_UPBOOK_TRAVELDOWNLOADGET_OFFERGET_QUOTECONTACT_USSUBSCRIBEAPPLY_NOWNO_BUTTONdescriptionstringThe text below the headline. Meta can truncate it.
headlinestringrequiredThe short bold line next to the button.
kindstringrequiredmeta_create_creativelinkstring<uri>requiredThe page the ad opens when somebody clicks it.
messagestringrequiredThe main body text, shown above the media.
namestringrequiredThe creative name. It is visible in Meta Ads Manager, and it is not shown to a person who sees the ad.
pageIdstringrequiredThe Facebook Page the ad is published from. AdCrunch can list the Pages this ad account can publish from.
bidCapnumberThe highest bid Meta places in an auction. Only with LOWEST_COST_WITH_BID_CAP. A bid is per optimization event, for example per purchase, and per 1,000 impressions when the optimization goal is IMPRESSIONS or REACH. The amount is in whole units of the ad account currency: 2.5 is 2.50. Meta refuses more decimals than the currency has.
costCapnumberThe average cost per result that Meta tries to keep. Only with COST_CAP. A bid is per optimization event, for example per purchase, and per 1,000 impressions when the optimization goal is IMPRESSIONS or REACH. The amount is in whole units of the ad account currency: 2.5 is 2.50. Meta refuses more decimals than the currency has. A cost cap can stop the ad set before it spends its full budget.
roasFloornumberThe lowest return on ad spend that Meta bids for, as a ratio: 1.5 means purchase value of 1.5 times the spend. Only with LOWEST_COST_WITH_MIN_ROAS. From 0.01 to 1000, with at most 4 decimals.
bidStrategystringrequiredHow Meta bids. LOWEST_COST_WITHOUT_CAP ("Highest volume" in Ads Manager) gets the most results for the budget and takes no amount. LOWEST_COST_WITH_BID_CAP ("Bid cap") takes bidCap. COST_CAP ("Cost per result goal") takes costCap. LOWEST_COST_WITH_MIN_ROAS ("ROAS goal") takes roasFloor, and needs the optimization goal VALUE. Give exactly the amount that the strategy takes, and no other amount. A higher bid cap, a higher cost cap or a lower ROAS floor can make an ad set spend its full budget, never more. Send the strategy also to change only an amount. A change of strategy starts the learning phase again, and a large change of amount can too. Meta refuses a change of strategy on a campaign with ad set budget sharing, on a campaign budget with more than 70 ad sets, and on a campaign budget on ROAS goal. Meta advises at most 2 or 3 bid or budget changes a day, and 15 minutes between a budget change and a bid change.
LOWEST_COST_WITHOUT_CAPLOWEST_COST_WITH_BID_CAPCOST_CAPLOWEST_COST_WITH_MIN_ROASidstringrequiredThe Meta id of the campaign or ad set to change: the native id, digits only, not an AdCrunch id. The object must be in the ad account of the advertiser, else the change ends with not_found.
kindstringrequiredmeta_update_biddinglevelstringrequiredWhich object the id refers to. The strategy sits where the budget sits: on the campaign under a campaign budget, otherwise on each ad set. Under a campaign budget, an ad set takes only its amount: send the bidStrategy of the campaign with the amount for this ad set. Another strategy ends with wrong_level. A campaign without a campaign budget ends with wrong_level. On a campaign, a bid cap or a cost cap applies one amount to every ad set of the campaign. A ROAS floor sits on each ad set: on a campaign, LOWEST_COST_WITH_MIN_ROAS is refused.
campaignadsetidstringrequiredThe Meta id of the campaign to copy: the native id, digits only, not an AdCrunch id. The campaign must be in the ad account of the advertiser, else the copy ends with not_found. The copy stays in that ad account.
kindstringrequiredmeta_copy_campaigncampaignIdstringThe Meta id of the campaign that receives the copy, digits only. Omit it to keep the copy in the campaign of the source. The copy takes the settings of that campaign: under a campaign budget, it spends the campaign budget. Meta decides whether the campaign accepts the copy.
endTimestringWhen delivery of the copy stops, as an ISO 8601 timestamp. Omit it to keep the end time of the source.
idstringrequiredThe Meta id of the ad set to copy: the native id, digits only, not an AdCrunch id. The ad set must be in the ad account of the advertiser, else the copy ends with not_found.
kindstringrequiredmeta_copy_adsetstartTimestringWhen delivery of the copy starts, as an ISO 8601 timestamp. Omit it to keep the start time of the source. A copy of an ad set that has ended starts when Meta makes it, with the duration of the source.
idstringrequiredThe Meta id of the object to rename: the native id, digits only, not an AdCrunch id. The object must be in the ad account of the advertiser, else the rename ends with not_found.
kindstringrequiredmeta_renamelevelstringrequiredWhich object the id refers to.
campaignadsetadnamestringrequiredThe new name, which replaces the whole name. It is visible in Meta Ads Manager.
advertiserIdstringrequiredThe advertiser to act on, as an AdCrunch acc_ id. It must belong to your organization and be connected with write access.
The Mutation started. Poll it for the outcome.
workflowIdstringrequiredThe id of the Mutation. Poll GET /mutations/{id} with it to find out whether the change succeeded.
The request does not match the schema of this operation: a field is missing or has the wrong type, or the body is not valid JSON. error is invalid_request, and issues names each field. Nothing was changed.
issuesobject[]requiredOne entry for each field that does not match.
Show propertiesHide properties
objectinstringrequiredThe part of the request that holds the field.
bodycookieheadersparamsquerymessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
pathstringrequiredA JSON Pointer into that part of the request, such as /filename. An empty string is the whole part.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
invalid_requestmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
No API key, or one that does not resolve. See the security scheme. error is unauthorized.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
unauthorizedmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
The caller does not hold mutation:write, or the advertiser is connected without write access. In the second case error is missing_write_access and message says how to fix it. AdCrunch started nothing.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
forbiddenmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
missing_write_accessmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
The advertiser does not exist, it belongs to another organization, or it is not a Meta ad account. error is not_found in each case. An advertiser that does not exist and an advertiser of another organization get the same answer on purpose, so a caller cannot learn which ids exist. AdCrunch started nothing.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
not_foundmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
The advertiser has no usable connection: a person removed it, it expired, or the provider refused it. A person must connect it again. error is provider_not_connected, the code that a live read of Observe sends for the same failure. AdCrunch started nothing.
providerstringrequiredThe ad platform of the advertiser. It is meta today.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
provider_not_connectedmessagestringrequiredA sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.