Event and data reference

Every event the Conviro_AiChat module sends to Conviro, what triggers it, when it is not sent, every field, how it is retried, and what Conviro does with it. Plan §21, and §20 items 8–10 (catalog data, order data, event reference).

Sources: the module's observers (AiChat/Observer/*, AiChat/etc/events.xml), AiChat/Service/Event/*, AiChat/Service/Inventory/*, AiChat/Service/Sync/*; the backend's apps/api/src/modules/magento/magento-event-ingest.service.ts and magento-commerce-sync.service.ts. Read 2026-09-24 on feat/magento-10-10 (d3472ce2); updated 2026-09-25 for revenue attribution (514d99b0, f9e583f6) and release gate R3 (ceaaac4d API, 8791cdc4 module: customer.deleted, the trimmed order.placed, payment assist, the cart link). Behaviour marked measured was measured on the local Magento 2.4.7-p4 test stack only (see Supported versions).

Contents: Delivery model · Envelope · Common rules · Retry and dead letter · Idempotency · Catalog events · Inventory · Customer events · Order events · Cart and payment · Operational events · Identity events (1.5.0) · Plan §21 coverage · Conviro → Magento webhooks · Catalog data reference · Order data reference


Delivery model

  1. A Magento observer (or a sync job) builds an envelope and inserts one row into the local table conviro_event_outbox — inside Magento's own database transaction where there is one. No network call happens in the storefront, checkout or admin request.
  2. The cron job conviro_deliver_events (every minute, one process at a time via a lock) claims up to 50 due rows at a time for up to 50 seconds and POSTs each one to https://api.conviro.io/v1/api/magento/events, signed.
  3. Conviro answers; the module's RetryPolicy decides what happens to the row.

Details (signature format, claim tokens, locks) are in Architecture.

Envelope

Built by Service/Event/EventFactory.php (ENVELOPE_VERSION = 1):

{
  "id": "3f0c6a8e-6f1e-4c2e-9d61-0f4c1c9e2b7a",
  "type": "order.placed",
  "version": 1,
  "occurredAt": "2026-09-24T10:15:02Z",
  "store": {
    "baseUrl": "https://shop.example.com",
    "websiteId": 1,
    "storeId": 1,
    "storeCode": "default",
    "locale": "en_US",
    "currency": "EUR"
  },
  "subject": { "type": "order", "id": "000000123" },
  "data": { "...": "per event type, below" },
  "meta": { "extensionVersion": "1.4.0", "magentoVersion": "2.4.7-p4" }
}
FieldTypeMeaning
idstring (UUID)Event id from Magento's IdentityGeneratorInterface. The idempotency key. Must equal the X-Conviro-Event-Id header (else HTTP 400).
typestringEvent type, ^[a-z][a-z_]*(\.[a-z_]+)+$, 3–64 chars.
versionintEnvelope version, 1.
occurredAtstringUTC, ISO 8601, second precision — when the envelope was built (queue time, not delivery time).
store.baseUrlstringBase URL of the store view, no trailing slash.
store.websiteId / store.storeIdintMagento website / store view id. Store 0 (admin scope) is reported as the default store view.
store.storeCodestringStore view code.
store.localestringgeneral/locale/code of the store view.
store.currencystringThe store view's current (display) currency code.
subject.type / subject.idstringWhat the event is about: product/SKU, order/order number (increment id), customer/customer id, cart/quote id, sync_job/job id, store/test.
dataobjectPer type, below.
meta.extensionVersionstringsetup_version of Conviro_AiChat from etc/module.xml.
meta.magentoVersionstringMagento's product version.

If the store context cannot be read, store holds only storeId (or is empty).

Common rules for every event

An event is not queued when any of these holds (EventPublisher::allows):

Each type below adds its own switch (a Sync Settings toggle). Toggles are read for the store view of the event, so a website-level override works (Configuration reference).

EventPublisher::publish() never throws: if the INSERT fails, the event is lost and a warning is logged ([Conviro] Could not queue …) — a failed sync event never fails a checkout, registration or product save.

