{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/frase-io/json-schema/frase-io-industry-benchmark-payload-schema.json",
  "title": "IndustryBenchmarkPayload",
  "description": "Composite industry-benchmark payload. Methodology fields (contributingOrgs, sampleSize, sampleWeightSum, outlierSuppressed) are intentionally absent from the wire shape and stripped at the route's stitch boundary regardless of helper-return drift. The `meta` field is additive and not required — older API pods during a rolling deploy may omit it; consumers must tolerate its absence.",
  "x-generated": "2026-11-09",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/frase-io-openapi.json#/components/schemas/IndustryBenchmarkPayload",
  "type": "object",
  "required": [
    "context",
    "platforms",
    "geo",
    "shareOfVoice"
  ],
  "properties": {
    "context": {
      "type": "object",
      "required": [
        "vertical",
        "siteId",
        "weekStart"
      ],
      "properties": {
        "vertical": {
          "type": [
            "string",
            "null"
          ],
          "description": "Resolved industry vertical, or null when no vertical can be resolved for the org."
        },
        "siteId": {
          "type": [
            "string",
            "null"
          ],
          "format": "uuid",
          "description": "Echoed site_id; null when site_id was omitted OR silently dropped by the ownership gate."
        },
        "weekStart": {
          "type": [
            "string",
            "null"
          ],
          "format": "date",
          "description": "ISO YYYY-MM-DD week start for the underlying benchmark snapshot."
        }
      }
    },
    "platforms": {
      "type": "array",
      "description": "Per-platform citation rates merged from the org overlay (when include_org=true) and the industry baseline.",
      "items": {
        "type": "object",
        "required": [
          "platform",
          "orgRate",
          "p50",
          "p25",
          "p75"
        ],
        "properties": {
          "platform": {
            "type": "string",
            "description": "Canonical platform identifier (e.g. chatgpt, perplexity)."
          },
          "orgRate": {
            "type": [
              "number",
              "null"
            ],
            "description": "Org-aggregate citation rate. Null when include_org=false or no org data."
          },
          "p50": {
            "type": "number",
            "description": "Industry-median citation rate."
          },
          "p25": {
            "type": "number",
            "description": "Industry 25th-percentile citation rate."
          },
          "p75": {
            "type": "number",
            "description": "Industry 75th-percentile citation rate."
          }
        }
      }
    },
    "geo": {
      "type": [
        "object",
        "null"
      ],
      "description": "Geo score comparison. Null when the industry distribution is unavailable or below the k-anon floor.",
      "required": [
        "orgP50",
        "articleCount",
        "industryP50"
      ],
      "properties": {
        "orgP50": {
          "type": [
            "number",
            "null"
          ]
        },
        "articleCount": {
          "type": [
            "integer",
            "null"
          ]
        },
        "industryP50": {
          "type": "number"
        }
      }
    },
    "shareOfVoice": {
      "type": [
        "object",
        "null"
      ],
      "description": "Share-of-voice. Null when the industry-side k-anon gate dropped all rows.",
      "required": [
        "orgPct",
        "topDomain",
        "topPct"
      ],
      "properties": {
        "orgPct": {
          "type": [
            "number",
            "null"
          ]
        },
        "topDomain": {
          "type": "string"
        },
        "topPct": {
          "type": "number"
        }
      }
    },
    "meta": {
      "type": "object",
      "description": "Authoritative readiness signal for cross-surface consumers (UI strip, dashboard hoist, MCP get_industry_benchmark). All three surfaces gate identically on `ready`. `transient: true` means the reason clears as data accrues; `transient: false` is terminal (user action required).",
      "required": [
        "ready",
        "reason",
        "transient"
      ],
      "properties": {
        "ready": {
          "type": "boolean",
          "description": "True when every readiness predicate clears."
        },
        "reason": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "vertical_not_resolved",
            "card_1_no_share_of_voice",
            "card_2_insufficient_articles",
            "card_3_no_medians"
          ],
          "description": "Highest-priority failing predicate, or null when ready=true."
        },
        "transient": {
          "type": "boolean",
          "description": "True when the reason clears as data accrues (no user action required)."
        }
      }
    }
  }
}