CONTRACT · INCREMENTALITY

Measurement

fidra proves whether it adds revenue with a treatment/control holdout. To close the loop we need exactly one thing from you: a daily NGR aggregate per pseudonymous user.

LAST UPDATED 2026-07-27

What we need — one row per userRef per day

{
  "schemaVersion": 1,
  "userRef": "u-9f3a",          // YOUR pseudonymous id — the join key to the assignment
  "day": "2026-07-01",           // UTC calendar day
  "ngrTotal": 42.5,              // all-surface NGR for this user this day (may be negative)
  "currency": "USDT",           // REQUIRED (v2): your single reporting currency
  "bySurface": { "feed": 20, "slots": 22.5 },   // the cannibalization view; absent surface = 0
  "bonusCost": 5,                // optional, ≥ 0
  "providerCost": 3,             // optional, ≥ 0
  "assignment": "treatment",     // the user's holdout arm — required
  "experimentId": "exp-2026q3",  // optional
  "strata": "vip"                // optional — stratified randomization label
}

What never crosses

No player name, email, IP, device id, wallet balance, bet, or raw transaction. The ingest runs an allowlist validator — any field outside the schema is rejected with 400, so a future integration cannot accidentally leak PII.

Endpoint

POST https://staging.fidra.tech/api/outcomes
  header: x-fidra-outcomes-key: <your per-tenant key>
  body:   one row, or an array of rows (a day's batch, ≤ 500)
  → 200 { ok: true, accepted: N } · 400 invalid (with reason) · 401 bad key · 429 rate limited

Idempotent per (userRef, day): re-reporting a day overwrites it — a corrected backfill is safe. Swap the host for production at go-live.

Currency normalization — the rule of one

One tenant reports in one currency, always. Multi-currency wagering (multi-crypto or dual-rail wallets) is normalized by you before reporting — you already do this for your own P&L. The integration contract records: the reporting currency (most crypto operators: USDT/USD), the FX source, and the rate-fixing moment — at bet time, not end-of-day, so market moves can't masquerade as NGR movement. fidra never converts; if rows arrive in more than one currency the dashboard refuses the readout instead of summing mixed units.

How the number is computed — intention-to-treat

The readout joins your rows to the holdout assignments by userRef, sums each user's window NGR, and compares arms counting every assigned user — non-openers enter treatment at their real, often-lower NGR. That is what keeps the estimate honest. The estimator, its 95% CI, the surface decomposition and the underpowered guard are unit-tested in @fidra/measurement; method detail ships in docs/METHODOLOGY.md.

Versioning

schemaVersion on every row is the outcome contract version (independent of the event schema version). Current: 2 — adds the required currency field. v1 rows are still accepted against the v1 allowlist (which predates currency), so in-flight reports never silently fail; new integrations report v2.

source of truth: docs/integration/MEASUREMENT.md · docs/integration/EVENTS.md fidra is a B2B software supplier — no gambling services operated, no player funds held. g.jgerenaia@tomsons.co