Retry and dead letter

Service/Event/RetryPolicy.php, same for every type:

Conviro's answerOutbox statusWhat happens next
2xxsentDone. Kept 7 days (health numbers), then purged.
no response (DNS, TLS, timeout), 408, 409, 425, 429, 5xxpending with a later next_attempt_atRetried after +30 s, +2 min, +10 min, +30 min, +2 h, +8 h (a larger Retry-After, up to 1 h, is honoured). After the 7th failed attempt: dead.
401, 403blockedNot retried. The rest of the claimed batch is held back too. Saving the Conviro configuration (or any successful re-registration) puts blocked events back to pending.
any other 4xx (e.g. 400 invalid envelope)deadNot retried; the same bytes cannot succeed. Retry failed in the admin re-queues it by hand.

The back-off adds up to 38,550 s (about 10.7 hours) plus up to a minute of cron granularity per attempt. dead, dropped and repaired rows are purged 30 days after they were queued (conviro_purge_outbox, daily 03:23). Repair failed items (a sync job) re-queues or rebuilds dead and dropped events — see Data sync.

Ordering: the worker claims rows in id order, so events usually arrive in queue order, but a retried event can arrive after later ones. Conviro's order store applies state, status and totals only from an event at least as new (occurredAt) as the last one applied.

Idempotency


Catalog events

