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.

magento2-module Compatibility: 2.4.8-2.4.9 Code Quality: Fail Tests: Pass Security: Pass MIT

Are you the maintainer of angeo?

Packagento pulls angeo's Composer packages from the public registry so buyers can find them here.

Claim the namespace to take ownership, publish new releases directly, and start charging for premium versions.

Claim this namespace →

Viewing version 2.0.0. Latest version is 2.0.1. Switch to latest

OpenAI Agentic Commerce Protocol (ACP) API for Magento 2

Latest Version
Total Downloads
License
PHP Version
Magento
ACP Feed API

Magento 2 REST implementation of the OpenAI Agentic Commerce Protocol (ACP) feed API: Feeds, Products and Promotions resources, so ChatGPT can retrieve and update your catalog data through API-based delivery instead of (or alongside) daily file uploads.

All endpoints are bearer-token authenticated per the ACP specification. Feeds are persisted in the database (they survive cache flushes and restarts), product export is fully paginated with configurable-product variants, and promotions are sourced from Magento Cart Price Rules including coupon codes and free shipping.

Works together with angeo/module-openai-product-feed (CSV file-upload feed): per OpenAI's guidance, provide the full feed daily via file upload and send incremental updates through this API.

Requirements

  • PHP >= 8.3
  • Magento 2.4.x (Open Source or Adobe Commerce)
  • angeo/module-openai-product-feed ^2.0

Installation

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

Authentication (required)

Every endpoint requires a bearer token carrying the Angeo_OpenAiProductFeedApi::manage_feeds ACL resource, matching the ACP requirement that requests include Authorization: Bearer <api_key>.

  1. In the Magento admin, go to System → Extensions → Integrations → Add New Integration.
  2. On the API tab, select the resource Angeo — Manage Product Feed API (under Marketing).
  3. Save, then Activate the integration and copy the Access Token.
  4. Provide that token to OpenAI as the feed API key; use it in the Authorization: Bearer header for your own calls as well.

Requests without a valid token receive 401 Unauthorized.

Endpoints

Method Path Description
POST /rest/V1/angeo/product_feeds Create a product feed
GET /rest/V1/angeo/product_feeds List all feeds (extension beyond the ACP spec)
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 bridge)
POST /rest/V1/angeo/product_feeds/:id/products/invalidate Reset product cache for the feed
GET /rest/V1/angeo/product_feeds/:id/promotions Get promotions
POST /rest/V1/angeo/product_feeds/:id/promotions/upsert Upsert promotions (PATCH bridge)

Invalid target_country returns 400 Bad Request; unknown feed or store IDs return 404 Not Found, per the ACP error model.

PATCH bridge — web server setup

Magento 2's REST framework does not support HTTP PATCH. The ACP spec defines upserts as PATCH /product_feeds/:id/products. Bridge this with a 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 the 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]

Quick start

TOKEN="<integration access token>"

# 1. Create a feed
curl -X POST https://yourstore.com/rest/V1/angeo/product_feeds \
  -H "Authorization: Bearer $TOKEN" -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 -H "Authorization: Bearer $TOKEN" \
  "https://yourstore.com/rest/V1/angeo/product_feeds/feed_a1b2c3/products?page=1&pageSize=100"

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

# 4. Get promotions (sourced from Magento Cart Price Rules)
curl -H "Authorization: Bearer $TOKEN" \
  https://yourstore.com/rest/V1/angeo/product_feeds/feed_a1b2c3/promotions

# 5. Reset the product cache after catalog changes
curl -X POST -H "Authorization: Bearer $TOKEN" \
  https://yourstore.com/rest/V1/angeo/product_feeds/feed_a1b2c3/products/invalidate

How caching works

  • Catalog snapshot — built from the Magento catalog on the first GET, persisted until invalidated. Store-scoped feeds are built under frontend store emulation, so URLs, currency and locale match the store view.
  • Upsert overlay — products received via PATCH/upsert are stored separately and merged over the snapshot at read time (overlay wins). Catalog rebuilds never discard upserted products.
  • Page slices — formatted responses are cached for 30 minutes with their own tag; any upsert invalidates them immediately.
  • /invalidate — full reset for the feed: snapshot, overlay and pages.

