Catalog ads
Run Advantage+ catalog ads from a Meta product catalog with goal catalog_sales, and find the catalog and product set to promote.
Promote items from a Meta product catalog with goal: "catalog_sales" on POST /v1/ads/create.
One ad covers N items. Meta renders the visuals per catalog item and picks which product or vehicle each person sees.
Before you start
You need the same accountId and adAccountId as any other create. The ad account needs a pixel.
Catalog contents live in Meta Commerce Manager or a feed provider. Zernio reads the catalogs and runs ads on them; it does not edit items.
Find the catalog and product set
Two discovery endpoints find the catalog and the product set first.
Catalogs hang off the ad account's business. Call GET /v1/ads/catalogs to list them.
import Zernio from '@zernio/node';
const zernio = new Zernio();
const { data: catalogs } = await zernio.productcatalogs.listAdCatalogs({
query: { accountId: '66b2e19d8c3f5a7e9d0b1c2d', adAccountId: 'act_1234567890' }
});
const catalogId = catalogs.catalogs[0].id;Response (200):
{
"catalogs": [
{ "id": "1003405825408877", "name": "Vehicle inventory", "vertical": "vehicles", "productCount": 132 }
]
}Then list that catalog's product sets. The product set, not the catalog, is what the ad promotes.
const { data: sets } = await zernio.productcatalogs.listAdCatalogProductSets({
path: { catalogId: '1003405825408877' },
query: { accountId: '66b2e19d8c3f5a7e9d0b1c2d' }
});
const productSetId = sets.productSets[0].id;Response (200):
{
"productSets": [
{ "id": "1003260032095191", "name": "All vehicles", "productCount": 132 }
]
}Create the catalog campaign
goal: "catalog_sales" builds the whole chain:
- a Sales-objective campaign
- an ad set bound to the product set
- a catalog template creative
There is no imageUrl and no video, because Meta renders the visuals from the catalog items.
The copy fields become the template, so each rendered item carries its own data. They accept Meta's catalog template tags:
{{product.name}},{{product.price}}- on a vehicle catalog,
{{vehicle.make}},{{vehicle.model}},{{vehicle.year}},{{vehicle.price}}
const { data: created } = await zernio.adcampaigns.createStandaloneAd({
body: {
accountId: '66b2e19d8c3f5a7e9d0b1c2d',
adAccountId: 'act_1234567890',
name: 'Vehicle inventory, catalog',
goal: 'catalog_sales',
budgetAmount: 30,
budgetType: 'daily',
headline: '{{vehicle.year}} {{vehicle.make}} {{vehicle.model}}',
body: 'Find your next car',
description: '{{vehicle.price}}',
callToAction: 'LEARN_MORE',
linkUrl: 'https://example.com/inventory',
countries: ['US'],
optimizationGoal: 'OFFSITE_CONVERSIONS',
promotedObject: {
productSetId: '1003260032095191',
pixelId: '1729525464415281',
customEventType: 'PURCHASE'
}
}
});Response (201), trimmed:
{
"ad": {
"_id": "66d4a1b2c3e4f5a6b7c8d9e6",
"status": "pending_review",
"goal": "catalog_sales",
"platformObjective": "OUTCOME_SALES",
"optimizationGoal": "OFFSITE_CONVERSIONS",
"promotedObject": {
"productSetId": "1003260032095191",
"pixelId": "1729525464415281",
"customEventType": "PURCHASE"
}
}
}All 3 promotedObject fields are required.
Meta's "Promoted Object is Required" error on a catalog ad set usually means the pixel is missing, not the product set.
How it behaves
Targeting works like any other campaign: countries, age, gender, placements and saved audiences all apply.
Broad targeting is fine here, because Meta matches items to people. Layer retargeting off pixel events with optimizationGoal: "OFFSITE_CONVERSIONS".
The ad set optimization defaults to LINK_CLICKS, which would buy clicks for a campaign asking Meta for purchases. Send the top-level optimizationGoal: "OFFSITE_CONVERSIONS", as the sample does.
That optimizes toward the customEventType in promotedObject (conversion campaigns).
catalog_sales is a single-creative shape. It cannot be combined with creatives[], adSetId, dynamicCreative or placementAssets, because the catalog template is already the multi-item mechanism.
Catalog creatives need an explicit Instagram identity for Instagram placements. When the connected Page has no linked Instagram account, Zernio falls back to the Page-backed one.
Meta has retired the legacy PRODUCT_CATALOG_SALES objective on modern ad accounts, so Zernio uses the current Sales-objective shape.
If it fails
A 400 names the field that conflicts with the catalog shape:
{
"error": "creatives is not supported with goal catalog_sales",
"type": "invalid_request_error",
"param": "creatives"
}Send one creative.
Zernio checks promotedObject.productSetId before creating anything. These return a precise 400 naming promotedObject.productSetId, rather than a raw Meta error:
- the catalog id passed where the product set id belongs
- a set the token cannot read
A productCatalogId that does not contain the set names promotedObject.productCatalogId instead.
If the catalog or product set id belongs to another business, Meta's own 400 comes back inside platformError. Re-read the ids from the two discovery calls above.
Related
- Campaigns: the base create request.
- Conversion campaigns: every
promotedObjectkey. - Pixels: create the pixel a catalog ad set needs.
- List catalogs and List product sets: every field.
Conversion campaigns
Optimize a Meta campaign toward a pixel event, an instant form or an app install by adding a promotedObject to the create request.
Messaging & call ads
Create Meta ads that open a WhatsApp, Messenger or Instagram Direct conversation with POST /v1/ads/messaging, or dial a number with POST /v1/ads/call.