# angeo/module-openai-product-feed-api

> Magento 2 REST API for OpenAI Agentic Commerce Protocol (ACP). Implements the full 6-endpoint ACP feed surface: feeds, products (with full pagination and configurable variants), and promotions. DB-persisted feeds, POST-based PATCH workaround for Magento compatibility.

`composer require angeo/module-openai-product-feed-api`

Canonical URL: https://packagento.com/angeo/module-openai-product-feed-api

## At a glance

- **Vendor**: angeo (https://packagento.com/angeo.md)
- **Latest version**: 1.0.0 — released 2026-04-18
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/angeo/module-openai-product-feed-api and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require angeo/module-openai-product-feed-api:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Magento 2 REST API for OpenAI Agentic Commerce Protocol (ACP). Implements the full 6-endpoint ACP feed surface: feeds, products (with full pagination and configurable variants), and promotions. DB-persisted feeds, POST-based PATCH workaround for Magento compatibility.

## README

[![Packagist](https://img.shields.io/packagist/v/angeo/module-openai-product-feed-api.svg)](https://packagist.org/packages/angeo/module-openai-product-feed-api)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![PHP](https://img.shields.io/badge/php-%3E%3D8.2-8892BF.svg)](https://php.net)

**Magento 2 REST API for the OpenAI Agentic Commerce Protocol (ACP). Full 7-endpoint feed surface with DB-persisted feeds, paginated product export, and SalesRule → Promotion mapping.**

---

### What this module fixes

- **DB-persisted feeds** — feed IDs survive cache flushes and server restarts (`angeo_acp_feed` table via Schema Patch)
- **Proper pagination** — `getProducts` now iterates the full catalog in batches (v1 silently capped at 100 products)
- **PATCH workaround documented** — Magento has no native PATCH support; upserts exposed via `/upsert` POST + nginx rewrite
- **Structured validation errors** — upsert responses include `errors: string[]` per field, not a silent `false`
- **Category names resolved** — products now return `{value: "Tools", taxonomy: "merchant"}` instead of `{value: "42"}`
- **ImageUrlBuilder** — product images use Magento's proper resized URL builder, not raw file paths
- **`/invalidate` endpoint** — bust product cache without a deploy
- **Coupon codes in promotion descriptions** — auto-appended when rule has a specific coupon
- **Multiple benefits per promotion** — e.g. 10% off + free shipping in one `benefits` array
- **`GET /product_feeds`** — list all feeds (new endpoint)

---

### Endpoints

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/rest/V1/angeo/product_feeds` | Create a product feed |
| `GET`  | `/rest/V1/angeo/product_feeds` | List all feeds |
| `GET`  | `/rest/V1/angeo/product_feeds/:id` | Get feed metadata |
| `GET`  | `/rest/V1/angeo/product_feeds/:id/products` | Get products (paginated) |
| `POST` | `/rest/V1/angeo/product_feeds/:id/products/upsert` | Upsert products (PATCH workaround) |
| `POST` | `/rest/V1/angeo/product_feeds/:id/products/invalidate` | Bust product cache |
| `GET`  | `/rest/V1/angeo/product_feeds/:id/promotions` | Get promotions |
| `POST` | `/rest/V1/angeo/product_feeds/:id/promotions/upsert` | Upsert promotions (PATCH workaround) |

---

### PATCH workaround — nginx setup

Magento 2's REST framework does not support HTTP `PATCH`. OpenAI's ACP crawler sends `PATCH /product_feeds/:id/products`. Bridge this with an nginx rewrite **before** the request reaches Magento:

```nginx
## Add inside your server {} block
location ~ ^/rest/V1/angeo/product_feeds/[^/]+/products$ {
    if ($request_method = PATCH) {
        rewrite ^(.*)$ $1/upsert last;
    }
}

location ~ ^/rest/V1/angeo/product_feeds/[^/]+/promotions$ {
    if ($request_method = PATCH) {
        rewrite ^(.*)$ $1/upsert last;
    }
}
```

**Apache** (`.htaccess` in Magento root):

```apache
RewriteCond %{REQUEST_METHOD} ^PATCH$
RewriteRule ^rest/V1/angeo/product_feeds/([^/]+)/products$ rest/V1/angeo/product_feeds/$1/products/upsert [L]
RewriteCond %{REQUEST_METHOD} ^PATCH$
RewriteRule ^rest/V1/angeo/product_feeds/([^/]+)/promotions$ rest/V1/angeo/product_feeds/$1/promotions/upsert [L]
```

---

### Installation

```bash
composer require angeo/module-openai-product-feed-api
bin/magento setup:upgrade
bin/magento cache:flush
```

---

### Configuration

Navigate to **Stores → Configuration → Angeo → Product Feed API**.

| Setting | Description | Default |
|---------|-------------|---------|
| Enabled | Enable/disable the API | Yes |
| Default Target Country | ISO 3166-1 alpha-2 | US |
| UTM Medium | Appended to all product URLs for attribution | feed |
| Include List Price | Original price when special price active | Yes |
| Include Barcodes | Read EAN/UPC/GTIN attributes | Yes |
| Seller Name | Store/brand name in ACP response | Store name |
| Terms of Service URL | Linked in seller.links | — |
| Privacy Policy URL | Linked in seller.links | — |
| Refund Policy URL | Linked in seller.links | — |
| Shipping Policy URL | Linked in seller.links | — |
| FAQ URL | Linked in seller.links | — |

---

### Quick start

```bash
## 1. Create a feed
curl -X POST https://yourstore.com/rest/V1/angeo/product_feeds \
  -H "Content-Type: application/json" \
  -d '{"targetCountry":"US","storeId":1}'
## → {"id":"feed_a1b2c3d4e5f6","target_country":"US","store_id":1,"updated_at":"...","created_at":"..."}

## 2. Get products (page 1, 100 per page)
curl "https://yourstore.com/rest/V1/angeo/product_feeds/feed_a1b2c3/products?page=1&pageSize=100"

## 3. Upsert products (POST to /upsert; OpenAI PATCH is rewritten by nginx)
curl -X POST https://yourstore.com/rest/V1/angeo/product_feeds/feed_a1b2c3/products/upsert \
  -H "Content-Type: application/json" \
  -d '{"feedId":"feed_a1b2c3","products":[{"id":"SKU_42","variants":[{"id":"SKU_42_BLK","title":"Black"}]}]}'
## → {"id":"feed_a1b2c3","accepted":true,"upserted_count":1,"errors":[]}

## 4. Get promotions (sourced from Magento SalesRules)
curl https://yourstore.com/rest/V1/angeo/product_feeds/feed_a1b2c3/promotions

## 5. Invalidate product cache (after catalog changes)
curl -X POST https://yourstore.com/rest/V1/angeo/product_feeds/feed_a1b2c3/products/invalidate \
  -H "Authorization: Bearer <admin_token>"
```

---

### ACP Product Schema Coverage

#### Product level
| Field | Source |
|-------|--------|
| `id` | `product.entity_id` — stable, never changes |
| `title` | `product.name` |
| `description.plain` | `short_description` stripped, or `description` stripped |
| `description.html` | `description` raw HTML |
| `url` | Product URL + `utm_medium=feed&utm_source=chatgpt` |
| `media` | Gallery images via `ImageUrlBuilder` |

_(README truncated for .md surface. Full README on https://packagento.com/angeo/module-openai-product-feed-api.)_

## Recent Versions

| Version | Released |
|---|---|
| 1.0.0 | 2026-04-18 |

## Dependencies

### Require

| Package | Constraint |
|---|---|
| angeo/module-openai-product-feed | ^1.0 |
| magento/framework | * |
| magento/module-backend | * |
| magento/module-catalog | * |
| magento/module-catalog-inventory | * |
| magento/module-configurable-product | * |
| magento/module-sales-rule | * |
| magento/module-store | * |
| php | >=8.2 |

### Require (dev)

| Package | Constraint |
|---|---|
| phpunit/phpunit | ^10.0 |

### Suggest

| Package | Constraint |
|---|---|
| angeo/module-aeo-audit | Audit your full AEO + AI feed readiness. |
| angeo/module-llms-txt | Generate llms.txt for AI content map. |

## Quality

Latest release (1.0.0) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | not tested | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | Pass |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Warning | 77 | 77 warnings (ruleset: Magento2) — 33 auto-fixable with phpcbf |
| PHPMD | Warning | 14 | 14 rule violations (EmptyCatchBlock:4, IfStatementAssignment:3, TooManyPublicMethods:2, ExcessiveClassComplexity:1, UnusedLocalVariable:1) |
| Cpd | Pass | 0 |  |
| Composer validate | Info | 8 | valid; 8 advisory notes (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | 45 | – | – |
| 2.4.8 | – | 45 | 45 | – |
| 2.4.9 | – | – | 45 | 45 |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Error | Error | – | – |
| 2.4.8 | – | Error | Error | – |
| 2.4.9 | – | – | Error | Error |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["angeo/module-openai-product-feed-api"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

angeo is a Magento 2 vendor on Packagento. See https://packagento.com/angeo.md for their full catalogue.

