{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/aisle-wedding/json-schema/aisle-wedding-guest-schema.json",
  "title": "Guest",
  "x-generated": "2026-11-01",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/aisle-wedding-openapi.json#/components/schemas/Guest",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "id",
    "first_name",
    "last_name",
    "phone",
    "phone_e164",
    "phone_status",
    "email",
    "party_id",
    "is_party_lead",
    "plus_one_allowance",
    "plus_one_for_guest_id",
    "rsvp_status",
    "rsvp_stage",
    "rsvp_responded_at",
    "rsvp_option_id",
    "rsvp_option_label",
    "rsvp_answers",
    "dietary_restrictions",
    "dietary_notes",
    "accommodation_id",
    "lodging_note",
    "address",
    "language",
    "notes",
    "tags",
    "broadcast_channel",
    "email_opted_out_at",
    "sms_opted_out",
    "whatsapp_opted_in_at",
    "preferred_transport",
    "preferred_transport_source",
    "created_at",
    "updated_at"
  ],
  "properties": {
    "id": {
      "$ref": "#/$defs/GuestId"
    },
    "first_name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120
    },
    "last_name": {
      "type": "string",
      "maxLength": 120
    },
    "phone": {
      "type": [
        "string",
        "null"
      ]
    },
    "email": {
      "type": [
        "string",
        "null"
      ],
      "format": "email"
    },
    "rsvp_status": {
      "type": "string",
      "enum": [
        "pending",
        "attending",
        "declined",
        "maybe"
      ],
      "description": "On update, explicitly setting this status clears the previous RSVP option ID and label. Omit it to preserve the guest's selected answer."
    },
    "dietary_restrictions": {
      "type": [
        "string",
        "null"
      ]
    },
    "dietary_notes": {
      "type": [
        "string",
        "null"
      ]
    },
    "accommodation_id": {
      "oneOf": [
        {
          "$ref": "#/$defs/AccommodationId"
        },
        {
          "type": "null"
        }
      ]
    },
    "lodging_note": {
      "type": [
        "string",
        "null"
      ]
    },
    "notes": {
      "type": [
        "string",
        "null"
      ]
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "language": {
      "type": [
        "string",
        "null"
      ]
    },
    "plus_one_allowance": {
      "type": "integer",
      "minimum": 0,
      "maximum": 8
    },
    "is_party_lead": {
      "type": "boolean"
    },
    "phone_e164": {
      "type": [
        "string",
        "null"
      ],
      "description": "Canonical E.164 identity with a leading +, or null when unresolved."
    },
    "phone_status": {
      "type": "string",
      "enum": [
        "valid",
        "missing",
        "invalid",
        "unresolved"
      ]
    },
    "party_id": {
      "oneOf": [
        {
          "$ref": "#/$defs/PartyId"
        },
        {
          "type": "null"
        }
      ]
    },
    "plus_one_for_guest_id": {
      "oneOf": [
        {
          "$ref": "#/$defs/GuestId"
        },
        {
          "type": "null"
        }
      ]
    },
    "rsvp_stage": {
      "type": [
        "string",
        "null"
      ]
    },
    "rsvp_responded_at": {
      "oneOf": [
        {
          "$ref": "#/$defs/Timestamp"
        },
        {
          "type": "null"
        }
      ]
    },
    "rsvp_option_id": {
      "type": [
        "string",
        "null"
      ]
    },
    "rsvp_option_label": {
      "type": [
        "string",
        "null"
      ]
    },
    "rsvp_answers": {
      "type": "object",
      "additionalProperties": true
    },
    "address": {
      "$ref": "#/$defs/GuestAddress"
    },
    "broadcast_channel": {
      "type": "string",
      "enum": [
        "email",
        "sms",
        "either"
      ]
    },
    "email_opted_out_at": {
      "oneOf": [
        {
          "$ref": "#/$defs/Timestamp"
        },
        {
          "type": "null"
        }
      ]
    },
    "sms_opted_out": {
      "type": "boolean"
    },
    "whatsapp_opted_in_at": {
      "description": "Explicit recipient WhatsApp consent for the current canonical number, recorded from their own choice or inbound message. Cleared on phone identity change.",
      "oneOf": [
        {
          "$ref": "#/$defs/Timestamp"
        },
        {
          "type": "null"
        }
      ]
    },
    "preferred_transport": {
      "type": "string",
      "enum": [
        "sms",
        "whatsapp"
      ],
      "description": "Preferred transport. SMS delivery depends on provider country permissions. WhatsApp also requires recipient consent and an open service window or approved template."
    },
    "preferred_transport_source": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "couple",
        "guest",
        "elena",
        "api",
        "system",
        null
      ],
      "description": "Who chose the preference. Recipient WhatsApp consent is recorded separately in whatsapp_opted_in_at; an API preference change does not grant consent."
    },
    "created_at": {
      "$ref": "#/$defs/Timestamp"
    },
    "updated_at": {
      "$ref": "#/$defs/Timestamp"
    }
  },
  "$defs": {
    "AccommodationId": {
      "type": "string",
      "pattern": "^acc_.+$"
    },
    "GuestAddress": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "line1",
        "line2",
        "city",
        "region",
        "postal_code",
        "country"
      ],
      "properties": {
        "line1": {
          "type": [
            "string",
            "null"
          ]
        },
        "line2": {
          "type": [
            "string",
            "null"
          ]
        },
        "city": {
          "type": [
            "string",
            "null"
          ]
        },
        "region": {
          "type": [
            "string",
            "null"
          ]
        },
        "postal_code": {
          "type": [
            "string",
            "null"
          ]
        },
        "country": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "GuestId": {
      "type": "string",
      "pattern": "^gst_.+$"
    },
    "PartyId": {
      "type": "string",
      "pattern": "^pty_.+$"
    },
    "Timestamp": {
      "type": "string",
      "format": "date-time",
      "description": "An RFC 3339 UTC timestamp with milliseconds."
    }
  }
}