Your store publishes product feeds as CSV files at public URLs. Paste a feed URL into the ad platform and it re-fetches the file on its own schedule. Copy each URL from **Settings → Feeds** in the admin.

| Feed | Path | Used by |
|------|------|---------|
| ChatGPT (OpenAI Ads) | `/api/feed/openai` | OpenAI Ads Manager |
| Google Merchant Center | `/api/feed/gmc` | Google Merchant Center |
| Meta | `/api/feed/meta` | Meta Commerce catalog |

```bash
curl https://your-store.yns.store/api/feed/openai
```

The feeds are served from your store's own domain. If your storefront is a separate app, it must forward `/api/feed/*` to the platform.

Every feed lists published products, one row per variant, priced with your store's tax setting. Bundles are left out. Settings → Feeds shows when each feed was last fetched and how many rows it returned.

## ChatGPT (OpenAI Ads)

The OpenAI feed follows OpenAI's product file schema, so Ads Manager can take the URL as a hosted feed. The response is `text/csv` with a fixed header: every row has every column, and an unknown value is an empty cell.

### Choose what to advertise

Two options in **Settings → Feeds**:

| Option | Effect |
|--------|--------|
| Collections | Only products in at least one of the selected collections are included. Leave empty to include every published product. |
| Exclude out-of-stock | Skip variants with no stock. When off, they are listed with `availability` set to `out_of_stock`. |

### Languages and currencies

The base feed uses your store's language and currency. Each additional language or currency you have enabled gets its own feed, with the market in the path because Ads Manager rejects hosted URLs with a query string:

| URL | Feed |
|-----|------|
| `/api/feed/openai` | Store language and currency |
| `/api/feed/openai/de-de` | German, store currency |
| `/api/feed/openai/eur` | Store language, prices in EUR |
| `/api/feed/openai/de-de/eur` | German, prices in EUR |

The path is lowercase. A language or currency you have not enabled returns `404`.

A feed in another language uses translated product names and summaries, falling back to the base text where a translation is missing. A feed in another currency includes only variants that have an explicit price in that currency – prices are never converted.

### Columns

| Column | Value |
|--------|-------|
| `item_id` | Variant ID |
| `group_id` | Product ID, shared by all variants of a product |
| `title` | Product and variant name, up to 150 characters |
| `description` | Product summary (title if none), up to 5000 characters |
| `url` | Canonical product page for the variant |
| `brand` | Product brand, or the store name |
| `image_url`, `additional_image_urls` | Variant images (videos excluded) |
| `availability` | `in_stock` or `out_of_stock` |
| `price`, `sale_price` | With currency code, e.g. `29.00 EUR`. `price` is the price before a promotion and `sale_price` the promoted price. |
| `gtin` | The variant barcode, only when it is a valid GTIN-8/12/13/14 |
| `variant_dict`, `color`, `size` | Variant options |
| `product_category` | Category name |
| `weight`, `length`, `width`, `height` | Grams and millimetres, with `item_weight_unit` and `dimensions_unit` |
| `review_count`, `star_rating` | From product reviews, when there are any |
| `is_ads_eligible`, `is_eligible_search` | Always `true` |
| `is_eligible_checkout` | `true` only when your store has both a privacy policy and terms page |
| `seller_url`, `seller_privacy_policy`, `seller_tos`, `return_policy` | Store and legal page URLs |
| `store_country` | Country of the store address |

### Target ad groups by collection

`ads_metadata` is a JSON object an ad group can filter on as `ads_metadata.<key>`:

```json
{ "on_sale": "false", "collection_summer-sale": "true" }
```

There is one `collection_<slug>` key per collection the product belongs to, so put products in a collection to target them together. `on_sale` is `true` when a promotion applies.

### Rows OpenAI would reject

OpenAI rejects a row without an image or a positive price. Those variants are left out of the CSV and listed in **Settings → Feeds** with the reason (`no_image` or `no_price`), so you can fix them.

## Google Merchant Center and Meta

`/api/feed/gmc` and `/api/feed/meta` return CSV in each platform's column format. The Google feed reports dimensions in centimetres (`product_height`, `product_width`, `product_length`) and weight in grams (`product_weight`); earlier versions reported dimensions ten times too small, so re-fetch the feed in Merchant Center after updating.