X-Autopilot

X Dynamic Product Ads: what the feed never deletes

X Dynamic Product Ads run off a catalog that only ever adds. Here is what the Catalog API can do, what it cannot, and why access is still gated.

X-Autopilot Team··12 min read
On this page · 10 sections

The short version

  • ▸A scheduled feed import on X is additive. X states that removing products from the feed does not delete them from the catalog, so a sold-out or discontinued item keeps serving unless you call DELETE with X's own product keys. That delete is permanent and is the most tightly rate limited call in the Catalog API: 150 requests per 15 minutes, against 600 for upserts.
  • ▸The Catalog API was announced on 6 October 2022 as early access 'ahead of our broad launch in the coming months'. On 14 November 2026 the docs still say early-access only. Four developer forum threads asking for access, from April 2024 to October 2026, have zero replies between them.
  • ▸One user gets one catalog and one feed. X states plainly that one user can only create one catalog, and that only one product feed is supported per user. There is no multi-brand structure in the API.
  • ▸The endpoint that creates the actual ad creative, POST accounts/:account_id/dynamic_product_cards, appears exactly once in X's entire 4.86 MB documentation corpus: as a single curl line in a guide. It has no reference page, no parameter table and no response example.
  • ▸X's Ads UI recommends the Conversions objective for DPA. The API has no Conversions objective. The API guide requires objective WEBSITE_CLICKS with goal WEBSITE_CONVERSIONS, so the route the UI recommends cannot be built from code.

Quick answer

X Dynamic Product Ads build their creative from a product catalog instead of a hand-made card, and the single most expensive thing to know about them is that the feed is additive. X states it directly: removing products from the feed does not delete them from the catalog. Discontinued stock keeps serving until you issue an explicit delete, that delete is permanent, it is keyed on identifiers X generates rather than your SKUs, and it is rate limited four times harder than the upsert that created the problem. Everything else below is the gap between what X's Ads UI does and what the Catalog API, still early-access only four years after launch, will let you do.

Last updated: November 2026

Every number here was read on 14 November 2026 from X's own documentation, its flattened doc corpus at docs.x.com/llms-full.txt (4,858,201 bytes, which is how you prove how many times X says something), and the developer forum's JSON API.

The feed only ever adds

Scheduled feeds are the normal way to keep a catalog current: you host a CSV, TSV or XML file up to 8GB, X fetches it hourly, daily or weekly, and your products update themselves. One sentence in the reference changes how you have to design around that:

Importing a scheduled feed is an additive action - removing products from the feed does not delete them from the catalog.

So the mental model most advertisers import from other ad platforms is wrong here. Your feed is not the source of truth for what exists. It is a stream of upserts. Pull a product out of the file and nothing happens: the row stays in the catalog, stays eligible for any filtered product set whose rules it still matches, and stays renderable as a card.

Removing it takes DELETE product_catalogs/:product_catalog_id/products, and three things about that call matter:

  • It is permanent. X labels it "This is a permanent deletion." There is no soft delete and no undo.
  • It takes product_keys, not your IDs. The required body is an array of "unique product object identifiers generated by X". Your own SKU, the id you uploaded, will not do. If you did not store X's key when you created the product, you have to go find it through GET products first.
  • It is the throttled one. Catalog rate limits per 15 minutes: 1,000 for reading products, 600 for upserting them, 150 for deleting them. The operation you need in a hurry when a price is wrong or an item is pulled is the one with the smallest budget.

There is a second trap stacked on the first. Variants are grouped by item_group_id, and X notes that when you fetch products including grouped ones, "only the product that you submitted first will be returned". So a plain product listing does not hand you back the keys for every variant you uploaded.

Practical rule: persist X's product_key against your own SKU at upload time, every time. It is the only handle you get on a product that is already live.

Four years of early access

@AdsAPI announced the Catalog API on 6 October 2022, in a thread that has one post, 6,003 views and no replies:

Ahead of our broad launch in the coming months, you can gain early access to the new Catalog API by filling out this form.

Those coming months have now been four years and one month. The Catalog Management page as it stands on 14 November 2026 still reads: "Catalog API endpoints are currently available via early-access only. To apply for access, please reach out to your X representative or fill out the appropriate form." You also have to accept terms through X Shopping Manager at ads.x.com/shopping_manager.

