{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://xaller.ai/schemas/webhooks/v1.json",
  "title": "Xaller webhook delivery, version 1",
  "description": "Body of every POST Xaller sends to a webhook endpoint. Additive changes (new optional fields) keep version 1; receivers must ignore fields they don't know.",
  "type": "object",
  "required": ["id", "type", "version", "created_at", "data"],
  "properties": {
    "id": {
      "description": "Delivery ID, equal to the X-Xaller-Delivery-Id header. The same across retries, so receivers can de-duplicate.",
      "type": "string",
      "format": "uuid"
    },
    "type": {"enum": ["call.completed", "call.missed", "test"]},
    "version": {"const": 1},
    "created_at": {"type": "string", "format": "date-time"},
    "data": {"$ref": "#/$defs/data"}
  },
  "$defs": {
    "urgency": {"enum": ["low", "normal", "high", "emergency", null]},
    "data": {
      "type": "object",
      "required": [
        "call_id",
        "account_id",
        "content",
        "started_at",
        "ended_at",
        "duration_seconds",
        "mode",
        "language",
        "outcome",
        "sentiment",
        "urgency",
        "follow_up_required",
        "dashboard_url"
      ],
      "properties": {
        "call_id": {"type": ["string", "null"], "format": "uuid", "description": "Null for test deliveries."},
        "account_id": {"type": "string", "format": "uuid"},
        "content": {
          "enum": ["full", "minimal"],
          "description": "minimal: HIPAA-mode accounts without a signed PHI attestation for this endpoint. Content fields are then absent."
        },
        "started_at": {"type": "string", "format": "date-time"},
        "ended_at": {"type": ["string", "null"], "format": "date-time"},
        "duration_seconds": {"type": ["integer", "null"], "minimum": 0},
        "mode": {"enum": ["phone", "test"]},
        "language": {"type": ["string", "null"], "description": "en or es"},
        "outcome": {
          "enum": [
            "new_lead",
            "message_taken",
            "question_answered",
            "appointment_request",
            "existing_customer",
            "wrong_number",
            "spam",
            "hang_up",
            "other",
            null
          ]
        },
        "sentiment": {"enum": ["positive", "neutral", "negative", null]},
        "urgency": {"$ref": "#/$defs/urgency"},
        "follow_up_required": {"type": ["boolean", "null"]},
        "summary_unavailable": {"type": "boolean"},
        "missed_reason": {
          "type": ["string", "null"],
          "description": "For call.missed: why the agent couldn't answer (agent_paused, trial_minutes_exhausted, payment_overdue, ...)."
        },
        "dashboard_url": {"type": "string", "format": "uri", "description": "Opens the call in Xaller; requires sign-in."},
        "headline": {"type": ["string", "null"]},
        "summary": {"type": ["string", "null"]},
        "next_step": {"type": ["string", "null"]},
        "caller_name": {"type": ["string", "null"]},
        "caller_number": {"type": ["string", "null"], "description": "E.164"},
        "returning_caller_count": {"type": "integer", "minimum": 0},
        "details": {
          "type": "object",
          "properties": {
            "callback_number": {"type": ["string", "null"]},
            "reason": {"type": ["string", "null"]},
            "requested_service": {"type": ["string", "null"]},
            "preferred_callback_time": {"type": ["string", "null"]},
            "qualification_answers": {
              "type": "array",
              "items": {
                "type": "object",
                "required": ["question", "answer"],
                "properties": {"question": {"type": "string"}, "answer": {"type": "string"}}
              }
            }
          }
        },
        "transcript": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["speaker", "text"],
            "properties": {
              "speaker": {"enum": ["caller", "agent"]},
              "text": {"type": "string"},
              "start_ms": {"type": ["integer", "null"]},
              "end_ms": {"type": ["integer", "null"]}
            }
          }
        },
        "transcript_truncated": {"type": "boolean"}
      },
      "if": {"properties": {"content": {"const": "minimal"}}},
      "then": {
        "not": {
          "anyOf": [
            {"required": ["headline"]},
            {"required": ["summary"]},
            {"required": ["next_step"]},
            {"required": ["caller_name"]},
            {"required": ["caller_number"]},
            {"required": ["details"]},
            {"required": ["transcript"]}
          ]
        }
      }
    }
  }
}
