angeo / module-openai-product-feed-api
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.
Angeo OpenAI Product Feed API — Magento 2
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_feedtable via Schema Patch) - Proper pagination —
getProductsnow iterates the full catalog in batches (v1 silently capped at 100 products) - PATCH workaround documented — Magento has no native PATCH support; upserts exposed via
/upsertPOST + nginx rewrite - Structured validation errors — upsert responses include
errors: string[]per field, not a silentfalse - 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
/invalidateendpoint — 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
benefitsarray 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:
# 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):
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
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
# 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 |
Variant level
| Field | Source |
|---|---|
id |
Child entity_id for configurable, product entity_id otherwise |
title |
Child or parent product name |
price |
final_price in minor units (cents) |
list_price |
price when special_price is active (per ACP best practices) |
availability |
StockRegistry → in_stock / out_of_stock |
categories |
Category names with merchant taxonomy |
variant_options |
Configurable attribute labels/values (color, size, …) |
barcodes |
ean / upc / gtin / barcode / isbn product attributes |
condition |
["new"] (override in ProductMapper) |
seller.name |
Config or store name |
seller.links |
ToS, privacy, refund, shipping, FAQ from config |
ACP Promotion Schema Coverage
Sourced from active Magento SalesRules:
| Magento SalesRule | ACP field |
|---|---|
rule_id |
id as promo_rule_{id} |
name |
title |
description + coupon code |
description.plain |
is_active + dates |
status: active / scheduled / expired / disabled |
from_date / to_date |
active_period.start_time / end_time (RFC 3339) |
by_percent |
{type:"percent_off", percent_off: N} |
by_fixed / cart_fixed |
{type:"amount_off", amount_off:{amount, currency}} |
free_shipping flag |
{type:"free_shipping"} (combinable with other benefits) |
Testing
vendor/bin/phpunit -c app/code/Angeo/OpenAiProductFeedApi/phpunit.xml
The Angeo AI Suite
| Module | Purpose |
|---|---|
angeo/module-aeo-audit |
AEO audit — 8 signals scored |
angeo/module-llms-txt |
Generates /llms.txt |
angeo/module-openai-product-feed |
CSV product feed file generator |
angeo/module-openai-product-feed-api |
This module — ACP REST API |
License
MIT — see LICENSE
No changelog yet
The vendor hasn't published a changelog. Tagged releases appear in the Versions tab.
Requires 9
| 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 |
Requires-dev 1
| Package | Constraint |
|---|---|
| phpunit/phpunit | ^10.0 |
Suggests 2
| Package | Reason |
|---|---|
| angeo/module-aeo-audit | Audit your full AEO + AI feed readiness. |
| angeo/module-llms-txt | Generate llms.txt for AI content map. |
Compatibility
Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.
Code Quality
Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge. 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's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases.
Tests
Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.
Unit tests
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
Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.
More from angeo
View vendorMagento 2 module for AI Engine Optimization (AEO). Generates spec-compliant llms.txt and llms-full.txt per llmstxt.org standard, plus streaming JSONL for vector indexing. Multi-store, multi-website, CLI, cron, async admin UI, Page Builder-aware sanitization, customer-group pricing, atomic writes, ETag/Cache-Control, .md mirrors.
Magento 2 module for AI Engine Optimization (AEO). Injects AI crawler rules (OAI-SearchBot, GPTBot, ChatGPT-User, PerplexityBot, Perplexity-User, Google-Extended, ClaudeBot, anthropic-ai, Claude-User, Applebot, cohere-ai, Amazonbot, Meta-ExternalAgent) into robots.txt — without overwriting your existing configuration. Supports per-bot Allow/Disallow lists, Crawl-delay, Sitemap directives, multi-store, and a public Api\RobotsStatusInterface for cross-module integration with angeo/module-aeo-audit.
Live AI brand visibility audit for Magento 2. Queries ChatGPT, Claude, Perplexity, Gemini and Groq with brand-probing prompts and scores real-world AI recall, citation rate and recommendation presence. Extends angeo/module-aeo-audit v3 via CheckerInterface as the 16th signal, alongside the 15 built-in technical checks.
Magento 2 AEO (AI Engine Optimization) Audit. v3 covers 15 signals — robots.txt AI bots, llms.txt + llms.jsonl, Product / Organization / FAQ schema, merchant return + shipping policies, sitemap.xml, UCP profile, AI product feed, OG tags, canonical + hreflang, JSON-LD quality, well-known endpoint matrix, Core Web Vitals via CrUX. Score Trend dashboard, Admin UI, cron, dynamic fix commands, dependency-injected extension point for custom checkers.
Turn an existing module into recurring revenue.
If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.