PPactDocs
Productivity

Today's analytics

The RevOps day-flow: a single page of KPIs, anomaly deltas, multi-touch attribution, and forecasts, each tenant-scoped and ETag-cached.

Today's analytics

Today is the RevOps day-flow — one page that answers "what changed, what's on fire, and where is revenue coming from?" without stitching together five reports. It composes a KPI strip, a pipeline funnel, velocity and consent charts, an owner leaderboard, win/loss reasons, and — the RevOps core — anomaly detection, attribution, and forecasts.

Live surface

The page is real and backed by enforced, tenant-scoped endpoints. Every read derives tenant_id from the auth context, is gated behind require_module("analytics"), and returns the standard {"data": ..., "generated_at": ...} envelope.

What feeds the page

The KPI strip, funnel, and consent donut come from /v1/dashboard/summary. The RevOps intelligence — the part that makes Today more than a dashboard — comes from core.analytics_revops, exposed under three endpoints:

  • GET /v1/analytics/anomalies — current window vs. prior window deltas for canonical KPIs (win rate, open rate, pipeline value, average cycle days). Returns only KPIs whose absolute delta clears the lowest band (10%), each tagged severity and is_alarm. An empty list means nothing is on fire.
  • GET /v1/analytics/attribution — multi-touch revenue attribution per channel. Models: first_touch, last_touch, linear (default), time_decay.
  • GET /v1/analytics/forecasts — projected pipeline / bookings.

The wider flagship charts — cohort retention, activity-by-hour heatmap, sequence heatmap, account density, enrichment costs, DSAR queue, win/loss reasons — are served by /v1/analytics/* (see api/routes/analytics_flagship.py) and lazy- loaded on the client so first paint isn't blocked by the ~110 KB chart bundle.

Anomalies as a first-class signal

bash
curl -s "https://api.pact.place/v1/analytics/anomalies?window_days=7" \
  -H "Authorization: Bearer $PACT_API_KEY"
json
{
  "data": {
    "items": [
      {"kpi_id": "win_rate", "label": "Win rate", "current": 22.0,
       "prior": 31.0, "delta": -9.0, "delta_pct": -29.0,
       "severity": "medium", "is_alarm": true, "window_days": 7}
    ],
    "window_days": 7,
    "current_window": {"since": "...", "until": "..."},
    "prior_window":   {"since": "...", "until": "..."}
  },
  "generated_at": "..."
}

Attribution is where Pact's consent-native posture shows up in the numbers. Each channel row carries a consent_violations count — touches that happened during a revoked-consent window. RevOps can quarantine credit that would otherwise look "won" but rests on a touch the contact had already opted out of. That is the differentiator versus attribution in Adobe, Looker, or Tableau, where consent state simply isn't in the model.

Caching

Each endpoint is ETag-cached: the response fingerprint (minus the volatile generated_at) is hashed with the tenant id into a weak ETag, and repeat requests with If-None-Match get a 304 with Cache-Control: private, max-age=60. Poll it on a timer without paying for a recompute every tick.