Create a Custom Audience
Creates a Custom Audience. The body holds the fields of the new Custom Audience.
It starts a Mutation of the kind meta_create_custom_audience, the same change that POST /mutations starts with that kind. The MCP tool of the same name makes the same change.
Create a Meta Custom Audience. source selects what makes the audience: website (the visitors of a Pixel) or lookalike (the people most like another audience, in one country). A Custom Audience has no status and starts no spend. An ad set uses it with customAudiences or excludedCustomAudiences. Meta can take some hours to populate a new audience, and a lookalike stays unusable until then.
The change does not happen during this request. The answer is 202, and Location names the Mutation. Poll GET /mutations/{id} until it reports complete or errored. 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.
/mutations/{advertiserId}/custom-audiencesAuthorizationBearer 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.
advertiserIdstringrequiredapplication/jsonexcludeEventsstring[]The Pixel events whose people the audience excludes, as the Pixel sends them, for example StartTrial or Purchase. A person who sent one of these events in the retention window is not in the audience. The events of a Pixel show which names it sends.
namestringrequiredThe name of the Custom Audience. It is visible in Meta Ads Manager.
pixelIdstringrequiredThe Meta id of the Pixel whose visitors make the audience, digits only. Find it with the Pixels read of AdCrunch.
retentionDaysintegerrequiredHow many days a person stays in the audience after a visit, from 1 to 180. Meta also adds the visits from before the create, up to this many days back.
sourcestringrequiredThe visitors of a Pixel make the audience.
websiteurlContainsstring[]The texts that the URL of a visited page contains, for example adcrunch.dev/pricing. A visitor of one page that contains one of the texts or more is in the audience. Meta compares with no regard to case. Omit it to include each visitor of the Pixel.
countrystringrequiredThe country of the people of the lookalike, as a two-letter ISO 3166-1 alpha-2 code in capitals, for example US. One country only.
namestringrequiredThe name of the Custom Audience. It is visible in Meta Ads Manager.
originAudienceIdstringrequiredThe Meta id of the Custom Audience to start from (the seed), digits only. Find it with the Custom Audiences read of AdCrunch. Meta needs at least 100 people of the seed in the country, and refuses a seed that is too small or that it flagged.
percentintegerrequiredThe share of the people of the country in the lookalike, from 1 to 10 percent. 1 holds the people most like the seed. A greater percent reaches more people who are less like the seed.
sourcestringrequiredThe people most like those of another Custom Audience make the audience.
lookalikeThe Mutation started, and it has not ended. The body is the answer of GET /mutations/{id}, with status of running. Poll the path in Location for the outcome.
mutationIdstringrequiredThe id of the Mutation, for example mut_k3x9q2v7m4n8p1r5t6w0y2z4. A start answers it, and also gives the path to poll in Location. A Mutation that started before the mut_ prefix keeps its UUID id.
priorValueobjectThe values that the change replaced, read from the provider just before the change. It uses the field names and the units of action, for example {"dailyBudget": 800}, {"status": "ACTIVE"}, {"bidStrategy": "COST_CAP", "costCap": 4}, {"startTime": "2026-10-01T00:00:00+0200", "endTime": null} or {"name": "Spring sale"}. To undo the change, send the same kind again with these values. A bid change on a campaign also gives the amount of each ad set in adsets: undo it on each ad set. A create and a copy have none.
resultanyHow the change ended. Present only when status is complete. ok of true carries what the provider gave back: a create carries the new object id, a copy carries the id of the copy and the budget that the copy carries, and every other action carries success. The budget is {"dailyBudget": 50} or {"lifetimeBudget": 500} in whole units of the account currency, "campaign" for an ad set copy that spends the budget of its campaign, or "adset" for a campaign copy whose ad sets each carry a budget. A schedule change also carries deliveryStartsAgain of true when it gave an ACTIVE ad set that had ended a new end: the ad set then delivers again. ok of false is a refusal, with a stable error code and a sentence: a provider refusal, or, for a change that an AI agent started through MCP, rejected (a person rejected it in the console) or expired (nobody confirmed it within 24 hours). After rejected or expired, nothing changed at the provider.
statusstringrequiredrunning means poll again. awaiting_confirmation means a person must confirm the change in the AdCrunch console first: only a change that an AI agent started through MCP waits, never one started through this API. complete means the change finished, and result says how it ended. errored means the Mutation itself broke down, and AdCrunch cannot say whether the change happened.
runningawaiting_confirmationcompleteerroredThe 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 organization has no active subscription. An owner subscribes at paywallUrl. error is organization_unentitled.
paywallUrlstring<uri>requiredThe page where an owner of the organization subscribes. Show it to the person.
errorstringrequiredA stable code for the failure. This is the field to branch on. It does not change for a given failure.
organization_unentitledmessagestringrequiredA 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.