{
  "license": "CC BY 4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "recipe": {
    "slug": "trial-to-paid-conversion",
    "title": "Calculate Trial-to-Paid Conversion",
    "testedWith": "Apache DataFusion 45.2.0",
    "lastReviewed": "2026-07-27"
  },
  "contract": {
    "tableName": "subscription_events",
    "schema": [
      {
        "name": "timestamp_utc",
        "type": "Timestamp",
        "description": "Subscription event time."
      },
      {
        "name": "account_id",
        "type": "Utf8",
        "description": "Stable billing account identifier."
      },
      {
        "name": "event_name",
        "type": "Utf8",
        "description": "trial_started or subscription_started."
      },
      {
        "name": "acquisition_source",
        "type": "Utf8",
        "description": "Source captured when the trial began."
      }
    ]
  },
  "query": "WITH trials AS (\n  SELECT\n    account_id,\n    MIN(timestamp_utc) AS trial_started_at,\n    MIN(acquisition_source) AS acquisition_source\n  FROM subscription_events\n  WHERE event_name = 'trial_started'\n    AND timestamp_utc >= now() - INTERVAL '120 days'\n  GROUP BY account_id\n),\npaid AS (\n  SELECT\n    account_id,\n    MIN(timestamp_utc) AS paid_at\n  FROM subscription_events\n  WHERE event_name = 'subscription_started'\n  GROUP BY account_id\n)\nSELECT\n  date_trunc('week', trials.trial_started_at) AS trial_week,\n  trials.acquisition_source,\n  COUNT(*) AS trial_accounts,\n  SUM(CASE\n    WHEN paid.paid_at >= trials.trial_started_at\n      AND paid.paid_at < trials.trial_started_at + INTERVAL '30 days'\n    THEN 1 ELSE 0\n  END) AS paid_accounts,\n  100.0 * SUM(CASE\n    WHEN paid.paid_at >= trials.trial_started_at\n      AND paid.paid_at < trials.trial_started_at + INTERVAL '30 days'\n    THEN 1 ELSE 0\n  END) / NULLIF(COUNT(*), 0) AS conversion_rate_pct\nFROM trials\nLEFT JOIN paid ON paid.account_id = trials.account_id\nGROUP BY\n  date_trunc('week', trials.trial_started_at),\n  trials.acquisition_source\nORDER BY trial_week, acquisition_source;",
  "fixtureKind": "schema-example",
  "inputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "account_id": "account_1",
      "event_name": "workflow_completed",
      "acquisition_source": "acquisition_source_example_1"
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "account_id": "account_2",
      "event_name": "workflow_completed",
      "acquisition_source": "acquisition_source_example_2"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "account_id": "account_3",
      "event_name": "workflow_completed",
      "acquisition_source": "acquisition_source_example_3"
    }
  ],
  "illustrativeInputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "account_id": "account_1",
      "event_name": "workflow_completed",
      "acquisition_source": "acquisition_source_example_1"
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "account_id": "account_2",
      "event_name": "workflow_completed",
      "acquisition_source": "acquisition_source_example_2"
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "account_id": "account_3",
      "event_name": "workflow_completed",
      "acquisition_source": "acquisition_source_example_3"
    }
  ],
  "expectedOutput": {
    "columns": [
      "trial_week",
      "acquisition_source",
      "trial_accounts",
      "paid_accounts",
      "conversion_rate_pct"
    ],
    "rows": [
      {
        "trial_week": "2026-06-29",
        "acquisition_source": "docs",
        "trial_accounts": 184,
        "paid_accounts": 41,
        "conversion_rate_pct": 22.28
      },
      {
        "trial_week": "2026-06-29",
        "acquisition_source": "paid_search",
        "trial_accounts": 310,
        "paid_accounts": 37,
        "conversion_rate_pct": 11.94
      },
      {
        "trial_week": "2026-07-06",
        "acquisition_source": "product_referral",
        "trial_accounts": 96,
        "paid_accounts": 28,
        "conversion_rate_pct": 29.17
      }
    ]
  },
  "notes": [
    "The compact input rows demonstrate field names and JSON types; they are not claimed to generate the displayed aggregate by themselves.",
    "The expected output is deterministic synthetic review data for the documented output shape.",
    "Adapt time windows, thresholds, identities, and business definitions before operational use."
  ]
}