Configuration

Stores → Configuration → Angeo → Product Feed API

Setting Description Default
Enabled Enable/disable the API Yes
Default Target Country ISO 3166-1 alpha-2, validated on feed creation US
UTM Medium Appended to all product URLs for attribution feed
Include List Price Original price when a special price is active Yes
Include Barcodes Read EAN/UPC/GTIN attributes Yes
Seller Name Store/brand name in ACP responses Store name
ToS / Privacy / Refund / Shipping / FAQ URLs Emitted as seller.links

ACP Product schema coverage

Field Source
id product.entity_id — stable, never changes
title Product name
description.plain / description.html description / short_description
url Product URL + utm_medium + utm_source=chatgpt
media Gallery images via Magento's ImageUrlBuilder
variants[].id / title Configurable children, or the product itself
variants[].price / list_price Final price / original price, minor units (cents)
variants[].availability Stock status → in_stock / out_of_stock
variants[].categories Category names, merchant taxonomy
variants[].variant_options Configurable attribute labels/values (color, size, …)
variants[].barcodes ean / upc / gtin / barcode / isbn attributes
variants[].condition ["new"]
variants[].seller Name + policy links from configuration

ACP Promotion schema coverage

Sourced from active Magento Cart Price Rules (SalesRules):

Magento SalesRule ACP field
rule_id id as promo_rule_{id}
name title
description + coupon code (via CouponRepositoryInterface) description.plain
is_active + dates status: active / scheduled / expired / disabled
from_date / to_date active_period (RFC 3339)
by_percent {type:"percent_off"}
by_fixed / cart_fixed {type:"amount_off"} (minor units)
simple_free_shipping {type:"free_shipping"} — combinable with a discount benefit

Testing

vendor/bin/phpunit -c app/code/Angeo/OpenAiProductFeedApi/phpunit.xml

The PromotionMapper suite (14 tests) covers benefit mapping, free-shipping detection, coupon-code resolution and status transitions.

The Angeo agentic commerce suite

Module Purpose
angeo/module-openai-product-feed OpenAI CSV product feed (file upload, all product types)
angeo/module-openai-product-feed-api This module — ACP REST API
angeo/module-ucp Universal Commerce Protocol discovery + MCP binding
angeo/module-mcp-server Read-only commerce tools over MCP
angeo/module-llms-txt llms.txt AI content map
angeo/module-aeo-audit AEO readiness audit

Need help with agentic commerce for Magento? Professional support, AEO audits and implementation at angeo.dev. Check how your store looks to AI agents with the free scanner at api.angeo.dev.

Questions? Contact me at [email protected]

License

MIT — see LICENSE

Changelog

All notable changes to this module are documented in this file.

[2.0.0] - 2026-07-05

Security

  • All REST routes now require bearer-token authentication via the
    Angeo_OpenAiProductFeedApi::manage_feeds ACL resource. Previous releases
    exposed every endpoint anonymously, which allowed anyone to dump the full
    catalog with prices and stock, create unlimited feed records in the
    database, poison the feed payload served to OpenAI through unauthenticated
    upserts, and flush the feed caches. This also aligns the module with the
    ACP API specification, which requires Authorization: Bearer <api_key> on
    every request. See the README for the Magento Integration setup that
    produces the token to hand to OpenAI.
  • target_country input is validated as ISO 3166-1 alpha-2 (returns
    400 Bad Request on invalid input instead of failing at the database
    layer), and storeId is validated against existing stores (returns
    404 Not Found for unknown stores).

Breaking changes

  • Authentication is now required on every endpoint (see Security). Update any
    callers to send a bearer token.
  • Requires angeo/module-openai-product-feed ^2.0 and PHP >= 8.3.
  • Cache key layout changed (v3 prefix, split snapshot / upsert overlay /
    page slices). Caches are rebuilt automatically on first request.