What that gate feels like from the outside is documented, because people keep posting about it and nobody answers. Four threads, one reply between them, and that reply was the forum robot:

DateThreadReplies
2 April 2024401 on product_catalogs with Standard Ads API access granted0
15 April 2024Told to apply for Catalog API after Ads API approval0
18 April 2024Form submitted, no reply, what now0
18 October 2026Two months of requests, support stopped respondingauto-closed

Memorise the error they all hit so you recognise it instantly:

{"errors":[{"code":"UNAUTHORIZED_CLIENT_APPLICATION",
  "message":"The client application with id 28579244 making this request does not have access to this Ads API endpoint"}]}

That is not an auth bug. Ads API access and Catalog API access are separate grants on the same app, and the second one is granted by a human. The October 2026 reporter described the loop precisely: support sent them to a sales representative, the representative could not help, support then said it had done all it could and would stop replying, and the Google Form returned no confirmation email and no reference number. Fourteen days later the forum closed the thread automatically.

If you are scoping a build that depends on this, treat Catalog API access as a commercial conversation with an X representative, not an application you submit and wait on. Budget for the possibility that it does not arrive.

One user, one catalog, one feed

Three hard structural limits, each stated once:

  • "Currently, one user can only create one catalog." The catalog is tied to the handle.
  • "Only one product feed is supported per user."
  • Manual product sets hold up to 50 products; filtered sets take up to 30 filter rules.

There is no multi-brand or multi-market structure in the API. If you run three storefronts from one X account, they share one catalog and one feed, and separation has to happen through product sets and custom_label_0 through custom_label_4.

Endpoint inventory is small and slightly incomplete. Fifteen endpoints across four objects: 4 GET, 3 POST, 4 PUT, 4 DELETE. Two absences stand out. There is no POST products at all, because creation and update are the same PUT batch call, which upserts by id: "If we do not recognize the id, we create a new product." And the rate limit table lists a row for GET /product_catalogs/:product_catalog_id/product_sets at 2,000 per 15 minutes, but the reference has no list endpoint for product sets, only fetch-by-id. Every other row in that table deep-links a real endpoint anchor; that one links the section.

One more thing to know before you write the upload: product_key is marked required on PUT products and described as a "unique product object identifier generated by X". On a brand-new product, by definition, you do not have one. The create path and the required-field list cannot both be right, so expect to discover the real behaviour by calling it.

The endpoint that makes the ad is barely documented

Five steps make a DPA campaign: create campaign, create line item, create a DPA card, create a post carrying that card, promote the post against the line item. Step three is the one that renders products into creative, and here is its complete documentation, as it appears in X's corpus:

twurl -X POST -H ads-api.twitter.com -A "Content-Type: application/json" \
  "/12/accounts/{ADS_ACCOUNT_ID}/dynamic_product_cards" \
  -d '{"url": "{URL}", "creative_type": "{CREATIVE_TYPE}"}'

dynamic_product_cards appears once in 4.86 MB of documentation, in that line. No reference page, no parameter table, no response example, no error list. The guide tells you creative_type accepts CAROUSEL, SINGLE or COLLECTION and defaults to carousel, and that is the whole specification.

Step two is just as thin. A DPA line item needs catalog_id, product_set_id and creative_source=DYNAMIC_PRODUCT_CREATIVE. Search the Campaign Management API Reference, which is 256KB of parameter tables covering 87 endpoints, and catalog_id appears zero times, product_set_id zero times, and creative_source only inside response examples, always with the value MANUAL. DYNAMIC_PRODUCT_CREATIVE appears twice in the entire corpus, both times in the DPA guide.

So the three parameters that turn an ordinary line item into a product ad exist only as a bullet list in a tutorial. If you generate your client from the reference, as any sensible toolchain does, it will not know they exist. Our breakdown of X Ads API campaigns covers the rest of that reference, including the two ceilings it states twice.

Two cosmetic oddities in the same guide, both harmless once you see them. It still instructs that the card URL "must start with https://twitter.com", and steps three through five point at the legacy ads-api.twitter.com host while steps one and two use ads-api.x.com. I checked both hosts on 14 November 2026: they resolve to the same address and return the identical {"errors":[{"message":"Bad Authentication data","code":215}]} unauthenticated, so the legacy host still answers. Copy the sequence, not the hostnames.

