One shared record of "what happened"
Every important event — a paid order, a refund, a catalog change — is written down once, in one consistent format, before anything downstream reacts to it. Every part of the system reads from that same record instead of guessing.
Merchant impact: A paid order reliably produces exactly the downstream effects it's supposed to — no silent drops, no accidental duplicates.
Developer impact: `DomainEventEnvelopeV1` (`eventId`, `eventName`, `schemaVersion`, `occurredAt`, `storeId`, `aggregate`, `source`, `payloadRef`) is the one provider-neutral description of "what happened." `eventId` for `commerce.order.paid.v1` is deterministic (the order's own `_id`), not a fresh random UUID, so the live path and the repair path can never disagree about identity.
Example: `commerce.order.paid.v1`, `commerce.refund.created.v1`, `catalog.product.updated.v1`, and `inventory.updated.v1` are all recorded in the vocabulary today, even though Marketing Hub v1 currently only subscribes to order-paid — recording the vocabulary now avoids a later rename/migration.
Nothing gets lost, even when a provider is briefly down
If Meta or Google is temporarily unreachable when a sale happens, that delivery isn't lost — it's queued and retried automatically until it succeeds.
Merchant impact: A temporary provider outage doesn't mean a lost conversion — delivery retries automatically until it succeeds, or is flagged for a closer look.
Developer impact: `OutboxDelivery` rows (`kind`, `subscriber`, `dedupeKey`, `status`, `attempts`, `nextAttemptAt`, `leaseUntil`, `lastError`) are dispatched by a worker that claims a lease before delivery, so two concurrently running dispatch cycles can never send the same due row twice. The unique delivery index (`{kind, subscriber, dedupeKey}`) guarantees Meta and GA4 each receive an event exactly once.
Example: The outbox processing cron runs every 5 minutes; a 48-hour bounded repair cron separately catches the rare case where an order is marked paid but its event enqueue failed at that exact moment.
Every size and color tracked individually
A product with three sizes isn't tracked as one blurry item — each size gets its own permanent identity, so stock, pricing, and reporting are always accurate down to the exact variant a customer bought.
Merchant impact: Feed, pixel, and channel data stays accurate at the level a customer actually buys — no ambiguity about which size was actually out of stock.
Developer impact: Every sellable offer gets a stable, opaque `catalogItemId`, generated once at creation and never derived from title, SKU, or a transient database shape. Every catalog output (Meta, Google Merchant, TikTok, CAPI `contents.id`) uses the same identifier.
Example: A refund and a catalog feed update for the same variant both resolve to the same `catalogItemId` — there's no reconciliation step needed between the two.
Marketing tools only ever report what actually happened
Meta and GA4 don't get to independently decide a sale happened — they only ever receive and report an event that Prebit has already confirmed. That decision is made once, in one place, no matter how many marketing tools you connect.
Merchant impact: Connecting a second marketing tool doesn't risk double-counting or redefining what counts as a sale — that decision was already made once, upstream.
Developer impact: `MarketingProvider` (`key`, `capabilities`, `validatePublicConfig`, `buildPayload`, `deliver`) is a strict registry — Meta and GA4 today. Meta receives browser + server Purchase under the same canonical `eventId` for real dedupe; GA4 stays server-only through Measurement Protocol on purpose, since it can't safely dedupe a parallel browser gtag Purchase against a server one.
Example: A merchant connects GA4 mid-month; every order-paid event from that point forward reaches it through the same registry Meta already used, with no separate integration code.
One tracking setup, reused by every marketing tool
Page views, product views, cart adds, and purchases are tracked once on the storefront using one standard set of event names. Connecting a new marketing tool later doesn't mean re-instrumenting the storefront from scratch.
Merchant impact: A single, standard event vocabulary means a new marketing provider doesn't require re-instrumenting the storefront.
Developer impact: `window.prebit.analytics` exposes `track(name, properties?)` and `subscribe(name | "*", callback)`. Standard events are auto-instrumented; provider adapters are subscribers on this bus, never an alternate direct-call path — a Meta adapter consumes the `purchase` event through the bus, it never calls `fbq` directly and bypasses it. Only JSON-safe properties are accepted, and direct identifiers (email, phone, tokens) are rejected.
Example: `purchase` is deliberately never auto-fired — only the authenticated order-summary page calls `prebit.analytics.track("purchase", {...})`, with a session guard preventing it from re-firing on refresh.
Selling on more channels reuses the same foundation
Publishing your catalog to Meta, Google, or TikTok, and bringing sales in from a marketplace, both build on the same underlying system — so adding a new sales channel is a smaller, more reliable step rather than a rebuild.
Merchant impact: Channel expansion doesn't require a new backend model per destination — only a new adapter on top of infrastructure that already exists.
Developer impact: Catalog outputs (push: Meta, Google, TikTok; pull: Pinterest) and inbound sales-channel order/refund import (`Order.channelOrigin` idempotency, `ChannelProductMapping`) reuse the same `catalogItemId` and outbox patterns as Marketing Hub. The `manual` sales channel is a real, credential-free reference implementation that exercises the entire inbound pipeline.
Example: Amazon's Selling Partner API adapter is on the roadmap as its own dedicated design — LWA OAuth, AWS SigV4 signing, and a multi-step Feeds API upload flow that deserves purpose-built handling rather than being squeezed into the generic adapter shape.