Context
0483 routes every app’s behaviour events through therelay driver to the analytics service, which fans out to Figentra’s own PostHog and
GA4. It left tenants’ own tools open. The owner’s answers of 2026-10-30 widen that: tenants at every level of the
recursive tree (0210)
connect any analytics or ad tool as a connector of the integrations service; Figentra and the levels above a tenant
must see transactions from everywhere; and no tenant should find its tools short of data without being told why. Most
parts exist. Every vendor connector is OS integrations code (0443
decision 7), a tenant’s credentials are a Connection in the connection store
(0308), and @stackra/integrations
already has AdPlatformConnector, MatchKeys hashing and the ConversionBridge that turns a business event into a
server conversion. What is missing is the rule for which tenants and tools receive an event, and the guarantees around
it. The tree sets the hard part: today a parent sees a child only through an explicit, audited grant (0210 decision 1,
0243 decision 7).
Decision
-
Three flows, kept apart.
- Figentra’s product analytics: behaviour events about the use of Figentra’s own product, as 0483 decides.
- Tenant analytics: behaviour events (page and screen views, clicks) and conversions (an order placed, a payment captured, a refund) sent to the tools the tenants on the event’s route have connected.
- Business transactions: payments, orders and the ledger stay owned by their services. They reach dashboards through read models and the warehouse (0163, note of 2026-10-29), and reach a connected tool only as a conversion built from their integration event.
- Roles: the tenant is the controller, and Figentra has a dual role. The tenant whose surface or sale an event belongs to is the controller of its customers’ data, and Figentra is its processor. Figentra is also a controller for named purposes of its own (platform analytics, fraud, billing and product improvement), as Shopify is, stated in the platform terms every tenant accepts at sign-up. The data processing agreement (0189 decision 5) and the record of processing name both. A tool a tenant connects is that tenant’s own vendor on its instruction, not Figentra’s sub-processor.
-
Who receives an event: its route. The analytics service works out the route on the server, from records, and
never from an id in the envelope:
- Parties. The tenant whose surface the event happened on (the request’s tenant context), and for a sale the seller tenant on the order or order line (a marketplace sale has both).
- Organisation ancestors. Every ancestor of a party that holds it as an organisation member (0243 decision 1) receives full detail.
- Other ancestors. A host or reseller ancestor receives what the link’s sharing level allows:
detail,aggregates(the default) ornone. The level is set when the child joins (0243 decision 4), accepted by the child, shown in the child’s settings, and changed only with both sides’ approval. - Aggregates are not events. An ancestor at
aggregatessees each child’s totals in the built-in dashboards and its warehouse. Nothing is pushed to its connected tools. - One region. A route stays inside the event’s region (0353 decision 5). An ancestor in another region gets aggregates only.
- Figentra sees every event, in its region. Figentra’s own view holds full event-level data for every tenant: a platform warehouse and a self-hosted PostHog in each region. Figentra’s global tools (PostHog EU and GA4 of 0483) receive events without contact data. This amends 0483 decision 5 for transaction events; behaviour events with no personal data keep 0483’s single-jurisdiction allowance.
-
Connectors live in the integrations service. Stackra keeps the ports and machinery, free
(0461
decision 1, 0443 decision 8):
@stackra/integrationsgains anAnalyticsToolConnectorport (ConnectorKind.Analytics:sendEvents, and an optionalerasePerson).AdPlatformConnectorgains an optionalerasePerson.- Each connector declares
canErase: true only when it can erase a person at the vendor with the connection’s own grant, proven by a recorded case. - The vendor connectors (GA4, PostHog, Meta, TikTok, Snap, Google Ads and later ones) are OS integrations connectors (0443 decision 7). Their connections sit at the tenant level or at a scope below it (0308 decision 9).
- No Firebase connector: its app reports need the Firebase SDK on the device, which 0483 decision 6 removed; a tenant measuring an app connects GA4. Owner default, changeable.
-
The analytics service routes; the integrations service sends.
- Routing data. The analytics service keeps a projection of the connections on each scope. It is fed by the
integrations service’s connection events (connector key, kind, owning scope, consent category,
canErase,phoneFormat; never a secret), plus the sharing levels fed by tenancy. - Routing. For each verified batch (0483 decision 2), and for each business integration event mapped to a
conversion, it computes the route, applies decisions 7 and 8 per connection, and publishes one
AnalyticsDeliveryRouted(analytics.delivery.routed.v1) per connection. - Sending. The integrations service handles each one in the connection owner’s context, through the connector.
Each connection retries alone.
ConversionBridgetakes routed conversions instead of reading business events itself. - Secrets. A secret never leaves the integrations service.
ScopeRef, never of a tenant (0323). - Routing data. The analytics service keeps a projection of the connections on each scope. It is fed by the
integrations service’s connection events (connector key, kind, owning scope, consent category,
-
What each connection receives.
- Behaviour. The 0483 envelope, unchanged: event name, declared properties, anonymous id, session id and public user id. It never carries a contact field, an IP address, a user agent or an advertising id.
- Conversions. Name, value, currency, items, the order’s public id as the event id (so a pixel and a server
send count once), and the ad click id when
marketingis granted. No IP address or user agent, as 0483 decision 3 says for behaviour. Owner default, changeable. - Match keys. Hashed email, phone and external id (
matchKeysOf, the connection’sphoneFormat). Computed in memory by the analytics service and never stored raw. Sent only to a connection whose connector declarescanErase, only when the event’s consent grantsmarketing, and only when the person’s stored consent proof grants it too (0472 decision 5), for every conversion and audience upload. Owner default, changeable. - Classification. Match keys are a classified field (0134) of the routed event.
-
Consent per connection.
- Behaviour. A behaviour event reaches a connection only when the visitor’s verified snapshot grants that connection’s category.
- Conversions. A conversion carries the snapshot of the call that produced it (0472 decision 4).
- The banner. The banner on a tenant’s surface names the categories of recipients on its routes, including ancestors that receive detail and their tools. A change to that set changes the surface’s consent policy version, so visitors are asked again (0298 decision 3).
-
Erasure and retention.
- Who got what. The integrations service keeps a recipients ledger: for each subject’s public id, the connections that received its match keys or user id, and when.
- Erasing. On
SubjectErasedit callserasePersonon each of them and lists each on the erasure receipt (0189 decision 2). Only connectors that can erase ever receive contacts, so the erasure is complete. Connections that only received behaviour hold anonymous ids we cannot tie to the person. - Replay store. Kept encrypted in the region for the replay window, and purged by erasure.
- Offboarding. On offboarding (0189 decision 3) a tenant’s connections and sharing levels are deleted. A child that leaves its organisation (0243 decision 5) stops routing upward from that moment.
-
Delivery guarantees, so a tenant always knows why.
- Health page. One page per connection, in the owner’s console: events sent, dropped by consent (with the
reason), sent without match keys (with the reason), failed, and the last error. It is fed by the integrations
service’s send outcomes and an hourly
AnalyticsRouteSummarisedof the analytics service’s drops. - Replay window. Delivered events are kept encrypted in the region for 7 days (owner default, changeable). The tenant can re-send a time range after fixing a key or an outage, with the same event ids. The console warns where the vendor does not dedup, such as GA4’s Measurement Protocol.
- Alerts. The tenant’s admins are notified after repeated failures or a rejected credential.
- Reconciliation. Each day, per tenant and connection, the ledger’s orders and revenue (analytics-reports read models) are set against what was routed and what was sent, with the difference broken down by reason.
- Health page. One page per connection, in the owner’s console: events sent, dropped by consent (with the
reason), sent without match keys (with the reason), failed, and the last error. It is fed by the integrations
service’s send outcomes and an hourly
- Every region, lockable. Connectors are available in every region’s stack and run in the region of the scope that holds the connection. A deployment may lock a connector off per region or per plan (0108 S2). The transfer to the vendor is the controller’s choice, and the console states it before the tenant connects. Every connector starts locked off in the GCC region until legal review of the KSA and UAE PDPL transfer rules and of Figentra’s controller purposes in the platform terms; that review is a release condition everywhere.
-
Not the built-in dashboards. analytics-reports’ dashboards and the warehouse
(0190 decision 3, 0163) read business data, stay in the region and
are served by us. They are also where
aggregatesancestors see their children. Connected tools receive only the routed events of decisions 7 and 8. Neither replaces the other. -
Plans. Connected tools, the replay window and reconciliation sit behind the entitlement
analytics.connectors(0242). It is off on every plan until the owner sets it per plan in the console, with a limit on connections per tenant. Owner default, changeable. -
Figentra’s own destinations follow. Figentra’s PostHog and GA4 of 0483 become platform-level connections of
the integrations service, so every connector lives there. A follow-up ADR amends 0483 decision 4 and the
analytics-destinationsrow of 0461 decision 6, since aga4driver in@stackra-pronames a vendor against 0443 decision 7. Until it lands, 0483 holds.
Consequences
- One rule answers “who gets this event” at every depth of the tree, and the health page and reconciliation explain every gap a tenant sees.
- The analytics service carries the routing for the whole platform: per batch, one routed event per connection on the route. The projection and the route computation must be cheap. The integrations service carries the sends, the recipients ledger and the replay store.
- Organisation parents and Figentra become recipients of child and tenant data. The platform terms, the DPA and the organisation join flow must say so before release; legal review is the product’s (0071 decision 5).
- Tools that cannot erase, such as GA4 through the Measurement Protocol, never get contacts, so their ad matching is weaker. The health page says this.
- Figentra needs a self-hosted PostHog and a platform warehouse in each region.
- Amends 0210 decision
1 and 0243
decision 7 (decision 3), 0483
decision 5 for transaction events (decision 4), and the
ConversionBridgeinput (decision 6).
Enforcement
planned:@stackra/analytics/nodetests: a route is built only from the request context and records; an organisation ancestor gets detail; a host ataggregatesgets nothing; a route never crosses a region; match keys only reach acanEraseconnection withmarketingand the person’s stored proof; no conversion carries an IP address or user agent; one routed event per connection.@stackra/integrationstests:canEraseconnectors erase every subject in the recipients ledger; a secret never appears in a read model, log or error.- The tenancy isolation test: a tenant outside the route never receives an event.