{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/craftingeventfinder-com/json-schema/craftingeventfinder-com-public-organizer-schema.json",
  "title": "PublicOrganizer",
  "x-generated": "2026-11-10",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/craftingeventfinder-com-organizers-api-openapi.yml#/components/schemas/PublicOrganizer",
  "type": "object",
  "properties": {
    "slug": {
      "type": "string",
      "description": "The public address's last part: /organizers/{slug}"
    },
    "displayName": {
      "type": "string"
    },
    "about": {
      "type": [
        "string",
        "null"
      ]
    },
    "website": {
      "type": [
        "string",
        "null"
      ]
    },
    "city": {
      "type": [
        "string",
        "null"
      ]
    },
    "state": {
      "type": [
        "string",
        "null"
      ]
    },
    "crafts": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Top-level craft slugs, in taxonomy order"
    },
    "avatarUrl": {
      "type": [
        "string",
        "null"
      ],
      "description": "The 512px picture, or null when the default badge shows"
    },
    "avatarSmallUrl": {
      "type": [
        "string",
        "null"
      ],
      "description": "The 96px picture"
    },
    "defaultAvatar": {
      "type": "string",
      "description": "The built-in badge, '<craft icon>-<color 1-6>'"
    },
    "upcoming": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/OrganizerEvent"
      },
      "description": "Published events still to come on this site, soonest first, at most 50"
    },
    "past": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/OrganizerEvent"
      },
      "description": "The newest 12 published events that are over"
    }
  },
  "required": [
    "slug",
    "displayName",
    "about",
    "website",
    "city",
    "state",
    "crafts",
    "avatarUrl",
    "avatarSmallUrl",
    "defaultAvatar",
    "upcoming",
    "past"
  ],
  "$defs": {
    "Event": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "slug": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "description": {
          "type": [
            "string",
            "null"
          ]
        },
        "summary": {
          "type": [
            "string",
            "null"
          ]
        },
        "start_date": {
          "type": "string"
        },
        "end_date": {
          "type": [
            "string",
            "null"
          ]
        },
        "start_time": {
          "type": [
            "string",
            "null"
          ]
        },
        "end_time": {
          "type": [
            "string",
            "null"
          ]
        },
        "timezone": {
          "type": [
            "string",
            "null"
          ]
        },
        "city": {
          "type": "string"
        },
        "state": {
          "type": "string"
        },
        "venue": {
          "type": [
            "string",
            "null"
          ]
        },
        "location_kind": {
          "type": "string",
          "enum": [
            "venue",
            "online",
            "hybrid",
            "multi"
          ],
          "description": "venue, online, hybrid (one place and online at once) or multi (several places)"
        },
        "street_address": {
          "type": [
            "string",
            "null"
          ]
        },
        "postal_code": {
          "type": [
            "string",
            "null"
          ]
        },
        "signup_note": {
          "type": [
            "string",
            "null"
          ]
        },
        "craft_types": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "event_type": {
          "type": [
            "string",
            "null"
          ]
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "url": {
          "type": [
            "string",
            "null"
          ]
        },
        "source_url": {
          "type": [
            "string",
            "null"
          ]
        },
        "organizer_name": {
          "type": [
            "string",
            "null"
          ]
        },
        "lat": {
          "type": [
            "number",
            "null"
          ]
        },
        "lng": {
          "type": [
            "number",
            "null"
          ]
        },
        "price_note": {
          "type": [
            "string",
            "null"
          ]
        },
        "is_free": {
          "type": [
            "boolean",
            "null"
          ]
        },
        "published_at": {
          "type": [
            "string",
            "null"
          ]
        },
        "languages": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "The languages it is held in, as BCP 47 codes (en, es); empty when unknown"
        },
        "hosted_by": {
          "type": [
            "string",
            "null"
          ],
          "description": "The group or shop hosting an online or hybrid event, when given"
        },
        "hasJoinDetails": {
          "type": "boolean",
          "description": "An online or hybrid event with join details (link, meeting ID, passcode or dial-in); get them from GET /api/events/{slug}/join"
        },
        "joinPlatform": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "zoom",
            "meet",
            "teams",
            "webex",
            "facebook",
            "youtube",
            "other",
            null
          ],
          "description": "The online meeting platform, for online events"
        },
        "contactName": {
          "type": [
            "string",
            "null"
          ],
          "description": "The organizer's contact person"
        },
        "hasContactDetails": {
          "type": "boolean",
          "description": "A contact email or phone exists; get them from GET /api/events/{slug}/contact"
        },
        "isNew": {
          "type": "boolean",
          "description": "Published within the last 7 days"
        },
        "updatedRecently": {
          "type": "boolean",
          "description": "Its date, time, place or price changed within the last 7 days"
        },
        "changedFields": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "date",
              "time",
              "place",
              "price"
            ]
          },
          "description": "What changed (date, time, place, price); empty unless updatedRecently"
        },
        "contentChangedAt": {
          "type": [
            "string",
            "null"
          ],
          "description": "When its date, time, place or price last changed; null if never"
        },
        "cancelled": {
          "type": "boolean",
          "description": "A cancelled event (only GET /api/events/{slug} returns one, until its dates pass); lists never include it"
        },
        "scheduleChange": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "postponed",
            "rescheduled",
            "moved_online",
            null
          ],
          "description": "postponed (new date to come), rescheduled or moved_online; null when it runs as listed"
        },
        "previousStartDate": {
          "type": [
            "string",
            "null"
          ],
          "description": "The start date a rescheduled event had before (YYYY-MM-DD); null otherwise"
        },
        "images": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/PublicEventImage"
          },
          "description": "The organizer's pictures in order, at most 6; the first is the cover. Empty when there are none"
        }
      },
      "required": [
        "id",
        "slug",
        "title",
        "description",
        "summary",
        "start_date",
        "end_date",
        "start_time",
        "end_time",
        "timezone",
        "city",
        "state",
        "venue",
        "location_kind",
        "street_address",
        "postal_code",
        "signup_note",
        "craft_types",
        "event_type",
        "tags",
        "url",
        "source_url",
        "organizer_name",
        "lat",
        "lng",
        "price_note",
        "is_free",
        "published_at",
        "languages",
        "hosted_by",
        "hasJoinDetails",
        "joinPlatform",
        "contactName",
        "hasContactDetails",
        "isNew",
        "updatedRecently",
        "changedFields",
        "contentChangedAt",
        "cancelled",
        "scheduleChange",
        "previousStartDate",
        "images"
      ]
    },
    "OrganizerEvent": {
      "allOf": [
        {
          "$ref": "#/$defs/Event"
        },
        {
          "type": "object",
          "properties": {
            "nextStartDate": {
              "type": [
                "string",
                "null"
              ],
              "description": "The next occurrence's start date, or null when it has none left (a repeating event's own dates are only its first)"
            },
            "nextEndDate": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          "required": [
            "nextStartDate",
            "nextEndDate"
          ]
        }
      ]
    },
    "PublicEventImage": {
      "type": "object",
      "properties": {
        "url": {
          "type": "string",
          "description": "The picture at most 1600px wide (WebP)"
        },
        "cardUrl": {
          "type": "string",
          "description": "The picture at most 600px wide (WebP), for cards"
        },
        "alt": {
          "type": "string",
          "description": "The description read to people who can't see the picture"
        },
        "width": {
          "type": "integer"
        },
        "height": {
          "type": "integer"
        },
        "focusX": {
          "type": "number",
          "description": "The focus point across, 0 (left) to 1 (right), kept in view when the picture is cropped"
        },
        "focusY": {
          "type": "number",
          "description": "The focus point down, 0 (top) to 1 (bottom)"
        }
      },
      "required": [
        "url",
        "cardUrl",
        "alt",
        "width",
        "height",
        "focusX",
        "focusY"
      ]
    }
  }
}