Switch: Sync Settings › Sync Products to KB (conviro_aichat/sync/product_sync, default off; the setup wizard's step 5 Catalog box switches it on). Read for the product's store (admin saves = store 0 = default).

product.created / product.updated

Triggercatalog_product_save_after (Observer/ProductSave.php): product.created for a new product, else product.updated. Also sent by Re-sync catalog and the catalog step of the initial sync (data.resync = true), and by Repair failed items.
Not sentProduct sync off; product without SKU; payload build failed (the save still succeeds). Changes that do not save the product model — Magento's catalog import and the Update attributes mass action — do not dispatch catalog_product_save_after (Magento core behaviour; not tested here): run Re-sync catalog afterwards.
Subjectproduct / SKU
Store scopeCatalog-wide; the envelope names the store of the save. Never filtered by store selection. Re-sync builds payloads for the default store view only.
Conviro effectUpserts the SKU's knowledge-base entry (one per SKU, text capped at 6,000 chars; see Catalog data reference) and drops cached live reads for the SKU in every store view. A re-sync (resync: true) whose KB text did not change skips the cache scan. enabled: false deactivates the SKU's KB entry at once.
AI contextYes — the KB entry is a KNOWLEDGE_BASE source. Price and stock the assistant states come from live store reads, which win over the KB (Trust layer).
AnalyticsCounted in the store's event stats (last event, events today) and the ingest SLIs.

data for an enabled product (Service/Event/ProductPayloadBuilder.php):

FieldTypePII classMeaning
skustringpublic catalogSKU.
enabledboolpublic catalogtrue.
typeIdstringpublic catalogMagento product type (simple, configurable, …).
namestringpublic catalogProduct name (store of the save).
pricenumberpublic catalogThe price attribute, base currency, not the storefront final price.
stockQtynumbermerchant confidentialLegacy stock item quantity. On an MSI store this is the default source's count, not the salable quantity.
isInStockboolpublic catalogLegacy stock item flag.
shortDescriptionstringpublic catalogstrip_tags of the short description.
descriptionstringpublic catalogstrip_tags of the description.
urlKeystringpublic catalogURL key.
productUrlstringpublic catalogStorefront URL, with utm_source/utm_medium/utm_campaign appended when Tag product links with UTM is on (source defaults to the store code).
attributesarray of {label, value}public catalogUp to 30 attributes that are visible on the storefront or used in listings, with labels and option values resolved by Magento's source models; values ≤ 200 chars; system, media, price, SEO, cost, manufacturer, country_of_manufacture and date attributes excluded.
isSalableboolpublic catalogMSI salability. Present only when MSI answered.
salableQtynumber | nullmerchant confidentialMSI salable quantity (null for composite types). Present only with isSalable.
stockSource"msi"—Present only with isSalable.
childrenarraypublic catalogConfigurable products only: up to 50 children {sku (≤64), options {label: value} (≤6, label ≤40, value ≤60), salable (bool|null), price (number|null)}.
resyncbool—true when sent by a re-sync job.

data for a disabled product: { "sku": "…", "enabled": false } only.

product.deleted

Triggercatalog_product_delete_after (Observer/ProductDelete.php); also Repair failed items when a failed product event's SKU no longer exists.
Not sentProduct sync off for the product's store; product without SKU.
Subjectproduct / SKU. Envelope store = default store view.
datasku (string), entityId (int, the product id). A repair-built delete carries sku only.
Conviro effectDeactivates the SKU's KB entry and drops cached live reads.
AI contextYes — the assistant stops offering the product.

inventory.updated

Trigger(a) cataloginventory_stock_item_save_after when quantity, stock status, backorders or manage-stock changed; (b) an MSI source-item save (plugin on SourceItemsSaveInterface: admin sources, MSI REST API, MSI imports); (c) Magento's catalog import — SKUs of stock rows are remembered per bunch and queued on catalog_product_import_finish_before; (d) Re-sync inventory and the initial sync (resync: true); (e) Repair failed items.
Not sentProduct sync off at default scope (this event is not per website); storefront orders (reservations never emit); the stock item save that happens inside a product save (the product event carries the stock — one product save = one event, measured); an MSI source save that happens after an admin product save is still sent with the fresh salable quantity.
CoalescingPer SKU: while an inventory.updated for the SKU waits in the outbox, a newer change replaces its payload.
Subjectproduct / SKU. Envelope store = default store view.
Conviro effectRewrites only the "In Stock" line of the SKU's active KB entry and drops cached live reads (a re-sync whose line did not change skips the cache scan).
AI contextYes (KB stock line). Live stock reads remain authoritative.

data (Service/Inventory/InventoryPayloadBuilder.php):

FieldTypePII classMeaning
skustringpublic catalogSKU.
isInStockboolpublic catalogLegacy stock item flag. Absent when the product has no stock item.
qtynumbermerchant confidentialLegacy stock item quantity. Absent without a stock item.
backordersAllowedboolmerchant confidentialBackorders setting > 0. Absent without a stock item.
manageStockboolmerchant confidentialManage Stock. Absent without a stock item.
isSalableboolpublic catalogMSI salability (only when MSI answered).
salableQtynumber | nullmerchant confidentialMSI salable quantity (only with isSalable).
stockSource"msi" | "legacy"—Which stock system answered.
resyncbool—Present (true) when sent by a re-sync.

Customer events

customer.created

Triggercustomer_register_success (Observer/CustomerRegister.php), which Magento's storefront registration controller dispatches. Accounts created in the admin, through the APIs or by import are not expected to dispatch it (not tested here).
Not sentCreate Leads on Registration off (conviro_aichat/sync/customer_lead, default on); store view not selected.
Subjectcustomer / customer id
Conviro effectCreates a lead (leads: name = first + last name, e-mail, customFields.source = magento, Magento customer id) unless the workspace already has a lead with that e-mail; and upserts a commerce_customers row (source = live, e-mail stored only as an HMAC hash). Leads appear in the Conviro Leads inbox and in the unanswered-lead monitors.
AI contextNo.
FieldTypePII classMeaning
customerIdintcustomer PII (identifier)Magento customer id.
emailstringcustomer PIIAccount e-mail.
firstName / lastNamestringcustomer PIIName.
groupIdintmerchant confidentialCustomer group.

customer.updated

Triggercustomer_save_after_data_object (Observer/CustomerUpdated.php) — every save through the customer repository: admin customer form, the shopper's account edit, REST, imports that use the repository.
Not sentA new customer (that is customer.created); a save that changed neither the e-mail (compared trimmed, case-insensitive) nor the customer group — a name, password or address change sends nothing; customer data not shared (Create Leads on Registration off for the website and the customer import not chosen in wizard step 5); store view not selected. Coalesced: saves before delivery stay one event with the latest values.
Subjectcustomer / customer id
Conviro effectUpserts the commerce_customers row only (e-mail as the keyed hash). No lead, notification, automation or flow.
AI contextNo.
FieldTypePII classMeaning
customerIdintcustomer PII (identifier)Customer id.
emailstringcustomer PIIHashed by Conviro on arrival, never stored raw.
groupIdintmerchant confidentialCustomer group.

Measured (attribution.sh, c3374a58): not on creation, not for a name change, one event for a group change, nothing while customer data is not shared or for an unselected store view, delivered signed without a name.

customer.deleted

Triggercustomer_delete_after (Observer/CustomerDeleted.php) — the customer model's delete event, inside the deletion's database transaction, for every path that deletes a customer (admin form and mass delete, REST / GraphQL through the repository). A deletion that rolls back queues nothing.
Also, locallyBefore queuing, the module drops this customer's undelivered outbox rows (pending, blocked, dead): its own customer.* events, and every order.*, cart.updated, checkout.started and payment.failed whose payload carries its e-mail. They become dropped with the payload emptied; a row a worker is sending at that moment is delivered and then removed at Conviro by the deletion.
Not sentNo customer data of the store view is shared with Conviro at all (Send Order Events, Create Leads on Registration, the customer import, confirmed cart recovery and confirmed payment assist all off) — a deletion is never the first time Conviro hears of a customer. Not held back by the store-view selection.
Subjectcustomer / customer id
Conviro effectMagentoCustomerDeletionService, one transaction: deletes the commerce_customers row of (this store, customer id); removes the e-mail hash from this store's commerce_orders, commerce_checkouts and commerce_payment_failures rows with that hash (a waiting payment-assist offer is withdrawn); anonymises the lead this store's customer.created made for that e-mail (name, e-mail, phone, company, job title, notes, city, country cleared; the row stays with custom_fields.anonymizedBecause = magento.customer.deleted; a lead of another Magento customer id or from a form is left alone); deletes the cart-recovery rows of that e-mail (an unsent recovery e-mail is never sent). Audit log magento.customer.deleted with the counts and the customer id — never the e-mail. Conversations and contacts are not touched: use Conviro's GDPR tools for those (see Privacy).
FieldTypePII classMeaning
customerIdintcustomer PII (identifier)The deleted customer's id.
emailstringcustomer PIIUsed in memory to find the hashed rows; never stored. Omitted when the account had none.

Measured on the local stack (privacy-deletion.sh): the customer's own customer.updated and the order / cart / payment events carrying its e-mail dropped with empty payloads, another shopper's order left pending, one customer.deleted with exactly customerId and email, delivered signed; none while no customer data is shared; sent although the store view was not selected. The backend half is covered by apps/api payment-assist.pg.spec.ts on Postgres (what is deleted, nulled, anonymised and left alone).

customer.synced (historical)

TriggerThe Import customers job — only when Customers is ticked in wizard step 5 (off by default).
Not sentCustomers not ticked (the job refuses to start and stops if unticked); store view not selected; customer without e-mail. Admin-created accounts (store 0) count as the default store view.
Subjectcustomer / customer id
Conviro effectcommerce_customers row only (source = historical). Never a lead, notification, automation, e-mail or flow.
FieldTypePII classMeaning
customerIdintcustomer PII (identifier)Customer id.
emailstringcustomer PIIHashed by Conviro on arrival (HMAC-SHA256), never stored raw.
groupId / websiteIdintmerchant confidentialGroup, website.
createdAtstringcustomer PIIAccount creation time (Magento UTC Y-m-d H:i:s).
historicalbool—true.

Order events

Switch: Sync Settings › Send Order Events (conviro_aichat/sync/order_events, default on), read for the order's store view. Store-scoped: nothing is sent for an order of an unselected store view.

Answers about orders in chat do not come from these events: the assistant reads the order live from Magento. The events keep Conviro's commerce_orders table current (history, and later revenue attribution) and stop cart recovery.

order.placed

Triggersales_model_service_quote_submit_success — the order exists (1.3.x listened to the checkout success page instead). Measured with storefront checkout; Magento's admin order creation uses the same quote submission (core behaviour, not tested here).
Not sentToggle off; store view not selected. Orders created by code that bypasses Magento's quote submission (some importers) are not seen (not tested).
Conviro effectCancels any scheduled cart-recovery e-mail for the customer e-mail; upserts commerce_orders (source = live); computes the order's revenue attribution (commerce_orders.attribution, see Privacy).

Exactly these fields — each one read by a Conviro consumer (release gate R3):

FieldTypePII classMeaning / stored by Conviro?
orderIdstringorder PII (identifier)Order number (increment id). Stored.
entityIdintorder PII (identifier)Order entity id. Stored.
status / statestringorder PIIStored.
grandTotalnumberorder PIIOrder currency. Stored.
currencystring—Order currency code. Stored.
customerEmailstringcustomer PIIStored only as an HMAC hash; used raw once to cancel cart recovery and to match the order to a conversation's e-mail (attribution), in memory.
isGuestboolorder PIIStored.
itemCountintorder PIIVisible items. Stored.
createdAtstringorder PIIOrder creation time (Magento UTC). Stored as placed_at.
attribution{visitorId?, linkIds?}pseudonymous idsOnly for a storefront order (frontend / REST / GraphQL), with Revenue attribution on and, under Cookie Restriction Mode, the shopper's consent: the chat visitor id and up to five followed Conviro link ids from the shopper's first-party cookies. Used to match; the visitor id is not stored.

Until 1.4.0 the event also carried the billing first / last name and phone, the line items (name, SKU, quantity, row total) and the customer id. No Conviro consumer read them (abandoned-cart cancellation, commerce_orders, attribution, live order lookup and leads were all checked), so they are no longer sent. Measured (privacy-deletion.sh): a real order's event carries exactly the ten fields above (no attribution from the CLI), delivered signed.

order.processing / order.completed / order.canceled / order.status_changed

Triggersales_order_save_after on an existing order whose state or status changed (Observer/OrderStatusChange.php). A state change to processing, complete or canceled gives order.processing, order.completed, order.canceled; any other change (other states such as holded or closed, or a status-only change) gives order.status_changed.
Not sentNew orders (they are order.placed); saves that change neither state nor status; changes written without saving the order model.
Conviro effectUpserts commerce_orders (state, status, total only from an event at least as new as the last applied).
FieldTypePII class
orderId, entityIdstring, intorder PII (identifier)
oldState, state, oldStatus, statusstringorder PII
customerEmailstringcustomer PII (hashed by Conviro)
grandTotal, currencynumber, stringorder PII
isGuestboolorder PII
createdAtstringorder PII

order.shipped

Triggersales_order_shipment_save_after for a new shipment.
Not sentA re-save of an existing shipment — so tracking numbers added to a shipment after it was created are not sent (the assistant still reads tracking live).
Conviro effectUpserts commerce_orders (last event time).
FieldTypePII class
orderId, entityIdstring, intorder PII (identifier)
shipmentIdstringorder PII
trackingarray {carrier, title, number}order PII
itemsarray {sku, qty}order PII
customerEmailstringcustomer PII (hashed by Conviro)

order.refunded / order.partially_refunded

Triggersales_order_creditmemo_save_after for a new credit memo. order.refunded when the order is closed or total refunded ≥ total paid; else order.partially_refunded.
Conviro effectUpserts commerce_orders.
FieldTypePII class
orderId, entityIdstring, intorder PII (identifier)
creditmemoIdstringorder PII
refundAmount, totalRefunded, totalPaidnumberorder PII
currencystring—
customerEmailstringcustomer PII (hashed by Conviro)

order.synced (historical)

TriggerThe order-history job: orders of the selected store views with created_at inside the window fixed when the job starts (30 / 90 / 365 days, chosen in wizard step 5; Re-sync recent orders uses 30 when "none" was chosen). Also Repair failed items rebuilds a failed order event as order.synced.
Not sentSend Order Events off; window "none" at setup (no history job); store view not selected.
Conviro effectcommerce_orders row with source = historical. Nothing live happens: no cart-recovery cancellation, notification or flow.
FieldTypePII class
orderId, entityIdstring, intorder PII (identifier)
state, statusstringorder PII
grandTotal (4 decimals), currencynumber, stringorder PII
itemCountint | nullorder PII
customerEmailstringcustomer PII — hashed by Conviro, never stored raw
isGuestboolorder PII
createdAt, updatedAtstringorder PII
historicalbooltrue

No names, addresses, phones or line items.


Cart and payment events

Both are off by default and need two things: the toggle on for the store's website and the merchant's confirmation at default scope (Cart recovery and payment assist). Upgrading from 1.3.x holds a toggle that was already on until it is confirmed.

cart.updated

Triggercheckout_cart_save_after (Magento's storefront cart model).
Not sentToggle off or not confirmed; store view not selected; the quote has no customer e-mail (in practice guests before checkout) or no items. Cart changes made through REST/GraphQL cart APIs do not dispatch this Magento event (Magento core behaviour; not tested here).
Subjectcart / quote id
Conviro effectIf the workspace's cartRecovery capability is on and the cart total is at least 1: schedules one recovery e-mail per cart 60 minutes after the last cart event (every cart event pushes it back), stores the cart in magento_abandoned_carts (with the store view, its locale and the cart link) and finds or creates a contact for the e-mail. A later order.placed for the same e-mail cancels it. The e-mail is in the store view's language (see Cart recovery).
FieldTypePII class
cartIdintcustomer PII (identifier)
emailstringcustomer PII
itemCountintorder PII
grandTotal, currencynumber, stringorder PII
itemsup to 10 {name, sku, qty, price}order PII
cartUrlstring— (the recovery e-mail's link: Cart page URL (headless stores) for the store view when set, else the store view's own checkout/cart URL, built locally, no HTTP)

checkout.started

TriggerThe predispatch of the checkout route itself (Observer/CheckoutStarted.php, etc/frontend/events.xml: checkout_index_index — Luma checkout, Hyvä Checkout and one-step checkouts that keep that route — and onestepcheckout_index_index). Server-side, no checkout JavaScript. A headless checkout that never requests these pages sends nothing.
Not sentBehind the same switch as cart.updated (cart recovery on and confirmed); store view not selected; an empty cart; a reload of the same checkout state in the same session (a changed cart reaching the checkout again is sent again).
Subjectcart / quote id
Conviro effectOne commerce_checkouts row per quote (e-mail as the keyed hash), with whether a Conviro conversation or product link preceded it. Nothing is ever sent to the shopper because of this event. Rows are deleted after 90 days.
FieldTypePII class
quoteIdintcustomer PII (identifier)
itemCountintorder PII
grandTotal, currencynumber, stringorder PII
emailstringcustomer PII — only when the shopper already gave it (logged in, or the e-mail step done)
attribution{visitorId?, linkIds?}pseudonymous ids — as on order.placed

Measured (attribution.sh, c3374a58): only with cart recovery on and confirmed, once per checkout state, no e-mail for a guest who gave none, not for an unselected store view; observer p50 0.89 / p95 1.18 ms.

payment.failed

Triggersales_model_service_quote_submit_failure — order placement threw (replaces 1.3.x's CheckoutFailure hook, which the default checkout never called).
Not sentToggle off or not confirmed; store view not selected; a payment declined before the order submission is attempted (e.g. inside a payment provider's own browser widget) never reaches Magento's quote submission. Since 1.4.1 also not when the order was already saved: Magento raises the same failure event for an exception thrown after the order exists (e.g. by another module's success observer) — that is not a failed payment, and the chat must not offer payment help.
Subjectcart / quote id
Conviro effectPayment assist (PaymentAssistService): one commerce_payment_failures row per event (method code, total, currency, the error text with e-mail addresses and digit runs of six or more masked, the e-mail only as the keyed hash; deleted after 90 days). When attribution.visitorId names a conversation of the workspace, staff see a "A payment failed at checkout" event on that conversation in the inbox, and — only while the workspace's paymentAssist capability is on (the module's switch and its confirmation, sent on registration) — the chat widget offers the shopper help once, on their next page view, in the widget's language. The offer expires 24 hours after the failure; switched off meanwhile, it is withdrawn. Without a visitor id Conviro only records the failure. See Payment assist.
FieldTypePII class
cartIdintcustomer PII (identifier)
emailstringcustomer PII (hashed by Conviro, never stored raw)
paymentMethodstringorder PII (method code, never card data)
grandTotal, currencynumber, stringorder PII
errorstringorder PII — exception message, tags stripped, whitespace collapsed, ≤ 300 chars
attribution{visitorId?, linkIds?}pseudonymous ids — only from a storefront request, with Revenue attribution on and, under Cookie Restriction Mode, the shopper's consent

Measured on the local stack (payment-assist.sh, the failure event dispatched as QuoteManagement::submitQuote() does, on a real quote): nothing while off or not confirmed; the six fields from an admin / CLI request, plus the visitor and link ids from a storefront REST request; no visitor id without consent under Cookie Restriction Mode or with Revenue attribution off; delivered signed. The backend half (one offer under five parallel page views, withdrawn, expired) is apps/api payment-assist.pg.spec.ts.


Operational events

sync.job.progress

TriggerEvery sync job (catalog, inventory, orders, customers, repair): once per batch and on every state change. Coalesced per job.
Subjectsync_job / Magento job id
Conviro effectUpserts commerce_sync_jobs (counters only grow; a completed/failed job is never reopened by a late "running"). Shown in the Conviro dashboard's Magento card.

data: jobId (int), type (catalog\|inventory\|orders\|customers\|repair), status (queued\|running\|completed\|failed), processed, failed, skipped, total (int), cursor (string), createdAt, startedAt, finishedAt (string\|null), lastError (≤ 300 chars, e-mail addresses replaced by [email]), and for repair rebuilt, requeued; for orders windowDays. No customer data.

test.ping

Sent by Send test event (data: {source: "admin"}, subject store/test) and by wizard step 7 ({source: "setup-wizard"}, subject store/setup-verify). Conviro accepts and counts it.

Unknown types

Conviro answers 2xx ignored to a type it does not handle, so a newer module never dead-letters against an older backend.


Identity events (1.5.0, unreleased)

1.5.0 (unreleased), read 2026-09-27 on feat/magento-1.5.0-customer-hub. Sent only by a store that has switched signed customer identity on at least once (Signed customer identity and My orders); a store that never did has no bindings and sends nothing.

identity.bindings_revoked

TriggerThe module revoked signed-session bindings (Service/Identity/BindingRevocation.php): customer_logout (every live binding of that Magento session — Observer/Identity/CustomerLogout.php, frontend area), customer_delete_after (every live binding of the customer — Observer/Identity/CustomerDeletedBindings.php; Phase 5: right after the event is queued, every binding row of that customer is deleted), a password change or reset (every live binding of the customer — Plugin/Identity/RevokeBindingsOnPasswordChange.php), and a bootstrap for customer B on a session that still had customer A's bindings (A's).
Not sentNothing was revoked (no live binding matched). The store has no installation id (identity never switched on). The common rules above: no API key, module disabled for the store view. Not held back by the store-view selection, and not a personal-data event (it carries no customer data), so it is queued even while delivery is blocked.
BatchingAt most 100 binding ids per event; more are split over several events.
Subjectidentity_binding / the first binding id of the batch
Conviro effectRevokes the Verified Customer Principals minted with those binding ids — only inside the workspace of the API key that delivered the event (ids of another workspace match nothing); unknown ids are a no-op, malformed ids are dropped, at most 100 are read. Reason mapping: customer_logout → customer_logged_out, customer_deleted → customer_deleted, account_switched → account_switched, anything else (e.g. password_changed) → binding_revoked. Idempotency: a database receipt (like order.placed), so a redelivery with Redis down is still a duplicate.
Latencythe outbox cron (every minute). Until it arrives, the binding is already revoked in Magento, so the next order read is refused anyway (403 binding_revoked), and the widget has usually dropped the verification itself on sign-out.
FieldTypePII classMeaning
bindingIdsstring[] (UUIDv4, 1–100)pseudonymous ids (random)The revoked bindings.
reasonstringnonecustomer_logout | customer_deleted | password_changed | account_switched.

No customer id, e-mail or session id. Not yet measured end to end (the identity-bridge.sh scenario that delivers it signed through the real outbox needs the Docker stack); unit tests cover the module side (BindingRevocationTest, PasswordChangeRevocationTest) and the Conviro ingest.


Plan §21 coverage

Every type of plan §21's baseline is emitted by 1.4.0: customer.updated and checkout.started (f9e583f6, above) were the last two. customer.deleted (release gate R3) goes beyond it.


Conviro → Magento webhooks

Conviro also calls the store: POST https://<store>/conviro/webhook/receive (Controller/Webhook/Receive.php). Conviro subscribes the store to these event types when it registers: lead.captured, lead.created, contact.created, session.started, plus webhook.test (Conviro's "send test", data.test = true).

The store verifies X-Webhook-Signature: t=<unix>,v1=<hex> (HMAC-SHA256 of "<t>.<raw body>" with the webhook secret, ±300 s), checks data.tenantId against its own tenant id, accepts only the known types, and records the delivery once (replay key = SHA-256 of "<t>.<verified HMAC>" — canonical, so re-spelling a captured header does not make it new again; table conviro_inbound_event, purged hourly after a day). Answers: 401 bad/missing signature, 400 malformed, 403 tenant mismatch, 422 unsupported event, 200 once (200 duplicate for a replay), 500 if processing threw (the replay key is released so Conviro's retry can apply it).

The store records these events in conviro_webhook_log (event name, direction in, HTTP status, error code — no payload); a request that fails the signature check is only counted — one rejected row per reason and minute, its hits column saying how many (1.4.0) — so forged POSTs cannot flood the table. It dispatches the Magento event conviro_webhook_received with conviro_event and conviro_data, for the merchant's own code to act on. The module itself takes no other action.


Catalog data reference

What Conviro keeps per product (one knowledge-base entry per SKU, built by apps/api/src/modules/magento/magento-product-kb-content.ts for both the event path and the nightly REST pull):

Product · SKU · Price · In Stock · Variants · Specifications · Summary · Description · URL, capped at 6,000 characters.

The optional nightly REST pull (02:00 server time, only for workspaces with KB sync enabled) lists products with visibility 2, 3 or 4 and deactivates KB entries of products no longer listed — only after a complete listing.

Order data reference

WhereWhat
Live, per questionOrder status, totals, items and tracking are read from Magento's REST API when a shopper asks, after the shopper gives the order number and checkout e-mail (capability Order status & tracking lookup). Nothing from these reads is written to Conviro's order tables; results are cached briefly (see Privacy).
commerce_ordersOne row per (workspace, integration, order number): store code and id, entity id, state, status, grand total, currency, item count, customer_email_hash + email_hash_key_id, is_guest, placed_at, source (live | historical, never changed after insert), attribution (reserved, NULL), last_event_at. No name, address, phone, line items or raw e-mail.
commerce_customersOne row per (workspace, integration, Magento customer id): store code/id, website id, group id, email_hash + key id, account creation time, source, last event.