Skip to content

Magento connector

A Magento Open Source 2.4+ / Adobe Commerce module that maps catalog products and CMS pages and blocks to bAInquet IngestItems, signs every request with the connector HMAC scheme, and POSTs idempotent batches.

The module lives under connectors/magento/Bainquet/Connector and sends X-Connector-Type: magento. Content is emitted per store view.

What it maps

Magento contentIngestItem typeStable idNotes
Catalog productproductproduct:<entity_id>@<store_view_code>The json.product bag carries SKU, type, status, visibility, typed prices { value, unit, currency }, special price, in_stock, and stock_quantity. Description becomes html plus a deterministic text rendition.
CMS pagepagepage:<page_id>@<store_view_code>Content into html.
CMS blockdocdoc:block-<id>@<store_view_code>doc is the in-enum type used for blocks.

Each item is emitted per store view, carrying the store-view currency and BCP-47 locale. updated_at is RFC3339 UTC with a Z suffix. Typed prices are always objects, never concatenated strings.

Install

bash
composer require bainquet/module-connector
bin/magento module:enable Bainquet_Connector
bin/magento setup:upgrade

Or copy Bainquet/Connector into app/code/ and run setup:upgrade.

Configure

Go to Stores, Configuration, bAInquet, Connector, Connection.

  1. Set Enabled to Yes.
  2. Paste the connector token (connectorId.secret). It is stored encrypted (an obscure field with the Encrypted backend model) and masked on reload.
  3. Enter the Website ID the token is scoped to.
  4. Confirm the Site domain (X-Site-Domain) and the API base URL (defaults to https://api.bainquet.online/v1/ingest).
  5. Save, then run bin/magento bainquet:sync to backfill.

All config is gated by the Bainquet_Connector::config ACL resource.

How incremental sync works

The module uses Magento observers.

  • Upsert. Observers on catalog_product_save_after and cms_page_save_after map the changed entity and POST to POST /v1/ingest/item.
  • Tombstone. catalog_product_delete_after, and any transition to a disabled product or inactive page, POST to POST /v1/ingest/delete, so the public node drops it.

How backfill works

bash
bin/magento bainquet:sync

It streams enabled products and active CMS pages per store view in chunks of 100 per batch and batch-POSTs to POST /v1/ingest/batch.

bash
bin/magento bainquet:sync --dry-run

The dry run builds and prints the batch it would send, without posting.

Out of scope

  • Single-item upserts are sent synchronously on the observer. A declarative-schema outbox table plus cron drain with debounce and coalesce is a later-phase enhancement. Planned
  • Categories, attributes, MSI multi-source detail, configurable and bundle child flattening, and B2B-gated exclusion are future work. Planned

Disabled and inactive content is excluded, and tombstoned on transition.

HMAC signing

Every request is signed exactly as the server verifies it, using the shared bq.connector.hmac.v1 scheme:

signingKey  = HKDF-SHA256(secret, salt = websiteId, info = "bq.connector.hmac.v1", 32 bytes)
canonical   = METHOD \n path \n sha256(body) \n timestamp \n nonce \n websiteId
X-Signature = hex HMAC-SHA256(signingKey, canonical)

The exact serialized bytes are signed and sent (Curl::post($url, $rawString) sends the string verbatim, with no re-encoding). Headers: Authorization: Bearer <token>, X-Site-Domain, X-Connector-Type: magento, X-Connector-Version, X-Signature, X-Timestamp, X-Nonce, X-Body-Sha256, and Idempotency-Key. Retries on 5xx and 429 reuse the same Idempotency-Key with a fresh nonce and timestamp.

The signing is parity-tested with standalone tests that need no Magento boot (php Test/Standalone/SignerParityTest.php and php Test/Standalone/MapperTest.php); the signer output matches the project-wide known-good vector byte-for-byte. Full observer, CLI, and encrypted-config behavior still requires a live Magento install to validate. The full scheme is documented in Ingestion and signing.

Owner-controlled structured data for AI.