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 content | IngestItem type | Stable id | Notes |
|---|---|---|---|
| Catalog product | product | product:<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 page | page | page:<page_id>@<store_view_code> | Content into html. |
| CMS block | doc | doc: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
composer require bainquet/module-connector
bin/magento module:enable Bainquet_Connector
bin/magento setup:upgradeOr copy Bainquet/Connector into app/code/ and run setup:upgrade.
Configure
Go to Stores, Configuration, bAInquet, Connector, Connection.
- Set Enabled to Yes.
- Paste the connector token (
connectorId.secret). It is stored encrypted (anobscurefield with theEncryptedbackend model) and masked on reload. - Enter the Website ID the token is scoped to.
- Confirm the Site domain (
X-Site-Domain) and the API base URL (defaults tohttps://api.bainquet.online/v1/ingest). - Save, then run
bin/magento bainquet:syncto 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_afterandcms_page_save_aftermap the changed entity and POST toPOST /v1/ingest/item. - Tombstone.
catalog_product_delete_after, and any transition to a disabled product or inactive page, POST toPOST /v1/ingest/delete, so the public node drops it.
How backfill works
bin/magento bainquet:syncIt streams enabled products and active CMS pages per store view in chunks of 100 per batch and batch-POSTs to POST /v1/ingest/batch.
bin/magento bainquet:sync --dry-runThe 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.