Skip to content

Wix connector

A standalone Node connector that streams a Wix site's content to the bAInquet ingestion API, mapping each Wix solution to the canonical IngestItem shape, signing every request with the bq.connector.hmac.v1 HMAC scheme, and POSTing idempotent items and batches.

Stable HMAC parity-tested: it vendors the SDK signer (src/bainquet-sign.ts, a self-contained copy proven byte-for-byte against the project-wide known-good vector).

What it maps

The SourceType enum has 13 fixed values; Wix solutions map onto them with no new enum values invented:

Wix solutiontypeStable idNotes
PagespagewixPage#<id>excludes hidden / unpublished
Stores productsproductwixStores.product#<id>variants plus typed price {value,unit,currency}
Bookings servicescustomwixBookings.service#<id>attributes.subtype = "service"
Restaurants menu itemscustomwixRestaurants.item#<id>attributes.subtype = "menu_item"
EventseventwixEvents.event#<id>typed date and location, lowest ticket price
Blog postspostwixBlog.post#<id>not article (not in the enum)
Business profileprofilewixBusiness.profile#<siteId>
LocationslocationwixLocations.location#<id>one entity per location

The two custom solutions advertise their subtype field mapping via POST /v1/ingest/schema once per connection, before their first batch (see src/schema.ts, customSubtypeMappings). All prices are typed objects, never concatenated strings, and url is always the public site URL whose host equals X-Site-Domain.

Install and build

bash
npm install
npm run build

Requires Node 20.11 or newer.

Configuration

VariablePurpose
BAINQUET_API_URLdefault https://api.bainquet.online/v1
BAINQUET_CONNECTOR_TOKENconnectorId.secret
BAINQUET_WEBSITE_IDscoped website id
BAINQUET_SITE_DOMAINsite host, for example acme.com
WIX_WEBHOOK_PUBLIC_KEYWix app webhook RSA public key (PEM), for inbound JWT verification
WIX_API_TOKENWix API access token (read-only) for backfill
WIX_SITE_ORIGINhttps://acme.com
WIX_CURRENCYdefault USD
WIX_DEFAULT_LANGUAGEdefault en
WIX_SOLUTIONScomma-separated list limiting which solutions sync (default all)

Two separate secrets

  • WIX_WEBHOOK_PUBLIC_KEY verifies inbound Wix webhooks, which Wix signs as an RS256 JWT.
  • BAINQUET_CONNECTOR_TOKEN signs the outbound HMAC to bAInquet.

WARNING

Keep the two secrets distinct. The webhook public key only verifies what Wix sends you; the connector token authenticates what you send to bAInquet.

Mapping pattern

Mapping is per-solution, governed by the resolution table above and implemented in mapper.ts. A record's solution determines its type and stable id; structured data (variants, prices, dates, locations) goes into typed json objects. The two custom solutions describe their subtype attribute to the server via /ingest/schema before sending items, so the server knows how to interpret the custom field.

Incremental sync

Wix delivers webhooks as a signed JWT. Subscribe to per-solution created / updated / deleted events (and app-removed), and point them at the bundled webhook server:

bash
node dist/scripts/webhook-server.js   # :8473 /webhooks/wix
  • created or updated maps the record and POSTs to POST /v1/ingest/item.
  • deleted or unpublished POSTs a tombstone to POST /v1/ingest/delete by stable id.
  • app or instance removed sends a final idle heartbeat for a clean disconnect.

The JWT signature is verified with WIX_WEBHOOK_PUBLIC_KEY before any processing; an invalid JWT is rejected with no side effects.

Backfill

bash
npm run backfill

Pages each enabled Wix solution (cursor paging, honoring 429), maps records, and batch-POSTs in chunks of 500. Idempotent: unchanged records return skipped.

Signing

signingKey  = HKDF-SHA256(secret, salt = websiteId, info = "bq.connector.hmac.v1", 32 bytes)
canonical   = METHOD\npath\nsha256(body)\ntimestamp\nnonce\nwebsiteId
X-Signature = hex HMAC-SHA256(signingKey, canonical)

Headers include X-Connector-Type: wix. Retries on 5xx / 429 / network errors reuse the same Idempotency-Key with a fresh nonce and timestamp. See Ingestion and signing.

Out of scope

This package is the content mapper, signer, webhook glue, and backfill. The full Wix App surface (OAuth install, embedded dashboard, encrypted token store, Postgres outbox and BullMQ, polling fallback, DNS or meta verification helper) wraps this core and is out of scope. The endpoint paths used in backfill.ts follow the documented Wix REST query endpoints and may need per-app permission adjustment. No LLM anywhere.

Verifying the signer

bash
npm test

Runs the vendored-signer parity check (known-good vector, byte-for-byte) plus mapper unit tests (SourceType resolution, typed prices, draft exclusion).

Owner-controlled structured data for AI.