Fixed

  • Free-shipping promotions were never detected. Free shipping lives in the
    simple_free_shipping rule field, not simple_action; the mapper now reads
    getSimpleFreeShipping() against the RuleInterface::FREE_SHIPPING_*
    constants (legacy integer values tolerated). The previous fallback on
    apply_to_shipping was also removed — that flag means "apply the discount
    to shipping cost", not "free shipping".
  • Coupon codes were never appended to promotion descriptions. The rule
    repository data model returns coupon_type as the string constant
    SPECIFIC_COUPON (the old == 2 check could never match) and does not
    expose getPrimaryCoupon(). Codes are now resolved through
    CouponRepositoryInterface.
  • Stale reads after upsert. PATCH-upserted products are now stored in a
    dedicated overlay cache and served page slices carry their own cache tag,
    so an upsert invalidates the pages immediately without discarding the
    catalog snapshot.
  • Catalog rebuilds no longer discard PATCH-upserted products. The upsert
    overlay is merged over the catalog snapshot at read time and survives
    snapshot rebuilds; /invalidate performs the full reset (snapshot +
    overlay + pages).
  • Product builds for store-scoped feeds now run under frontend store
    emulation, so product URLs, currency and locale match the feed's store view
    instead of the REST default scope.
  • updated_at touch now writes UTC, consistent with the database defaults.
  • Unit tests are now runnable: the previous suite mocked
    getCurrentCurrencyCode() on StoreInterface, where the method does not
    exist, and stubbed getSimpleAction() twice in the same mock. The
    PromotionMapper suite (14 tests) passes against the rewritten mapper.

Changed

  • /invalidate now performs a scoped reset for the requested feed (snapshot
    and overlay keys) plus the shared page-slice tag, instead of flushing every
    feed's payload cache.

[1.0.0]

  • Initial release: ACP feed/products/promotions REST surface, DB-persisted
    feeds, paginated product export, SalesRule → Promotion mapping,
    PATCH-as-POST bridge.
Versions
Version Stability QA Status Compatibility Released
2.0.1 stable Fail Magento 2.4.7-2.4.9 Details 2026-07-06 20:41:27
2.0.0 stable Fail Magento 2.4.8-2.4.9 Details 2026-07-05 20:45:46
1.0.0 stable Fail Magento 2.4.8-2.4.9 Details 2026-04-18 19:19:00

Requires 9

Package Constraint
angeo/module-openai-product-feed ^2.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.1

Requires-dev 1

Package Constraint
phpunit/phpunit ^10.0

Suggests 3

Package Reason
angeo/module-aeo-audit Audit your full AEO + AI feed readiness.
angeo/module-llms-txt Generate llms.txt for AI content map.
angeo/module-mcp-server Expose read-only commerce tools over MCP.

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.

Compatibility matrix (Magento × PHP)
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. 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.

Static analysis results
Tool Status Findings Summary
PHPCS Warning 76 76 warnings (ruleset: Magento2), 29 auto-fixable with phpcbf
PHPMD Warning 12 12 rule violations (EmptyCatchBlock:3, IfStatementAssignment:2, 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.

PHPStan results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A 51
2.4.8 51 51
2.4.9 51 51

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

Unit tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A Pass
2.4.8 Pass Pass
2.4.9 Pass Pass

Integration tests

Integration tests results by Magento and PHP version
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.

Security results
Tool Status Findings Summary
Composer audit Pass 0
Malware scan Pass 0
License
MIT
Homepage
https://angeo.dev
Authors

More from angeo

View vendor
angeo/module-llms-txt Free
magento2-module

Magento 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.

v3.2.0 1mo ago
0
angeo/module-robots-txt-aeo Free
magento2-module

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.

v3.0.0 1mo ago
0
angeo/module-aeo-brand-visibility Free
magento2-module

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.

v1.2.0 1mo ago
0
angeo/module-aeo-audit Free
magento2-module

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.

v3.2.0 7d ago
0
Make it pay

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.