The objective the UI recommends does not exist in the API

X's help page for building a DPA campaign in the Ads UI says you create it "under the Conversions (recommended) or Website Traffic objectives".

Its API has eight objective values, in full: APP_ENGAGEMENTS, APP_INSTALLS, FOLLOWERS, ENGAGEMENTS, REACH, VIDEO_VIEWS, PREROLL_VIEWS, WEBSITE_CLICKS. There is no Conversions objective. There never has been one in this enum.

What the DPA guide does instead is bolt the conversion goal onto the traffic objective. Its own instructions:

  • objective should always be WEBSITE_CLICKS
  • goal should always be WEBSITE_CONVERSIONS
  • primary_web_event_tag is required, because the reference makes that tag mandatory whenever the goal is WEBSITE_CONVERSIONS

Above those bullets, the section heading reads "Create line item with Sales objective", which is a third name for the same thing and matches neither the enum nor the UI. The bullets are right; the heading is a label.

Getting that primary_web_event_tag is its own prerequisite: X requires either the X Pixel or the Conversions API on your site, firing Page View, Content View, Add to Cart and Purchase. If you have not built that yet, start with X Conversion API, because no amount of catalog work produces a working DPA campaign without a conversion signal.

The retargeting half has no API at all

Dynamic Product Ads earn their reputation on retargeting: show someone the exact item they viewed. X's help page states the requirement for that mode plainly - retargeting campaigns need Catalog Activity Audiences, built from people who interacted with products in your catalog, selected at campaign creation.

The word "catalog" appears zero times in the Audiences API reference. "Catalog Activity" appears zero times in the entire documentation corpus, Ads API and X API v2 together. The Audiences surface covers CRM lists, website activity, mobile app users, engagement audiences, lookalikes and flexible boolean segments, and nothing catalog-aware.

That is the real boundary of API-driven DPA today. You can automate catalog ingestion, product sets, the campaign, the line item, the card and the promotion. The audience that makes a product ad a retargeting ad has to be built in the UI by a person. If you are automating the audience side generally, X custom audiences is the surface that does exist, with its own match-rate rules and a 500-user floor for UI targeting.

Feed rules worth getting right first time

Product attributes track Google's shopping spec closely, which is deliberate, and the required set is short: id, product_key, title (max 150 characters), description (max 5,000, plain text only), availability, condition, price, link, image_link. Then one of brand, gtin or mpn is required whenever the other two are absent.

Details that cause silent rejections:

FieldRule
availabilityin stock, available for order, preorder, out of stock, discontinued
conditionnew, used, refurbished
pricenumber, space, 3-letter ISO 4217 code, . as decimal
image_linkJPG, GIF, WEBP or PNG, minimum 500x500, max 5MB
inventorymust be 1 or more when availability is in stock
additional_image_linkcomma-separated, up to 10 URLs
product_typeyour own taxonomy, levels separated by > with spaces

Note that product_type means two unrelated things depending on which call you are in. On a catalog product it is your merchandising taxonomy. On a line item it is the ad product type, one of MEDIA, PROMOTED_ACCOUNT, PROMOTED_TWEETS. Same parameter name, different universe.

And if you need a user ID to scope a catalog call, the Catalog reference tells you to "Use GET users/lookup to retrieve a user ID for a screen name" in four separate places. X's own migration guide says the v2 user lookup endpoints replace standard v1.1 GET users/lookup. Resolve handles with GET /2/users/by/username/:username and ignore the suggestion.

What to do with this

If you sell physical products and already run X ads, DPA is worth setting up in the UI today: catalog in Shopping Manager, pixel events wired, product sets by margin or season. The UI path is complete and the Conversions objective it recommends is the better one.

If you were planning to automate it, scope it honestly. Catalog ingestion and campaign assembly are automatable the moment access is granted. Audience building is not automatable at all. Access is a human decision with a four-year track record of silence on the public forum, so do not put it on a critical path. And whatever you build, store X's product_key for every product, because the alternative is a catalog you can add to and never prune.

