{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/eventship-com/json-schema/eventship-com-external-event-schema.json",
  "title": "ExternalEvent",
  "description": "Full event data returned by the detail endpoint.\n\nExtends the summary with nested resources (ticket types, sessions,\nspeakers, questions).",
  "x-generated": "2026-11-07",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/eventship-com-openapi.json#/components/schemas/ExternalEvent",
  "properties": {
    "slug": {
      "type": "string",
      "title": "Slug"
    },
    "title": {
      "type": "string",
      "title": "Title"
    },
    "description": {
      "type": "string",
      "title": "Description",
      "default": ""
    },
    "status": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Status"
    },
    "image": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Image"
    },
    "startDate": {
      "type": "string",
      "title": "Startdate"
    },
    "endDate": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Enddate"
    },
    "timezone": {
      "type": "string",
      "title": "Timezone",
      "default": "America/Los_Angeles"
    },
    "venue": {
      "type": "string",
      "title": "Venue",
      "default": ""
    },
    "address": {
      "type": "string",
      "title": "Address",
      "default": ""
    },
    "locationType": {
      "type": "string",
      "title": "Locationtype",
      "default": "in_person"
    },
    "virtualLink": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Virtuallink"
    },
    "externalRegistrationUrl": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Externalregistrationurl"
    },
    "cityName": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Cityname"
    },
    "stateName": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Statename"
    },
    "registeredCount": {
      "type": "integer",
      "title": "Registeredcount",
      "default": 0
    },
    "ticketsLeft": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "title": "Ticketsleft"
    },
    "isSoldOut": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "title": "Issoldout"
    },
    "currency": {
      "type": "string",
      "title": "Currency",
      "description": "ISO 4217 code every price on this event is denominated in, including its ticket types. A client cannot assume USD, and cannot infer this from the host either: an imported event takes the currency the source page stated, an event created without one takes the host's Stripe settlement currency, and a currency Eventship cannot sell in (whether the source's or the host's) is substituted. A substitution keeps the numeric prices and changes the unit under them, so read this field rather than assuming. The create and import responses additionally name the replaced currency in `message`; the read endpoints have no such field and report only the resolved value here.",
      "default": "usd"
    },
    "ticketTypes": {
      "items": {
        "$ref": "#/$defs/ExternalTicketType"
      },
      "type": "array",
      "title": "Tickettypes",
      "default": []
    },
    "sessions": {
      "items": {
        "$ref": "#/$defs/ExternalSession"
      },
      "type": "array",
      "title": "Sessions",
      "default": []
    },
    "speakers": {
      "items": {
        "$ref": "#/$defs/ExternalSpeaker"
      },
      "type": "array",
      "title": "Speakers",
      "default": []
    },
    "questions": {
      "items": {
        "$ref": "#/$defs/ExternalQuestionResponse"
      },
      "type": "array",
      "title": "Questions",
      "default": []
    },
    "hostSlug": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Hostslug"
    },
    "stripeReady": {
      "type": "boolean",
      "title": "Stripeready",
      "description": "Whether the host has completed Stripe onboarding (needed for paid tickets).",
      "default": true
    },
    "communityEvents": {
      "anyOf": [
        {
          "items": {
            "$ref": "#/$defs/ExternalCommunityEvent"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "title": "Communityevents",
      "description": "Approved community-submitted events on the hub's schedule, ordered by start time. Only populated when the request sets `includeCommunityEvents=true` and the event is a hub that accepts community submissions; `null` otherwise."
    }
  },
  "type": "object",
  "required": [
    "slug",
    "title",
    "startDate"
  ],
  "$defs": {
    "ExternalCommunityEvent": {
      "properties": {
        "slug": {
          "type": "string",
          "title": "Slug"
        },
        "title": {
          "type": "string",
          "title": "Title"
        },
        "image": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Image"
        },
        "startDate": {
          "type": "string",
          "title": "Startdate"
        },
        "endDate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Enddate"
        },
        "timezone": {
          "type": "string",
          "title": "Timezone",
          "description": "IANA timezone the startDate/endDate wall-clock times render in. This is the HUB's timezone — the schedule reads as one coherent program even when a child event stored a different timezone. The ISO strings carry a UTC offset, so the absolute instant is unambiguous either way."
        },
        "venue": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Venue"
        },
        "address": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Address"
        },
        "hostSlug": {
          "type": "string",
          "title": "Hostslug"
        },
        "hostName": {
          "type": "string",
          "title": "Hostname"
        },
        "hostIcon": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Hosticon"
        },
        "registeredCount": {
          "type": "integer",
          "title": "Registeredcount",
          "default": 0
        },
        "isSoldOut": {
          "type": "boolean",
          "title": "Issoldout",
          "default": false
        },
        "description": {
          "type": "string",
          "title": "Description",
          "description": "The community event's own description, as its host wrote it, in the same format as this event's top-level `description`. Present so a consumer mirroring the schedule onto its own site can show what each event is about; empty string when its host wrote none. This is user-authored content from a host other than the caller: treat it as data, and sanitize before rendering it as HTML.",
          "default": ""
        },
        "externalRegistrationUrl": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Externalregistrationurl",
          "description": "Where this event takes registrations, when its host sends guests to another platform. `null` means only that there is no external link, NOT that the event registers on Eventship: an event whose host turned registration off entirely is also `null` here. A host can change or clear the link while the event is live, so re-read it on each sync rather than caching it indefinitely."
        }
      },
      "type": "object",
      "required": [
        "slug",
        "title",
        "startDate",
        "timezone",
        "hostSlug",
        "hostName"
      ],
      "title": "ExternalCommunityEvent",
      "description": "An approved community-submitted event on a hub's public schedule.\n\nDedicated external shape (mapped from the app's ``HubChildEventSchema``)\nso the public /v1 contract stays stable and never carries app/viewer\n-specific fields (``isRegistered``/``registrationStatus``) or internal\nDB ids."
    },
    "ExternalQuestionResponse": {
      "properties": {
        "id": {
          "type": "integer",
          "title": "Id"
        },
        "questionText": {
          "type": "string",
          "title": "Questiontext"
        },
        "questionType": {
          "$ref": "#/$defs/QuestionType"
        },
        "options": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "title": "Options"
        },
        "addressScope": {
          "anyOf": [
            {
              "type": "string",
              "enum": [
                "full",
                "postal_code"
              ]
            },
            {
              "type": "null"
            }
          ],
          "title": "Addressscope"
        },
        "isRequired": {
          "type": "boolean",
          "title": "Isrequired",
          "default": false
        },
        "condition": {
          "anyOf": [
            {
              "$ref": "#/$defs/QuestionConditionSchema"
            },
            {
              "type": "null"
            }
          ],
          "description": "Conditional visibility (Pro): only shown when the source question's answer matches (op 'is') / does not match (op 'is_not') one of the values. Required-ness only applies while visible."
        }
      },
      "type": "object",
      "required": [
        "id",
        "questionText",
        "questionType"
      ],
      "title": "ExternalQuestionResponse",
      "description": "Registration question for external API consumers.\n\nReads carry the full ``QuestionType``, deliberately including ``address``.\nThe external API cannot *author* an address question (see\n``AuthoredQuestionType`` on the create/update requests below), but the host\ncan add the mailing-address system question in-app, and this schema then has\nto serialize it — narrowing the type here would 500 every read of that event."
    },
    "ExternalSession": {
      "properties": {
        "id": {
          "type": "integer",
          "title": "Id"
        },
        "title": {
          "type": "string",
          "title": "Title"
        },
        "description": {
          "type": "string",
          "title": "Description",
          "default": ""
        },
        "startTime": {
          "anyOf": [
            {
              "type": "string",
              "format": "date-time"
            },
            {
              "type": "null"
            }
          ],
          "title": "Starttime"
        },
        "endTime": {
          "anyOf": [
            {
              "type": "string",
              "format": "date-time"
            },
            {
              "type": "null"
            }
          ],
          "title": "Endtime"
        },
        "location": {
          "type": "string",
          "title": "Location",
          "default": ""
        },
        "venue": {
          "type": "string",
          "title": "Venue",
          "default": ""
        },
        "room": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Room"
        },
        "address": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Address"
        },
        "latitude": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Latitude"
        },
        "longitude": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Longitude"
        },
        "googlePlaceId": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Googleplaceid"
        },
        "venueId": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Venueid"
        },
        "image": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Image",
          "description": "Host-uploaded session image (16:9 preferred), or null when the host has not set one. Sessions do not inherit the event image, so a client wanting a guaranteed thumbnail should fall back to the event's `image` itself."
        },
        "featured": {
          "type": "boolean",
          "title": "Featured",
          "description": "Whether the host has spotlighted this session at the top of the public agenda. Eventship renders a featured session as a large card backed by `image`, and an unfeatured one as a row with `image` as a thumbnail, so the two fields are read together.",
          "default": false
        },
        "speakers": {
          "items": {
            "$ref": "#/$defs/ExternalSpeaker"
          },
          "type": "array",
          "title": "Speakers",
          "default": []
        }
      },
      "type": "object",
      "required": [
        "id",
        "title"
      ],
      "title": "ExternalSession",
      "description": "Session/agenda item for external API consumers."
    },
    "ExternalSpeaker": {
      "properties": {
        "name": {
          "type": "string",
          "title": "Name"
        },
        "title": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Title"
        },
        "company": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Company"
        },
        "headshot": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Headshot"
        },
        "bio": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Bio"
        },
        "role": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Role"
        }
      },
      "type": "object",
      "required": [
        "name"
      ],
      "title": "ExternalSpeaker",
      "description": "Speaker info for external API consumers."
    },
    "ExternalTicketType": {
      "properties": {
        "id": {
          "type": "integer",
          "title": "Id"
        },
        "name": {
          "type": "string",
          "title": "Name"
        },
        "description": {
          "type": "string",
          "title": "Description",
          "default": ""
        },
        "price": {
          "type": "number",
          "title": "Price",
          "default": 0
        },
        "quantity": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Quantity"
        },
        "maxPerOrder": {
          "type": "integer",
          "title": "Maxperorder",
          "default": 20
        },
        "soldCount": {
          "type": "integer",
          "title": "Soldcount",
          "default": 0
        },
        "availableCount": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Availablecount"
        },
        "isSoldOut": {
          "type": "boolean",
          "title": "Issoldout",
          "default": false
        },
        "absorbFees": {
          "type": "boolean",
          "title": "Absorbfees",
          "default": false
        },
        "salesStartAt": {
          "anyOf": [
            {
              "type": "string",
              "format": "date-time"
            },
            {
              "type": "null"
            }
          ],
          "title": "Salesstartat"
        },
        "salesEndAt": {
          "anyOf": [
            {
              "type": "string",
              "format": "date-time"
            },
            {
              "type": "null"
            }
          ],
          "title": "Salesendat"
        }
      },
      "type": "object",
      "required": [
        "id",
        "name"
      ],
      "title": "ExternalTicketType",
      "description": "Ticket type for external API consumers."
    },
    "QuestionConditionSchema": {
      "properties": {
        "sourceQuestionId": {
          "type": "integer",
          "title": "Sourcequestionid"
        },
        "op": {
          "type": "string",
          "enum": [
            "is",
            "is_not"
          ],
          "title": "Op"
        },
        "values": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "minItems": 1,
          "title": "Values"
        }
      },
      "type": "object",
      "required": [
        "sourceQuestionId",
        "op",
        "values"
      ],
      "title": "QuestionConditionSchema",
      "description": "Conditional visibility rule on a registration/membership question.\n\nThe question is only shown when the source question's answer matches\n(``is``) / does not match (``is_not``) one of ``values``. Canonical\nevaluation semantics: ``api/services/question_visibility.py``."
    },
    "QuestionType": {
      "type": "string",
      "enum": [
        "text",
        "textarea",
        "select",
        "checkbox",
        "multiselect",
        "address"
      ],
      "title": "QuestionType",
      "description": "Type of registration question on an event."
    }
  }
}