For the organic side of the same account, X-Autopilot runs on your own Mac using your own session and residential IP rather than a shared cloud pool, which lowers the detection surface relative to cloud schedulers without removing it. Browser-driven automation of your own account is a gray area X has never endorsed, and no tool can tell you otherwise. The ads path, by contrast, is sanctioned, documented and metered - which is exactly why its documentation gaps are worth mapping before you commit engineering to them. If link previews rather than product feeds are what you are debugging, the X card validator piece covers the other kind of card entirely.

The bottom line

X Dynamic Product Ads work, and the catalog surface behind them is more complete than its reputation suggests: real feed scheduling, real filter rules, a sensible product spec. Three things keep it from being a build-it-today integration. Access has been early-access only since October 2022 and the forum record on requests is four threads and zero answers. The card endpoint that renders the ads has a single line of documentation. And the feed, which everyone assumes is the catalog's source of truth, can only ever add to it.

Frequently asked

Answers indexed by Google + AI assistants.

What are Dynamic Product Ads on X?+

Ads whose creative is generated from a product catalog rather than hand-built per product. You upload a feed of products with titles, prices, images and availability, group them into product sets, and X renders carousel, single-image or collection cards from the matching products. They support prospecting and retargeting, and per X's own help pages the retargeting mode needs Catalog Activity Audiences built from people who interacted with items in your catalog.

Can I run X Dynamic Product Ads through the API?+

Partially, and only with granted access. The Catalog API covers catalogs, products, product sets and scheduled feeds across 15 endpoints, and a five-step guide covers campaign, line item, card, post and promotion. What has no API surface is the audience half: the word catalog does not appear once in the Audiences API reference, so Catalog Activity Audiences cannot be created from code. Catalog endpoints are also early-access only.

Why do I get UNAUTHORIZED_CLIENT_APPLICATION on product_catalogs?+

Because Ads API access and Catalog API access are separate grants. Developers with working Standard Ads API access have reported the exact error 'The client application with id X making this request does not have access to this Ads API endpoint' on GET product_catalogs since April 2024. The documented route is a Google Form plus your X representative. Forum threads reporting no confirmation email or reference number have gone unanswered.

Does removing a product from my X feed remove the ad?+

No. X documents feed import as an additive action and states that removing products from the feed does not delete them from the catalog. To actually remove an item you call DELETE product_catalogs/:product_catalog_id/products with an array of product_keys, which are X-generated identifiers rather than your own SKUs, and the deletion is permanent. Store X's product_key for every product you upload or you will not be able to delete it later.

What formats and schedules does the X product feed support?+

CSV, TSV or XML at a URL you host, up to 8GB. Ingestion frequency is HOURLY, DAILY or WEEKLY, with a repeat value of 1, 2, 3, 4, 6, 8 or 12 for hourly and a day name for weekly, plus a start_time in HH:MM and an IANA time zone. Batch updates are the alternative: PUT up to 25 products per request, at 600 requests per 15 minutes.

How many products can one X product set hold?+

A manual set takes a list of X-generated product keys, and X's Catalog Management overview caps it at 50 products. A filtered set takes up to 30 filter rules on attributes including price, product_type, google_product_category, sale_price, inventory and custom_label_0 through custom_label_4, with operators GREATER_THAN, EQUAL_TO, LESS_THAN, MATCH, CONTAINS and NOT_CONTAINS. Filtered sets build asynchronously and report processing_status of DONE, PROCESSING or FAILED.

Sources
Related searches
x dynamic product adsx catalog apix dynamic product ads apix product catalog feedtwitter dynamic product ads setupx shopping manager catalogx product sets dpahow to run dynamic product ads on xx ads apix ads api campaignsx conversion apix custom audiencesx pixelx carousel adsproduct feed csv
DY
Deepak YadavBuilding X-Autopilot

Product designer and indie hacker. Runs the agent on his own X account every day and writes up what the data shows, including when it's inconvenient.

Follow on X →
Try X-Autopilot.
$199 once. No subscription, no monthly bill. Real Chrome on your Mac.
See pricing▶
Free PDF · the X Growth Playbook

The exact playbook we use to grow on X

The bio that converts, the daily reply loop, the posting cadence, and the tool stack, in one no-fluff PDF. Drop your email and it's yours.

No spam. Unsubscribe anytime.

Free tools

Try it yourself.

All free X tools →
Keep reading

Related posts.