{
  "openapi": "3.1.0",
  "info": {
    "title": "Crafting Event Finder API",
    "version": "1.0.0",
    "description": "Everything the site does is available here, and as MCP tools at /api/mcp."
  },
  "servers": [
    {
      "url": "https://craftingeventfinder.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from /admin/api-keys: Authorization: Bearer cef_<scope>_..."
      },
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "cef_session"
      }
    },
    "schemas": {
      "EventImage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "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"
          },
          "position": {
            "type": "integer",
            "description": "Its place in the order, from 0; 0 is the cover"
          },
          "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": [
          "id",
          "url",
          "cardUrl",
          "alt",
          "width",
          "height",
          "position",
          "focusX",
          "focusY"
        ]
      },
      "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"
        ]
      },
      "EventImages": {
        "type": "object",
        "properties": {
          "images": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventImage"
            },
            "description": "The event's pictures in order, at most 6"
          }
        },
        "required": [
          "images"
        ]
      },
      "EventImageUpload": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "The picture (JPEG, PNG, WebP or HEIC, at most 4 MB): a file part in multipart/form-data, or base64 when sent as JSON (MCP)"
          },
          "alt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Describe the picture for people who can't see it, 1 to 200 characters"
          }
        },
        "required": [
          "file",
          "alt"
        ]
      },
      "EventImagePatch": {
        "type": "object",
        "properties": {
          "alt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "position": {
            "type": "integer",
            "minimum": 0,
            "description": "Move the picture to this place in the order (0 makes it the cover); a number past the end moves it last"
          },
          "focusX": {
            "type": "number",
            "description": "0 to 1; values outside are clamped"
          },
          "focusY": {
            "type": "number",
            "description": "0 to 1; values outside are clamped"
          }
        },
        "additionalProperties": false
      },
      "ImageToCheck": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventSlug": {
            "type": "string",
            "description": "The event page is /events/{eventSlug} while the event is published"
          },
          "eventTitle": {
            "type": "string"
          },
          "eventStatus": {
            "type": "string",
            "enum": [
              "published",
              "cancelled",
              "hidden"
            ],
            "description": "A hidden or cancelled event has no public page"
          },
          "cardUrl": {
            "type": "string",
            "description": "The picture at most 600px wide (WebP)"
          },
          "alt": {
            "type": "string",
            "description": "The organizer's description of the picture"
          },
          "organizerEmail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who uploaded it, or null when that account is gone"
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "eventId",
          "eventSlug",
          "eventTitle",
          "eventStatus",
          "cardUrl",
          "alt",
          "organizerEmail",
          "createdAt"
        ]
      },
      "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": "#/components/schemas/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"
        ]
      },
      "EventSearchItem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          },
          {
            "type": "object",
            "properties": {
              "next_start": {
                "type": "string"
              },
              "next_end": {
                "type": "string"
              },
              "occurrence_count": {
                "type": "integer"
              },
              "distance_miles": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "recurrence_label": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "featured": {
                "type": "boolean"
              }
            },
            "required": [
              "next_start",
              "next_end",
              "occurrence_count",
              "distance_miles",
              "recurrence_label",
              "featured"
            ]
          }
        ]
      },
      "EventManager": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Their public page: /organizers/{slug} (GET /api/organizers/{slug})"
          },
          "displayName": {
            "type": "string"
          },
          "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>'"
          }
        },
        "required": [
          "slug",
          "displayName",
          "avatarUrl",
          "avatarSmallUrl",
          "defaultAvatar"
        ]
      },
      "EventDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          },
          {
            "type": "object",
            "properties": {
              "upcoming_dates": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "start": {
                      "type": "string"
                    },
                    "end": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "start",
                    "end"
                  ]
                }
              },
              "recurrence_label": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "owned": {
                "type": "boolean",
                "description": "An organizer manages this event (it can't be claimed)"
              },
              "managedBy": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/EventManager"
                  },
                  {
                    "type": [
                      "object",
                      "null"
                    ],
                    "description": "The managing organizer when their profile is public, else null (also null when owned is false)"
                  }
                ]
              }
            },
            "required": [
              "upcoming_dates",
              "recurrence_label",
              "owned",
              "managedBy"
            ]
          }
        ]
      },
      "CraftCount": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          }
        },
        "required": [
          "slug",
          "label",
          "count"
        ]
      },
      "StateCount": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "top_craft": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "state",
          "count",
          "top_craft"
        ]
      },
      "JoinDetails": {
        "type": "object",
        "properties": {
          "platform": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "zoom",
              "meet",
              "teams",
              "webex",
              "facebook",
              "youtube",
              "other",
              null
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          },
          "meetingId": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 40
          },
          "passcode": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 40
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 40
          }
        },
        "required": [
          "platform",
          "url",
          "meetingId",
          "passcode",
          "phone"
        ]
      },
      "EventContact": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 120
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 40
          }
        },
        "required": [
          "name",
          "email",
          "phone"
        ]
      },
      "AdminEvent": {
        "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"
            ]
          },
          "recurrence": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "venue": {
            "type": [
              "string",
              "null"
            ]
          },
          "lat": {
            "type": [
              "number",
              "null"
            ]
          },
          "lng": {
            "type": [
              "number",
              "null"
            ]
          },
          "location_kind": {
            "type": "string",
            "enum": [
              "venue",
              "online",
              "hybrid",
              "multi"
            ]
          },
          "street_address": {
            "type": [
              "string",
              "null"
            ]
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "signup_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hosted_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_platform": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "zoom",
              "meet",
              "teams",
              "webex",
              "facebook",
              "youtube",
              "other",
              null
            ]
          },
          "join_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_meeting_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_passcode": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact_phone": {
            "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"
            ]
          },
          "organizer_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "price_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_free": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "origin": {
            "type": "string",
            "enum": [
              "public",
              "scrape",
              "organizer"
            ]
          },
          "source_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "confidence": {
            "type": [
              "number",
              "null"
            ]
          },
          "source_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "organizer_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "series_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "published",
              "cancelled",
              "hidden"
            ]
          },
          "last_verified_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "auto_published": {
            "type": "boolean"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "owner_user_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The organizer who manages this event, or null"
          },
          "schedule_change": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "postponed",
              "rescheduled",
              "moved_online",
              null
            ],
            "description": "postponed, rescheduled or moved_online; null when it runs as listed"
          },
          "previous_start_date": {
            "type": [
              "string",
              "null"
            ],
            "description": "The start date a rescheduled event had before"
          }
        },
        "required": [
          "id",
          "slug",
          "title",
          "description",
          "summary",
          "start_date",
          "end_date",
          "start_time",
          "end_time",
          "timezone",
          "recurrence",
          "city",
          "state",
          "venue",
          "lat",
          "lng",
          "location_kind",
          "street_address",
          "postal_code",
          "signup_note",
          "join_platform",
          "join_url",
          "join_meeting_id",
          "join_passcode",
          "join_phone",
          "contact_name",
          "contact_email",
          "contact_phone",
          "craft_types",
          "event_type",
          "tags",
          "url",
          "organizer_name",
          "price_note",
          "is_free",
          "origin",
          "source_id",
          "source_url",
          "confidence",
          "source_key",
          "organizer_email",
          "series_id",
          "status",
          "last_verified_at",
          "auto_published",
          "published_at",
          "created_at",
          "updated_at",
          "owner_user_id"
        ]
      },
      "AdminEventListItem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AdminEvent"
          },
          {
            "type": "object",
            "properties": {
              "owner_email": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The managing organizer's email, or null when nobody manages it"
              }
            },
            "required": [
              "owner_email"
            ]
          }
        ]
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "scope": {
            "type": "string",
            "enum": [
              "read",
              "user",
              "admin"
            ]
          },
          "last4": {
            "type": "string"
          },
          "userId": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "lastUsedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "revokedAt": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "scope",
          "last4",
          "userId",
          "createdAt",
          "lastUsedAt",
          "revokedAt"
        ]
      },
      "PaletteSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "swatch": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id",
          "name",
          "swatch"
        ]
      },
      "Appearance": {
        "type": "object",
        "properties": {
          "theme": {
            "type": "string",
            "enum": [
              "county-fair",
              "craft-paper",
              "quilt-show",
              "gallery-linen",
              "sunny-fair"
            ]
          },
          "themeLabel": {
            "type": "string"
          },
          "seasonMode": {
            "type": "string",
            "enum": [
              "auto",
              "fixed",
              "off"
            ]
          },
          "seasonFixed": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "fall",
              "holiday",
              "winter",
              "spring",
              "summer",
              null
            ]
          },
          "season": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string",
                "enum": [
                  "fall",
                  "holiday",
                  "winter",
                  "spring",
                  "summer"
                ]
              },
              "label": {
                "type": "string"
              },
              "tagline": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "label",
              "tagline"
            ],
            "description": "The season showing right now, or null when seasons are off or the theme has none"
          },
          "seasons": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "enum": [
                    "fall",
                    "holiday",
                    "winter",
                    "spring",
                    "summer"
                  ]
                },
                "label": {
                  "type": "string"
                },
                "startsMonthDay": {
                  "type": "string",
                  "description": "MM-DD, Pacific time"
                }
              },
              "required": [
                "id",
                "label",
                "startsMonthDay"
              ]
            },
            "description": "The theme's seasons; empty for a theme without seasons"
          },
          "palette": {
            "type": [
              "string",
              "null"
            ],
            "description": "The color palette showing: the chosen one, else the theme's default; null for a theme without palettes"
          },
          "palettes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaletteSummary"
            },
            "description": "The theme's color palettes, its default first; empty for a theme without palettes"
          }
        },
        "required": [
          "theme",
          "themeLabel",
          "seasonMode",
          "seasonFixed",
          "season",
          "seasons",
          "palette",
          "palettes"
        ]
      },
      "ThemeSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "enum": [
              "county-fair",
              "craft-paper",
              "quilt-show",
              "gallery-linen",
              "sunny-fair"
            ]
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "swatch": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hasSeasons": {
            "type": "boolean"
          },
          "seasons": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "enum": [
                    "fall",
                    "holiday",
                    "winter",
                    "spring",
                    "summer"
                  ]
                },
                "label": {
                  "type": "string"
                },
                "startsMonthDay": {
                  "type": "string",
                  "description": "MM-DD, Pacific time"
                }
              },
              "required": [
                "id",
                "label",
                "startsMonthDay"
              ]
            },
            "description": "This theme's own seasons; empty for a theme without seasons"
          },
          "palettes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaletteSummary"
            },
            "description": "This theme's own color palettes, its default first; empty for a theme without palettes"
          }
        },
        "required": [
          "id",
          "label",
          "description",
          "swatch",
          "hasSeasons",
          "seasons",
          "palettes"
        ]
      },
      "AdminAppearance": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Appearance"
          },
          {
            "type": "object",
            "properties": {
              "themes": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ThemeSummary"
                }
              }
            },
            "required": [
              "themes"
            ]
          }
        ]
      },
      "AuditRecord": {
        "type": "object",
        "properties": {
          "id": {
            "type": "number"
          },
          "createdAt": {
            "type": "string"
          },
          "actorKind": {
            "type": "string",
            "enum": [
              "session",
              "apiKey",
              "system"
            ]
          },
          "actorUserId": {
            "type": [
              "string",
              "null"
            ]
          },
          "actorKeyId": {
            "type": [
              "string",
              "null"
            ]
          },
          "action": {
            "type": "string"
          },
          "targetType": {
            "type": "string"
          },
          "targetId": {
            "type": "string"
          },
          "before": {},
          "after": {},
          "tenantSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "ip": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "createdAt",
          "actorKind",
          "actorUserId",
          "actorKeyId",
          "action",
          "targetType",
          "targetId",
          "tenantSlug",
          "ip"
        ]
      },
      "AutomationSummary": {
        "type": "object",
        "properties": {
          "since": {
            "type": "string",
            "description": "The start of the 7-day window"
          },
          "autoPublished": {
            "type": "integer",
            "description": "New events auto-published in the last 7 days (excludes auto-merged updates and auto-settled duplicates)"
          },
          "autoMerged": {
            "type": "integer",
            "description": "Updates auto-merged into published events in the last 7 days"
          },
          "duplicatesMerged": {
            "type": "integer",
            "description": "Same-source duplicates auto-settled onto published events in the last 7 days"
          },
          "sourcesTrusted": {
            "type": "integer",
            "description": "Sources that became trusted in the last 7 days, automatically or through a first review"
          },
          "sourcesDistrusted": {
            "type": "integer",
            "description": "Sources that lost trust automatically in the last 7 days"
          },
          "spotChecks": {
            "type": "object",
            "properties": {
              "decided": {
                "type": "integer",
                "description": "Spot checks decided in the last 7 days"
              },
              "right": {
                "type": "integer",
                "description": "Of those, how many came back ok"
              }
            },
            "required": [
              "decided",
              "right"
            ]
          }
        },
        "required": [
          "since",
          "autoPublished",
          "autoMerged",
          "duplicatesMerged",
          "sourcesTrusted",
          "sourcesDistrusted",
          "spotChecks"
        ]
      },
      "Claim": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "method": {
            "type": "string",
            "enum": [
              "email_match",
              "admin",
              "invite"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected",
              "withdrawn"
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "dispute": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string"
          },
          "decidedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "rejectNote": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "eventId",
          "userId",
          "method",
          "status",
          "note",
          "dispute",
          "createdAt",
          "decidedAt",
          "rejectNote"
        ]
      },
      "ClaimWithEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Claim"
          },
          {
            "type": "object",
            "properties": {
              "event": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "slug": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "startDate": {
                    "type": "string"
                  },
                  "city": {
                    "type": "string"
                  },
                  "state": {
                    "type": "string"
                  },
                  "locationKind": {
                    "type": "string",
                    "description": "venue, online or multi: an online event's city and state are only its host's"
                  }
                },
                "required": [
                  "id",
                  "slug",
                  "title",
                  "startDate",
                  "city",
                  "state",
                  "locationKind"
                ]
              }
            },
            "required": [
              "event"
            ]
          }
        ]
      },
      "AdminClaim": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ClaimWithEvent"
          },
          {
            "type": "object",
            "properties": {
              "userEmail": {
                "type": "string"
              },
              "currentOwnerEmail": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "userEmail",
              "currentOwnerEmail"
            ]
          }
        ]
      },
      "ClaimResult": {
        "type": "object",
        "properties": {
          "claim": {
            "$ref": "#/components/schemas/Claim"
          }
        },
        "required": [
          "claim"
        ]
      },
      "MyClaims": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClaimWithEvent"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "Correction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventTitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "eventSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "correct",
              "remove",
              "cancelled",
              "postponed",
              "rescheduled"
            ],
            "description": "correct, remove, cancelled, postponed, or rescheduled (it has a new date)"
          },
          "message": {
            "type": "string"
          },
          "contactEmail": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "resolved",
              "dismissed"
            ]
          },
          "resolutionNote": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "resolvedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "newStartDate": {
            "type": [
              "string",
              "null"
            ],
            "description": "A rescheduled request's new date (YYYY-MM-DD), when it gave one"
          }
        },
        "required": [
          "id",
          "eventId",
          "eventTitle",
          "eventSlug",
          "kind",
          "message",
          "contactEmail",
          "status",
          "resolutionNote",
          "createdAt",
          "resolvedAt",
          "newStartDate"
        ]
      },
      "Kpi": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              },
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ]
          },
          "better": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "up",
              "down",
              null
            ]
          }
        },
        "required": [
          "key",
          "label",
          "value",
          "better"
        ]
      },
      "KpiGroup": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "directory",
                  "coverage",
                  "quality",
                  "listingQuality",
                  "reread",
                  "site",
                  "automation",
                  "yourTime",
                  "queue",
                  "ingest",
                  "gate",
                  "sources",
                  "organizers",
                  "visitors",
                  "email"
                ]
              },
              "label": {
                "type": "string"
              },
              "kpis": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Kpi"
                }
              }
            },
            "required": [
              "key",
              "label",
              "kpis"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "directory",
                  "coverage",
                  "quality",
                  "listingQuality",
                  "reread",
                  "site",
                  "automation",
                  "yourTime",
                  "queue",
                  "ingest",
                  "gate",
                  "sources",
                  "organizers",
                  "visitors",
                  "email"
                ]
              },
              "label": {
                "type": "string"
              },
              "error": {
                "type": "string"
              }
            },
            "required": [
              "key",
              "label",
              "error"
            ]
          }
        ]
      },
      "DailySnapshot": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "The report's Pacific date, YYYY-MM-DD"
          },
          "generatedAt": {
            "type": "string"
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KpiGroup"
            }
          }
        },
        "required": [
          "date",
          "generatedAt",
          "groups"
        ]
      },
      "DailyAction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "owner": {
            "type": "string",
            "enum": [
              "robert",
              "claude"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "done",
              "dropped"
            ]
          },
          "why": {
            "type": [
              "string",
              "null"
            ]
          },
          "firstRaised": {
            "type": "string",
            "description": "YYYY-MM-DD, Pacific"
          },
          "closedOn": {
            "type": [
              "string",
              "null"
            ],
            "description": "YYYY-MM-DD, Pacific; null while open"
          },
          "closeReason": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "action",
              "finding"
            ],
            "description": "\"action\" for Robert's own to-dos, \"finding\" for one Claude raised"
          },
          "area": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "data",
              "site",
              "coverage",
              "growth",
              "automation",
              "design",
              "accessibility",
              "seo",
              null
            ]
          },
          "impact": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "high",
              "medium",
              "low",
              null
            ]
          },
          "effort": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "small",
              "medium",
              "large",
              null
            ]
          },
          "who": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "claude-code",
              "claude-data",
              "robert",
              null
            ]
          },
          "evidence": {
            "type": [
              "string",
              "null"
            ]
          },
          "fix": {
            "type": [
              "string",
              "null"
            ]
          },
          "branch": {
            "type": [
              "string",
              "null"
            ]
          },
          "draftStatus": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "drafting",
              "ready",
              "abandoned",
              "merged",
              null
            ]
          },
          "draftSummary": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "title",
          "owner",
          "status",
          "why",
          "firstRaised",
          "closedOn",
          "closeReason",
          "kind",
          "area",
          "impact",
          "effort",
          "who",
          "evidence",
          "fix",
          "branch",
          "draftStatus",
          "draftSummary"
        ]
      },
      "DailyActionList": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/DailyAction"
        }
      },
      "DailyReport": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "YYYY-MM-DD, Pacific"
          },
          "createdAt": {
            "type": "string"
          },
          "snapshot": {
            "$ref": "#/components/schemas/DailySnapshot"
          },
          "flags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          },
          "insight": {
            "type": [
              "string",
              "null"
            ]
          },
          "wordsStatus": {
            "type": "string",
            "enum": [
              "ok",
              "unavailable"
            ]
          },
          "wordsError": {
            "type": [
              "string",
              "null"
            ]
          },
          "tokens": {
            "type": "integer"
          },
          "selfReview": {
            "type": [
              "string",
              "null"
            ],
            "description": "The monthly listing-quality self-review (markdown), on the first Pacific day of a month; null otherwise or before migration 040"
          }
        },
        "required": [
          "date",
          "createdAt",
          "snapshot",
          "flags",
          "summary",
          "insight",
          "wordsStatus",
          "wordsError",
          "tokens"
        ]
      },
      "DailyReportList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "description": "YYYY-MM-DD, Pacific"
                },
                "createdAt": {
                  "type": "string"
                },
                "flags": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "summary": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "insight": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "wordsStatus": {
                  "type": "string",
                  "enum": [
                    "ok",
                    "unavailable"
                  ]
                },
                "wordsError": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "tokens": {
                  "type": "integer"
                }
              },
              "required": [
                "date",
                "createdAt",
                "flags",
                "summary",
                "insight",
                "wordsStatus",
                "wordsError",
                "tokens"
              ]
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items",
          "nextCursor"
        ]
      },
      "DataFix": {
        "type": "object",
        "properties": {
          "auditId": {
            "type": "string"
          },
          "at": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "source_paused",
              "source_auto_activated",
              "source_auto_rejected",
              "event_hidden",
              "event_hidden_missing",
              "queue_closed",
              "queue_closed_second_opinion",
              "queue_closed_no_date",
              "judge",
              "quality_fix",
              "spot_check_released",
              "check_closed_moot",
              "spot_check_soft_ok",
              "queue_closed_host_abroad",
              "queue_closed_lost_trust"
            ]
          },
          "targetId": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "undone": {
            "type": "boolean"
          },
          "noUndo": {
            "type": "string",
            "description": "A plain note shown in place of Undo when this fix can never be undone here"
          }
        },
        "required": [
          "auditId",
          "at",
          "kind",
          "targetId",
          "label",
          "detail",
          "undone"
        ]
      },
      "DataFixList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFix"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "AdminDashboard": {
        "type": "object",
        "properties": {
          "tiles": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "value": {
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "sublabel": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "href": {
                  "type": "string"
                },
                "series": {
                  "type": [
                    "array",
                    "null"
                  ],
                  "items": {
                    "type": "number"
                  }
                }
              },
              "required": [
                "key",
                "label",
                "value",
                "sublabel",
                "href",
                "series"
              ]
            }
          }
        },
        "required": [
          "tiles"
        ]
      },
      "ApiError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "Feature": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "startsOn": {
            "type": "string"
          },
          "endsOn": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "admin",
              "paid",
              "early"
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdBy": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "endedEarlyAt": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "eventId",
          "startsOn",
          "endsOn",
          "source",
          "note",
          "createdBy",
          "createdAt",
          "endedEarlyAt"
        ]
      },
      "FeatureListItem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Feature"
          },
          {
            "type": "object",
            "properties": {
              "eventTitle": {
                "type": "string"
              },
              "eventSlug": {
                "type": "string"
              }
            },
            "required": [
              "eventTitle",
              "eventSlug"
            ]
          }
        ]
      },
      "FeatureListResult": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureListItem"
            }
          }
        },
        "required": [
          "items"
        ]
      },
      "Submitter": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Null once the account is deleted"
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "organizer",
              "admin"
            ]
          },
          "trust": {
            "type": "string",
            "enum": [
              "untrusted",
              "trusted",
              "blocked"
            ]
          },
          "active": {
            "type": "boolean",
            "description": "Not suspended or deleted"
          },
          "approved": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Clean approvals in the gate's 90-day window; null when the lookup failed"
          },
          "rejected": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rejections and strikes in the same window; null when the lookup failed"
          }
        },
        "required": [
          "id",
          "email",
          "role",
          "trust",
          "active",
          "approved",
          "rejected"
        ]
      },
      "Proposal": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "publish",
              "merge",
              "reject",
              "close_update",
              "keep",
              "hide",
              "looks_right",
              "fix_event"
            ]
          },
          "label": {
            "type": "string",
            "description": "The button's text"
          },
          "reason": {
            "type": "string",
            "description": "One plain sentence: what happened, or why it's waiting"
          },
          "edits": {
            "type": "object",
            "properties": {
              "city": {
                "type": "string"
              },
              "state": {
                "type": "string"
              },
              "location_kind": {
                "type": "string",
                "enum": [
                  "venue",
                  "online",
                  "multi"
                ]
              },
              "venue": {
                "type": "string"
              },
              "end_date": {
                "type": "string"
              },
              "start_time": {
                "type": "string"
              },
              "end_time": {
                "type": "string"
              }
            },
            "description": "For publish: the fixes the approve call sends"
          },
          "targetId": {
            "type": "string",
            "description": "For merge: the event to merge into"
          },
          "reasons": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "not_event",
                "not_crafting",
                "wrong_date",
                "wrong_place",
                "duplicate",
                "other"
              ]
            },
            "description": "For reject: the reasons the reject call sends"
          },
          "eventEdits": {
            "type": "object",
            "properties": {
              "start_date": {
                "type": "string"
              },
              "end_date": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "start_time": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "end_time": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "city": {
                "type": "string"
              }
            },
            "description": "For fix_event: the changes resolve-check's Keep sends to the event (a nightly quality card's fix)"
          }
        },
        "required": [
          "action",
          "label",
          "reason"
        ]
      },
      "Submission": {
        "type": "object",
        "properties": {
          "id": {
            "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"
            ]
          },
          "recurrence": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "venue": {
            "type": [
              "string",
              "null"
            ]
          },
          "lat": {
            "type": [
              "number",
              "null"
            ]
          },
          "lng": {
            "type": [
              "number",
              "null"
            ]
          },
          "location_kind": {
            "type": "string",
            "enum": [
              "venue",
              "online",
              "hybrid",
              "multi"
            ]
          },
          "street_address": {
            "type": [
              "string",
              "null"
            ]
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "signup_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hosted_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_platform": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "zoom",
              "meet",
              "teams",
              "webex",
              "facebook",
              "youtube",
              "other",
              null
            ]
          },
          "join_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_meeting_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_passcode": {
            "type": [
              "string",
              "null"
            ]
          },
          "join_phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "contact_phone": {
            "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"
            ]
          },
          "organizer_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "price_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_free": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "origin": {
            "type": "string",
            "enum": [
              "public",
              "scrape",
              "organizer"
            ]
          },
          "source_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "confidence": {
            "type": [
              "number",
              "null"
            ]
          },
          "source_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "organizer_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected"
            ]
          },
          "flags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "duplicate_of_event_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "update_of_event_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "suggested_series_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "review_notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "reviewed_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "published_event_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "admin_edited": {
            "type": "boolean"
          },
          "review_reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "gate_decision": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "publish",
              "queue",
              null
            ]
          },
          "gate_reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "gate_bucket": {
            "type": [
              "string",
              "null"
            ]
          },
          "auto_published": {
            "type": "boolean"
          },
          "spot_check_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "spot_check_result": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "ok",
              "rejected",
              "edited",
              null
            ]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "submitted_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "The signed-in account that added it, if any"
          },
          "submitter": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "email": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Null once the account is deleted"
              },
              "role": {
                "type": "string",
                "enum": [
                  "user",
                  "organizer",
                  "admin"
                ]
              },
              "trust": {
                "type": "string",
                "enum": [
                  "untrusted",
                  "trusted",
                  "blocked"
                ]
              },
              "active": {
                "type": "boolean",
                "description": "Not suspended or deleted"
              },
              "approved": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Clean approvals in the gate's 90-day window; null when the lookup failed"
              },
              "rejected": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Rejections and strikes in the same window; null when the lookup failed"
              }
            },
            "required": [
              "id",
              "email",
              "role",
              "trust",
              "active",
              "approved",
              "rejected"
            ],
            "description": "In queue lists: who added it and their record, or null for a scraped or anonymous submission"
          },
          "proposal": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "publish",
                  "merge",
                  "reject",
                  "close_update",
                  "keep",
                  "hide",
                  "looks_right",
                  "fix_event"
                ]
              },
              "label": {
                "type": "string",
                "description": "The button's text"
              },
              "reason": {
                "type": "string",
                "description": "One plain sentence: what happened, or why it's waiting"
              },
              "edits": {
                "type": "object",
                "properties": {
                  "city": {
                    "type": "string"
                  },
                  "state": {
                    "type": "string"
                  },
                  "location_kind": {
                    "type": "string",
                    "enum": [
                      "venue",
                      "online",
                      "multi"
                    ]
                  },
                  "venue": {
                    "type": "string"
                  },
                  "end_date": {
                    "type": "string"
                  },
                  "start_time": {
                    "type": "string"
                  },
                  "end_time": {
                    "type": "string"
                  }
                },
                "description": "For publish: the fixes the approve call sends"
              },
              "targetId": {
                "type": "string",
                "description": "For merge: the event to merge into"
              },
              "reasons": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "not_event",
                    "not_crafting",
                    "wrong_date",
                    "wrong_place",
                    "duplicate",
                    "other"
                  ]
                },
                "description": "For reject: the reasons the reject call sends"
              },
              "eventEdits": {
                "type": "object",
                "properties": {
                  "start_date": {
                    "type": "string"
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "start_time": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "end_time": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "city": {
                    "type": "string"
                  }
                },
                "description": "For fix_event: the changes resolve-check's Keep sends to the event (a nightly quality card's fix)"
              }
            },
            "required": [
              "action",
              "label",
              "reason"
            ],
            "description": "In queue and spot-check lists: the proposed answer (the judge's stored one, else derived), or null"
          },
          "noProposalReason": {
            "type": [
              "string",
              "null"
            ],
            "description": "In queue and spot-check lists, when proposal is null: why, as \"No suggestion: ...\""
          },
          "published_event_slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "In spot-check lists: the published event's slug, for its public page, or null"
          },
          "published_event_status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "published",
              "cancelled",
              "hidden",
              null
            ],
            "description": "In spot-check lists: the published event's status now (only a published one has a public page), or null"
          }
        },
        "required": [
          "id",
          "title",
          "description",
          "summary",
          "start_date",
          "end_date",
          "start_time",
          "end_time",
          "timezone",
          "recurrence",
          "city",
          "state",
          "venue",
          "lat",
          "lng",
          "location_kind",
          "street_address",
          "postal_code",
          "signup_note",
          "join_platform",
          "join_url",
          "join_meeting_id",
          "join_passcode",
          "join_phone",
          "contact_name",
          "contact_email",
          "contact_phone",
          "craft_types",
          "event_type",
          "tags",
          "url",
          "organizer_name",
          "price_note",
          "is_free",
          "origin",
          "source_id",
          "source_url",
          "confidence",
          "source_key",
          "organizer_email",
          "status",
          "flags",
          "duplicate_of_event_id",
          "update_of_event_id",
          "suggested_series_id",
          "review_notes",
          "reviewed_at",
          "published_event_id",
          "admin_edited",
          "review_reasons",
          "gate_decision",
          "gate_reasons",
          "gate_bucket",
          "auto_published",
          "spot_check_at",
          "spot_check_result",
          "created_at",
          "updated_at"
        ]
      },
      "GateBucket": {
        "type": "object",
        "properties": {
          "bucket": {
            "type": "string",
            "enum": [
              "0.75-0.85",
              "0.85-0.9",
              "0.9+"
            ]
          },
          "hits": {
            "type": "integer"
          },
          "misses": {
            "type": "integer"
          },
          "decided": {
            "type": "integer"
          },
          "precision": {
            "type": [
              "number",
              "null"
            ]
          },
          "lowerBound": {
            "type": "number"
          },
          "recentPrecision": {
            "type": [
              "number",
              "null"
            ]
          },
          "missReasons": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            }
          },
          "byType": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "eventType": {
                  "type": "string"
                },
                "hits": {
                  "type": "integer"
                },
                "misses": {
                  "type": "integer"
                }
              },
              "required": [
                "eventType",
                "hits",
                "misses"
              ]
            }
          }
        },
        "required": [
          "bucket",
          "hits",
          "misses",
          "decided",
          "precision",
          "lowerBound",
          "recentPrecision",
          "missReasons",
          "byType"
        ]
      },
      "GateSettings": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "target": {
            "type": "number"
          },
          "threshold": {
            "type": "number"
          },
          "thresholdReason": {
            "type": [
              "string",
              "null"
            ]
          },
          "thresholdChangedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "pausedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "pausedReason": {
            "type": [
              "string",
              "null"
            ]
          },
          "resumedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "updatedAt": {
            "type": "string"
          }
        },
        "required": [
          "enabled",
          "target",
          "threshold",
          "thresholdReason",
          "thresholdChangedAt",
          "pausedAt",
          "pausedReason",
          "resumedAt",
          "updatedAt"
        ]
      },
      "GateCandidateStat": {
        "type": "object",
        "properties": {
          "candidate": {
            "type": "number"
          },
          "hits": {
            "type": "integer"
          },
          "misses": {
            "type": "integer"
          },
          "decided": {
            "type": "integer"
          },
          "precision": {
            "type": [
              "number",
              "null"
            ]
          },
          "lowerBound": {
            "type": "number"
          }
        },
        "required": [
          "candidate",
          "hits",
          "misses",
          "decided",
          "precision",
          "lowerBound"
        ]
      },
      "GateSecondOpinionAccuracy": {
        "type": "object",
        "properties": {
          "confirmed": {
            "type": "object",
            "properties": {
              "decided": {
                "type": "integer"
              },
              "right": {
                "type": "integer"
              }
            },
            "required": [
              "decided",
              "right"
            ]
          },
          "closed": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "reopened": {
                "type": "integer"
              }
            },
            "required": [
              "total",
              "reopened"
            ]
          }
        },
        "required": [
          "confirmed",
          "closed"
        ]
      },
      "GateReport": {
        "type": "object",
        "properties": {
          "buckets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GateBucket"
            }
          },
          "pending": {
            "type": "object",
            "properties": {
              "wouldPublish": {
                "type": "integer"
              },
              "wouldQueue": {
                "type": "integer"
              },
              "topQueueReasons": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "reason": {
                      "type": "string"
                    },
                    "n": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "reason",
                    "n"
                  ]
                }
              }
            },
            "required": [
              "wouldPublish",
              "wouldQueue",
              "topQueueReasons"
            ]
          },
          "settings": {
            "$ref": "#/components/schemas/GateSettings"
          },
          "candidates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GateCandidateStat"
            }
          },
          "secondOpinion": {
            "$ref": "#/components/schemas/GateSecondOpinionAccuracy"
          },
          "judge": {
            "$ref": "#/components/schemas/GateSecondOpinionAccuracy"
          }
        },
        "required": [
          "buckets",
          "pending",
          "settings",
          "candidates",
          "secondOpinion",
          "judge"
        ]
      },
      "GateSettingsResponse": {
        "type": "object",
        "properties": {
          "settings": {
            "$ref": "#/components/schemas/GateSettings"
          },
          "candidates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GateCandidateStat"
            }
          }
        },
        "required": [
          "settings",
          "candidates"
        ]
      },
      "GrowthWeek": {
        "type": "object",
        "properties": {
          "weekStart": {
            "type": "string",
            "description": "The week's Monday (YYYY-MM-DD, Pacific)"
          },
          "invitesSent": {
            "type": "integer"
          },
          "claims": {
            "type": "integer"
          },
          "organizerEdits": {
            "type": "integer"
          },
          "organizerAdded": {
            "type": "integer"
          },
          "emailsBounced": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Null where the email log has no data (before it was set up, or over 90 days ago)"
          }
        },
        "required": [
          "weekStart",
          "invitesSent",
          "claims",
          "organizerEdits",
          "organizerAdded",
          "emailsBounced"
        ]
      },
      "WelcomeStepCounts": {
        "type": "object",
        "properties": {
          "step": {
            "anyOf": [
              {
                "type": "number",
                "enum": [
                  1
                ]
              },
              {
                "type": "number",
                "enum": [
                  2
                ]
              },
              {
                "type": "number",
                "enum": [
                  3
                ]
              },
              {
                "type": "number",
                "enum": [
                  4
                ]
              }
            ]
          },
          "sent": {
            "type": "integer"
          },
          "skipped": {
            "type": "integer"
          },
          "stopped": {
            "type": "integer",
            "description": "Never got this step because the account had already stopped the series (welcome_opt_out) by then"
          }
        },
        "required": [
          "step",
          "sent",
          "skipped",
          "stopped"
        ]
      },
      "WelcomeSummary": {
        "type": "object",
        "properties": {
          "started": {
            "type": "integer",
            "description": "Accounts whose first sign-in was in the last 30 days"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WelcomeStepCounts"
            },
            "description": "Steps 1 to 4, in order"
          },
          "savedOrAdded": {
            "type": "integer",
            "description": "Of those who started, how many saved or added an event within 14 days of their own first sign-in"
          },
          "savedPreferences": {
            "type": "integer",
            "description": "Of those who started, how many have saved their town or crafts: users.preferences is not null (Make it yours, or any other preferences save), whenever it happened"
          }
        },
        "required": [
          "started",
          "steps",
          "savedOrAdded",
          "savedPreferences"
        ]
      },
      "GrowthSummary": {
        "type": "object",
        "properties": {
          "funnel": {
            "type": "object",
            "properties": {
              "couldInvite": {
                "type": "integer"
              },
              "sent": {
                "type": "integer"
              },
              "reminded": {
                "type": "integer"
              },
              "claimed": {
                "type": "integer"
              },
              "claimedEvents": {
                "type": "integer"
              },
              "optedOut": {
                "type": "integer"
              },
              "bounced": {
                "type": "integer"
              },
              "claimRate": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "claimed / sent, null with none sent"
              },
              "spotsLeft": {
                "type": "integer"
              }
            },
            "required": [
              "couldInvite",
              "sent",
              "reminded",
              "claimed",
              "claimedEvents",
              "optedOut",
              "bounced",
              "claimRate",
              "spotsLeft"
            ]
          },
          "organizers": {
            "type": "object",
            "properties": {
              "count": {
                "type": "integer"
              },
              "eventsManaged": {
                "type": "integer"
              },
              "upcomingShare": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Share of upcoming published events with an owner, null with none upcoming"
              },
              "last30": {
                "type": "object",
                "properties": {
                  "edits": {
                    "type": "integer"
                  },
                  "added": {
                    "type": "integer"
                  },
                  "pictures": {
                    "type": "integer"
                  }
                },
                "required": [
                  "edits",
                  "added",
                  "pictures"
                ]
              }
            },
            "required": [
              "count",
              "eventsManaged",
              "upcomingShare",
              "last30"
            ]
          },
          "weeks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GrowthWeek"
            },
            "description": "8 Monday-start Pacific weeks, newest first"
          },
          "welcome": {
            "allOf": [
              {
                "$ref": "#/components/schemas/WelcomeSummary"
              },
              {
                "type": [
                  "object",
                  "null"
                ],
                "description": "The welcome series' own numbers, null before migration 035"
              }
            ]
          }
        },
        "required": [
          "funnel",
          "organizers",
          "weeks",
          "welcome"
        ]
      },
      "EmailLogItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "sentAt": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "sign_in",
              "reminder",
              "change",
              "event_live",
              "claim_decision",
              "organizer_invite",
              "invite_reminder",
              "welcome"
            ]
          },
          "toEmail": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "trigger": {
            "type": "string",
            "enum": [
              "admin",
              "system",
              "visitor"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "sent",
              "delivered",
              "bounced",
              "complained",
              "failed"
            ]
          },
          "eventId": {
            "type": [
              "string",
              "null"
            ]
          },
          "organizerSlug": {
            "type": [
              "string",
              "null"
            ],
            "description": "The recipient's public organizer page, when they have one"
          }
        },
        "required": [
          "id",
          "sentAt",
          "kind",
          "toEmail",
          "subject",
          "trigger",
          "status",
          "eventId",
          "organizerSlug"
        ]
      },
      "EmailLogPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailLogItem"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items",
          "nextCursor"
        ]
      },
      "EmailDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "sentAt": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "sign_in",
              "reminder",
              "change",
              "event_live",
              "claim_decision",
              "organizer_invite",
              "invite_reminder",
              "welcome"
            ]
          },
          "toEmail": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "trigger": {
            "type": "string",
            "enum": [
              "admin",
              "system",
              "visitor"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "sent",
              "delivered",
              "bounced",
              "complained",
              "failed"
            ]
          },
          "bodyText": {
            "type": [
              "string",
              "null"
            ],
            "description": "The email's plain-text part as sent, a sign-in email's code and link blanked; null for an email sent before text was kept"
          }
        },
        "required": [
          "id",
          "sentAt",
          "kind",
          "toEmail",
          "subject",
          "trigger",
          "status",
          "bodyText"
        ]
      },
      "HubAdminItem": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string"
          },
          "categoryName": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "stateName": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "rule": {
            "type": "string",
            "enum": [
              "headline",
              "events"
            ]
          },
          "events": {
            "type": [
              "integer",
              "null"
            ]
          },
          "headline": {
            "type": [
              "integer",
              "null"
            ]
          },
          "rulePasses": {
            "type": "boolean"
          },
          "indexable": {
            "type": "boolean"
          },
          "indexedSince": {
            "type": [
              "string",
              "null"
            ]
          },
          "belowSince": {
            "type": [
              "string",
              "null"
            ]
          },
          "intro": {
            "type": [
              "string",
              "null"
            ]
          },
          "introApproved": {
            "type": "boolean"
          },
          "introApprovedAt": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "category",
          "categoryName",
          "state",
          "stateName",
          "path",
          "rule",
          "events",
          "headline",
          "rulePasses",
          "indexable",
          "indexedSince",
          "belowSince",
          "intro",
          "introApproved",
          "introApprovedAt"
        ]
      },
      "HubAdminList": {
        "type": "object",
        "properties": {
          "configured": {
            "type": "boolean"
          },
          "countsAvailable": {
            "type": "boolean"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HubAdminItem"
            }
          }
        },
        "required": [
          "configured",
          "countsAvailable",
          "items"
        ]
      },
      "HubStatus": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "indexedSince": {
            "type": [
              "string",
              "null"
            ]
          },
          "belowSince": {
            "type": [
              "string",
              "null"
            ]
          },
          "intro": {
            "type": [
              "string",
              "null"
            ]
          },
          "introApprovedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "introApprovedBy": {
            "type": [
              "string",
              "null"
            ]
          },
          "updatedAt": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "category",
          "state",
          "indexedSince",
          "belowSince",
          "intro",
          "introApprovedAt",
          "introApprovedBy",
          "updatedAt"
        ]
      },
      "Source": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "craftTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "candidate",
              "active",
              "paused",
              "rejected"
            ]
          },
          "trust": {
            "type": "string",
            "enum": [
              "untrusted",
              "suggested",
              "trusted",
              "blocked"
            ]
          },
          "approvedCleanCount": {
            "type": "integer"
          },
          "lastFetchedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "lastContentHash": {
            "type": [
              "string",
              "null"
            ]
          },
          "lastError": {
            "type": [
              "string",
              "null"
            ]
          },
          "consecutiveFailures": {
            "type": "integer"
          },
          "eventsFoundCount": {
            "type": "integer"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "unchangedStreak": {
            "type": "integer"
          },
          "consecutiveEmptyRuns": {
            "type": "integer"
          },
          "nextFetchAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "trustedAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the source last became trusted; null unless trusted"
          },
          "distrustedReason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the source last lost trust automatically, e.g. \"1 event rejected: wrong date\""
          },
          "rejectReason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "not_event_source",
              "not_crafting",
              "wrong_craft",
              "out_of_area",
              "duplicate",
              "date_passed",
              "site_dead",
              "wrong_dates",
              "other",
              null
            ],
            "description": "Why an admin rejected the source; null unless rejected with a reason"
          },
          "rejectNote": {
            "type": [
              "string",
              "null"
            ],
            "description": "The admin's own words on the rejection, if any"
          },
          "probation": {
            "type": "string",
            "enum": [
              "restart"
            ],
            "description": "Keep on probation (WI-336): start a fresh probation, so its events publish with a spot check on each and rejects from before today no longer count. Not with trust"
          },
          "home": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "venue": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "street": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "city": {
                "type": "string"
              },
              "state": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "postal": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "venue",
              "street",
              "city",
              "state",
              "postal"
            ],
            "description": "The source's own place (WI-292): a class, club night, guild meeting or crop from it that names no town takes this town, and its venue, street and ZIP where the listing gives none"
          },
          "outreachEmail": {
            "type": [
              "string",
              "null"
            ],
            "description": "WI-512: the source's public contact email, used only to draft organizer invites and never shown on the site (migration 052); null when unknown"
          },
          "preview": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "found": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "upcoming": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "at": {
                "type": "string"
              }
            },
            "required": [
              "found",
              "upcoming",
              "at"
            ],
            "description": "WI-545: how many distinct event dates the source's page showed and how many are today or later (an estimate), and when it was counted; found and upcoming are null when the page couldn't be read that day; null until tried (migration 053)"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "url",
          "craftTypes",
          "state",
          "status",
          "trust",
          "approvedCleanCount",
          "lastFetchedAt",
          "lastContentHash",
          "lastError",
          "consecutiveFailures",
          "eventsFoundCount",
          "notes",
          "unchangedStreak",
          "consecutiveEmptyRuns",
          "nextFetchAt",
          "trustedAt",
          "distrustedReason",
          "rejectReason",
          "rejectNote",
          "home",
          "outreachEmail",
          "preview",
          "createdAt",
          "updatedAt"
        ]
      },
      "FirstReviewResult": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Submissions approved"
          },
          "failed": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "code": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "code",
                "message"
              ]
            },
            "description": "Submissions that couldn't be approved, and why: not_pending (already handled), needs_review (a blocking flag or likely duplicate, to check on its own), or the approval's own error"
          },
          "trusted": {
            "type": "boolean",
            "description": "Whether this call made the source trusted: at least one approval succeeded and it has no rejection in 90 days"
          }
        },
        "required": [
          "ok",
          "failed",
          "trusted"
        ]
      },
      "OrganizerContact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "organizerKey": {
            "type": "string",
            "description": "Who it belongs to before any organizer account exists: source:<id>, or source:<id>|org:<name> on a calendar of many organizers"
          },
          "party": {
            "type": "string",
            "enum": [
              "organizer",
              "publisher"
            ],
            "description": "organizer, or publisher: a many-organizer calendar's own contact, never used for invites"
          },
          "kind": {
            "type": "string",
            "description": "email, phone, website, facebook, instagram, youtube, pinterest, tiktok, x, threads, bluesky, etsy, ravelry or linkedin"
          },
          "value": {
            "type": "string"
          },
          "foundOn": {
            "type": [
              "string",
              "null"
            ]
          },
          "via": {
            "type": "string",
            "description": "listing_page, contact_page, event or source"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "gone",
              "removed"
            ]
          },
          "firstSeen": {
            "type": "string"
          },
          "lastSeen": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "organizerKey",
          "party",
          "kind",
          "value",
          "foundOn",
          "via",
          "status",
          "firstSeen",
          "lastSeen"
        ]
      },
      "SubmissionInput": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "start_date": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "end_date": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "string",
                "enum": [
                  ""
                ]
              }
            ]
          },
          "city": {
            "type": "string",
            "maxLength": 100,
            "description": "The town; required unless location_kind is online"
          },
          "state": {
            "type": "string",
            "maxLength": 40,
            "description": "A US state name or two-letter code; required unless location_kind is online (then taken from the time zone)"
          },
          "venue": {
            "type": "string",
            "maxLength": 200
          },
          "street_address": {
            "type": "string",
            "maxLength": 200
          },
          "postal_code": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{5}$"
              },
              {
                "type": "string",
                "enum": [
                  ""
                ]
              }
            ]
          },
          "location_kind": {
            "type": "string",
            "enum": [
              "venue",
              "online",
              "hybrid",
              "multi"
            ]
          },
          "timezone": {
            "type": "string",
            "maxLength": 64,
            "description": "The event's own clock (IANA, like America/Chicago); required for an online or hybrid event"
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 40
            },
            "maxItems": 5,
            "description": "The languages the event is held in, as BCP 47 codes (en, es); leave out when unknown"
          },
          "hosted_by": {
            "type": "string",
            "maxLength": 120,
            "description": "The group or shop hosting an online or hybrid event"
          },
          "craft_types": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 60
            },
            "maxItems": 20,
            "default": []
          },
          "event_type": {
            "type": "string",
            "maxLength": 40
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            },
            "maxItems": 20
          },
          "start_time": {
            "type": "string",
            "maxLength": 8
          },
          "end_time": {
            "type": "string",
            "maxLength": 8
          },
          "is_free": {
            "type": "boolean"
          },
          "price_note": {
            "type": "string",
            "maxLength": 200
          },
          "url": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "string",
                "enum": [
                  ""
                ]
              }
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 5000
          },
          "join_url": {
            "type": "string",
            "maxLength": 500
          },
          "join_meeting_id": {
            "type": "string",
            "maxLength": 40
          },
          "join_passcode": {
            "type": "string",
            "maxLength": 40
          },
          "join_phone": {
            "type": "string",
            "maxLength": 40
          },
          "contact_name": {
            "type": "string",
            "maxLength": 120
          },
          "contact_email": {
            "type": "string",
            "maxLength": 200
          },
          "organizer_email": {
            "type": "string"
          }
        },
        "required": [
          "title",
          "start_date"
        ]
      },
      "MyEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          },
          {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "published",
                  "cancelled",
                  "hidden"
                ]
              },
              "joinUrl": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "joinMeetingId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "joinPasscode": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "joinPhone": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "contactEmail": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "contactPhone": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "recurrence": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "nextStartDate": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The next occurrence's start date (today or later); null when it has none"
              },
              "nextEndDate": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The next occurrence's end date; null when it has none"
              }
            },
            "required": [
              "status",
              "joinUrl",
              "joinMeetingId",
              "joinPasscode",
              "joinPhone",
              "contactEmail",
              "contactPhone",
              "recurrence",
              "nextStartDate",
              "nextEndDate"
            ]
          }
        ]
      },
      "MyEvents": {
        "type": "object",
        "properties": {
          "upcoming": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MyEvent"
            }
          },
          "past": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MyEvent"
            }
          }
        },
        "required": [
          "upcoming",
          "past"
        ]
      },
      "OrganizerEdit": {
        "type": "object",
        "properties": {
          "auditId": {
            "type": "string",
            "description": "The event.organizer_update audit entry; pass it to undo-organizer-edit or organizer-edits/{auditId}/ok"
          },
          "eventId": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "organizerId": {
            "type": "string"
          },
          "organizerEmail": {
            "type": "string"
          },
          "at": {
            "type": "string"
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "before": {},
                "after": {}
              },
              "required": [
                "field"
              ]
            },
            "description": "Each organizer-editable field the edit changed, before and after"
          }
        },
        "required": [
          "auditId",
          "eventId",
          "slug",
          "title",
          "organizerId",
          "organizerEmail",
          "at",
          "changes"
        ]
      },
      "MyEventCancelled": {
        "type": "object",
        "properties": {
          "event": {
            "$ref": "#/components/schemas/MyEvent"
          }
        },
        "required": [
          "event"
        ]
      },
      "OrganizerEventInput": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "start_date": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "end_date": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "string",
                "enum": [
                  ""
                ]
              }
            ]
          },
          "city": {
            "type": "string",
            "maxLength": 100,
            "description": "The town; required unless location_kind is online"
          },
          "state": {
            "type": "string",
            "maxLength": 40,
            "description": "A US state name or two-letter code; required unless location_kind is online (then taken from the time zone)"
          },
          "venue": {
            "type": "string",
            "maxLength": 200
          },
          "street_address": {
            "type": "string",
            "maxLength": 200
          },
          "postal_code": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{5}$"
              },
              {
                "type": "string",
                "enum": [
                  ""
                ]
              }
            ]
          },
          "location_kind": {
            "type": "string",
            "enum": [
              "venue",
              "online",
              "hybrid",
              "multi"
            ]
          },
          "timezone": {
            "type": "string",
            "maxLength": 64,
            "description": "The event's own clock (IANA, like America/Chicago); required for an online or hybrid event"
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 40
            },
            "maxItems": 5,
            "description": "The languages the event is held in, as BCP 47 codes (en, es); leave out when unknown"
          },
          "hosted_by": {
            "type": "string",
            "maxLength": 120,
            "description": "The group or shop hosting an online or hybrid event"
          },
          "craft_types": {
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 60
            },
            "maxItems": 20,
            "default": []
          },
          "event_type": {
            "type": "string",
            "maxLength": 40
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            },
            "maxItems": 20
          },
          "start_time": {
            "type": "string",
            "maxLength": 8
          },
          "end_time": {
            "type": "string",
            "maxLength": 8
          },
          "is_free": {
            "type": "boolean"
          },
          "price_note": {
            "type": "string",
            "maxLength": 200
          },
          "url": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "string",
                "enum": [
                  ""
                ]
              }
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 5000
          },
          "join_url": {
            "type": "string",
            "maxLength": 500
          },
          "join_meeting_id": {
            "type": "string",
            "maxLength": 40
          },
          "join_passcode": {
            "type": "string",
            "maxLength": 40
          },
          "join_phone": {
            "type": "string",
            "maxLength": 40
          },
          "contact_name": {
            "type": "string",
            "maxLength": 120
          },
          "contact_email": {
            "type": "string",
            "maxLength": 200
          },
          "organizer_email": {
            "type": "string"
          },
          "summary": {
            "type": "string",
            "maxLength": 300
          },
          "signup_note": {
            "type": "string",
            "maxLength": 200
          },
          "recurrence": {
            "type": "string",
            "maxLength": 500
          }
        },
        "required": [
          "title",
          "start_date"
        ],
        "additionalProperties": false
      },
      "OrganizerEventCreated": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "published",
              "queued",
              "duplicate_pending"
            ]
          },
          "submissionId": {
            "type": [
              "string",
              "null"
            ]
          },
          "eventId": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "flags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "duplicate",
                    "date",
                    "check_failed"
                  ]
                },
                "message": {
                  "type": "string",
                  "description": "The warning in plain words, for the organizer"
                },
                "event": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "properties": {
                    "slug": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "slug",
                    "title"
                  ],
                  "description": "The listing it might duplicate, to link to"
                }
              },
              "required": [
                "kind",
                "message",
                "event"
              ]
            },
            "description": "What an instant publish warned about: a listing that might be the same event, or a date that looks wrong"
          }
        },
        "required": [
          "status",
          "submissionId",
          "eventId",
          "slug",
          "flags"
        ]
      },
      "MyProfile": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "The public address's last part, /organizers/{slug}; set from the display name"
          },
          "slugLocked": {
            "type": "boolean",
            "description": "True while the slug changed under 30 days ago; a name change then keeps the old slug"
          },
          "slugUnlocksAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the slug can change again, or null when it already can"
          },
          "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>'"
          },
          "isPublic": {
            "type": "boolean",
            "description": "True for an organizer with a display name: the profile has a public page"
          },
          "publicUrl": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "displayName",
          "slug",
          "slugLocked",
          "slugUnlocksAt",
          "about",
          "website",
          "city",
          "state",
          "crafts",
          "avatarUrl",
          "avatarSmallUrl",
          "defaultAvatar",
          "isPublic",
          "publicUrl"
        ]
      },
      "ProfilePatch": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 60
          },
          "about": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500
          },
          "website": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 300,
            "description": "A full address starting with http:// or https://"
          },
          "city": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 80
          },
          "state": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2,
            "description": "A two-letter US state code"
          },
          "crafts": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            },
            "maxItems": 30,
            "description": "Active top-level craft slugs; an unknown slug is a 400"
          }
        },
        "additionalProperties": false
      },
      "AvatarUpload": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "The picture (JPEG, PNG, WebP or HEIC, at most 4 MB): a file part in multipart/form-data, or base64 when sent as JSON (MCP)"
          },
          "crop": {
            "type": "string",
            "description": "Optional JSON {\"x\",\"y\",\"size\"} in the picture's upright pixels: whole numbers, x and y 0 or more, size above 0. Without it the center square is kept"
          }
        },
        "required": [
          "file"
        ]
      },
      "HeaderProfile": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarSmallUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "defaultAvatar": {
            "type": "string"
          }
        },
        "required": [
          "displayName",
          "avatarUrl",
          "avatarSmallUrl",
          "defaultAvatar"
        ]
      },
      "OrganizerEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/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"
            ]
          }
        ]
      },
      "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": "#/components/schemas/OrganizerEvent"
            },
            "description": "Published events still to come on this site, soonest first, at most 50"
          },
          "past": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrganizerEvent"
            },
            "description": "The newest 12 published events that are over"
          }
        },
        "required": [
          "slug",
          "displayName",
          "about",
          "website",
          "city",
          "state",
          "crafts",
          "avatarUrl",
          "avatarSmallUrl",
          "defaultAvatar",
          "upcoming",
          "past"
        ]
      },
      "ProfileToCheck": {
        "type": "object",
        "properties": {
          "userId": {
            "type": "string"
          },
          "displayName": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "The public page is /organizers/{slug}, when set"
          },
          "about": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ],
            "description": "The 512px picture, or null when the default badge shows"
          },
          "avatarSmallUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "defaultAvatar": {
            "type": "string",
            "description": "The built-in badge, '<craft icon>-<color 1-6>'"
          },
          "changedAt": {
            "type": "string",
            "description": "The last public change (About or picture), or the profile's last save for one never checked"
          }
        },
        "required": [
          "userId",
          "displayName",
          "slug",
          "about",
          "avatarUrl",
          "avatarSmallUrl",
          "defaultAvatar",
          "changedAt"
        ]
      },
      "ProfilesToCheckPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProfileToCheck"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "total": {
            "type": "integer",
            "description": "How many organizer profiles are waiting for a check"
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ]
      },
      "CheckProfileBody": {
        "type": "object",
        "properties": {
          "changedAt": {
            "type": "string",
            "maxLength": 64,
            "description": "The item's changedAt as you loaded it; when given, a profile changed since is a 409 and is left as it is"
          }
        },
        "additionalProperties": false
      },
      "RemoveProfileContentBody": {
        "type": "object",
        "properties": {
          "what": {
            "type": "string",
            "enum": [
              "picture",
              "about"
            ],
            "description": "Remove the photo (and its files) or clear the About text"
          },
          "changedAt": {
            "type": "string",
            "maxLength": 64,
            "description": "The item's changedAt as you loaded it; when given, a profile changed since is a 409 and is left as it is"
          }
        },
        "required": [
          "what"
        ],
        "additionalProperties": false
      },
      "InviteEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "dateLabel": {
            "type": "string"
          },
          "place": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "slug",
          "title",
          "dateLabel",
          "place",
          "url"
        ]
      },
      "AdminInvite": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "sent",
              "skipped",
              "claimed",
              "stopped",
              "expired"
            ]
          },
          "stage": {
            "type": "string",
            "enum": [
              "invite",
              "reminder"
            ]
          },
          "intro": {
            "type": [
              "string",
              "null"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InviteEvent"
            }
          },
          "sentAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "found": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "sourceId": {
                "type": "string"
              },
              "sourceName": {
                "type": "string"
              },
              "alsoFound": {
                "type": "integer"
              }
            },
            "required": [
              "sourceId",
              "sourceName",
              "alsoFound"
            ],
            "description": "WI-591: the address was collected from this source's pages or events; alsoFound counts the organizer's other addresses"
          }
        },
        "required": [
          "id",
          "email",
          "status",
          "stage",
          "intro",
          "events",
          "sentAt",
          "createdAt"
        ]
      },
      "InviteList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdminInvite"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "total": {
            "type": "integer"
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ]
      },
      "InvitePreview": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "subject",
          "html",
          "text"
        ]
      },
      "OutreachSettings": {
        "type": "object",
        "properties": {
          "postalAddress": {
            "type": [
              "string",
              "null"
            ]
          },
          "pausedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "pausedReason": {
            "type": [
              "string",
              "null"
            ]
          },
          "resumedAt": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "postalAddress",
          "pausedAt",
          "pausedReason",
          "resumedAt"
        ]
      },
      "OutreachSummary": {
        "type": "object",
        "properties": {
          "drafts": {
            "type": "integer"
          },
          "sent": {
            "type": "integer"
          },
          "reminded": {
            "type": "integer"
          },
          "claimed": {
            "type": "integer"
          },
          "claimedEvents": {
            "type": "integer"
          },
          "optedOut": {
            "type": "integer"
          },
          "bounced": {
            "type": "integer"
          },
          "spotsLeft": {
            "type": "integer"
          },
          "eventsInvited": {
            "type": "integer",
            "description": "Events listed across every sent invite (one invite can list several of an organizer's events)"
          },
          "line": {
            "type": "string"
          }
        },
        "required": [
          "drafts",
          "sent",
          "reminded",
          "claimed",
          "claimedEvents",
          "optedOut",
          "bounced",
          "spotsLeft",
          "eventsInvited",
          "line"
        ]
      },
      "Suppression": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "enum": [
              "opted_out",
              "not_mine",
              "bounced",
              "complained",
              "admin_never"
            ]
          },
          "inviteId": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "reason",
          "inviteId",
          "createdAt"
        ]
      },
      "InvitePage": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "used",
              "expired",
              "unknown"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InviteEvent"
            }
          }
        },
        "required": [
          "status",
          "events"
        ]
      },
      "InviteClaimResult": {
        "type": "object",
        "properties": {
          "granted": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InviteEvent"
            }
          },
          "pending": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InviteEvent"
            }
          },
          "skipped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InviteEvent"
            }
          },
          "perk": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "eventId": {
                "type": "string"
              },
              "endsOn": {
                "type": "string"
              }
            },
            "required": [
              "eventId",
              "endsOn"
            ]
          }
        },
        "required": [
          "granted",
          "pending",
          "skipped",
          "perk"
        ]
      },
      "InboxGroup": {
        "anyOf": [
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "paused"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "urgent"
                ]
              },
              "total": {
                "type": "integer"
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "pausedAt": {
                      "type": "string"
                    },
                    "pausedReason": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "pausedAt",
                    "pausedReason"
                  ]
                }
              },
              "nextCursor": {
                "type": "null"
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "ingest"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "urgent"
                ]
              },
              "total": {
                "type": "integer"
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "lastRunAt": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "status": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "statusWords": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "How the last run ended, in plain words: finished, stopped partway (only for a budget, time or Claude stop), failed or is still running"
                    },
                    "runId": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The last run's id, for its summary (GET /api/admin/ingest/runs/{id}, /admin/ingest/{id})"
                    },
                    "lines": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Plain reasons from the last run, one sentence each (why it stopped, sources that couldn't be read, auto-pauses, or that no recent run happened)"
                    },
                    "missedMorning": {
                      "type": "boolean",
                      "description": "True after 8:00 am Pacific when no run has started since today's 6:00 am Pacific (the scheduled task's time)"
                    }
                  },
                  "required": [
                    "lastRunAt",
                    "status",
                    "statusWords",
                    "runId",
                    "lines",
                    "missedMorning"
                  ]
                }
              },
              "nextCursor": {
                "type": "null"
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "added",
                  "spotChecks",
                  "review",
                  "sourceChecks"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Submission"
                },
                "description": "added: pending events a signed-in person added or suggested, oldest first, each with its submitter; review leaves them out"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "wouldPublishIds": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "claims"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AdminClaim"
                },
                "description": "Pending claims, oldest first; decide with POST /api/admin/claims/{id}/approve or /reject"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "invites"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer",
                "description": "Draft invites plus sent invites with a reminder draft waiting"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AdminInvite"
                },
                "description": "Oldest first; act with POST /api/admin/outreach/invites/{id}/send, /skip or /never"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "reachByHand"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer",
                "description": "WI-591: organizers with an upcoming unowned event and no invite address, reachable only by social media or phone"
              },
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "sourceId": {
                      "type": "string"
                    },
                    "sourceName": {
                      "type": "string"
                    },
                    "upcoming": {
                      "type": "integer"
                    },
                    "next": {
                      "type": "object",
                      "properties": {
                        "slug": {
                          "type": "string"
                        },
                        "title": {
                          "type": "string"
                        },
                        "dateLabel": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "slug",
                        "title",
                        "dateLabel",
                        "url"
                      ]
                    },
                    "socials": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "kind": {
                            "type": "string"
                          },
                          "value": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "kind",
                          "value"
                        ]
                      }
                    },
                    "phones": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "website": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "key",
                    "name",
                    "sourceId",
                    "sourceName",
                    "upcoming",
                    "next",
                    "socials",
                    "phones",
                    "website"
                  ]
                },
                "description": "Soonest event first; act with POST /api/admin/outreach/hand (reached, skip, never) or /api/admin/outreach/hand/message. Nothing is sent automatically"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "organizerEdits"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer",
                "description": "Organizer edits from the last 14 days not yet marked fine or undone"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/OrganizerEdit"
                }
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "profiles"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer",
                "description": "Organizer profiles changed in public since their last check, or never checked"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ProfileToCheck"
                },
                "description": "Oldest change first; act with POST /api/admin/profiles/{userId}/check or /remove"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "pictures"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer",
                "description": "Organizers' live event pictures no admin has checked yet"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ImageToCheck"
                },
                "description": "Newest first; act with POST /api/admin/images/{id}/check or /remove"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "corrections"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Correction"
                }
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "candidates"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Source"
                }
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "counts": {
                "type": "object",
                "properties": {
                  "all": {
                    "type": "integer"
                  },
                  "has": {
                    "type": "integer"
                  },
                  "none": {
                    "type": "integer"
                  },
                  "unread": {
                    "type": "integer"
                  }
                },
                "required": [
                  "all",
                  "has",
                  "none",
                  "unread"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "trust"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer",
                "description": "Ready to trust: active suggested sources that never lost trust"
              },
              "items": {
                "type": "array",
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Source"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "record": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "properties": {
                            "clean": {
                              "type": "integer"
                            },
                            "rejected": {
                              "type": "integer"
                            }
                          },
                          "required": [
                            "clean",
                            "rejected"
                          ],
                          "description": "Clean approvals and rejections in the last 90 days, live from the gate's own record; null when that lookup failed"
                        }
                      },
                      "required": [
                        "record"
                      ]
                    }
                  ]
                },
                "description": "Newest first; act with PATCH /api/admin/sources/{id} { trust: \"trusted\" } (Trust) or { trust: \"untrusted\" } (Not yet)"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          },
          {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "trustLost"
                ]
              },
              "title": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "normal"
                ]
              },
              "total": {
                "type": "integer",
                "description": "Lost trust, needs review: active sources that lost trust automatically (demoted, auto-blocked or out of probation), each with a distrustedReason"
              },
              "items": {
                "type": "array",
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Source"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "record": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "properties": {
                            "clean": {
                              "type": "integer"
                            },
                            "rejected": {
                              "type": "integer"
                            }
                          },
                          "required": [
                            "clean",
                            "rejected"
                          ],
                          "description": "Clean approvals and rejections in the last 90 days, live from the gate's own record; null when that lookup failed"
                        },
                        "rejections": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "properties": {
                            "admin": {
                              "type": "integer",
                              "description": "Rejected by an admin"
                            },
                            "judge": {
                              "type": "integer",
                              "description": "Rejected by the judge"
                            },
                            "spotCheck": {
                              "type": "integer",
                              "description": "Auto-published, then rejected by a spot check"
                            },
                            "firstAt": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "lastAt": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "items": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "string"
                                  },
                                  "title": {
                                    "type": "string"
                                  },
                                  "startDate": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "by": {
                                    "type": "string",
                                    "enum": [
                                      "admin",
                                      "judge",
                                      "spot_check"
                                    ]
                                  },
                                  "at": {
                                    "type": "string"
                                  },
                                  "reasons": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  },
                                  "url": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "endDate": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "startTime": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "city": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "why": {
                                    "type": [
                                      "string",
                                      "null"
                                    ],
                                    "description": "What the rejecter said: the judge's reason, or an admin's note"
                                  },
                                  "quote": {
                                    "type": [
                                      "string",
                                      "null"
                                    ],
                                    "description": "The page's own words the judge quoted"
                                  },
                                  "agreed": {
                                    "type": "boolean",
                                    "description": "An admin already agreed with this reject"
                                  }
                                },
                                "required": [
                                  "id",
                                  "title",
                                  "startDate",
                                  "by",
                                  "at",
                                  "reasons",
                                  "url"
                                ]
                              },
                              "description": "The newest rejections, at most 50; agree or overturn each with POST /api/admin/submissions/{id}/reject-verdict"
                            },
                            "passedCloses": {
                              "type": "object",
                              "properties": {
                                "count": {
                                  "type": "integer"
                                },
                                "titles": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                }
                              },
                              "required": [
                                "count",
                                "titles"
                              ],
                              "description": "Rejects closed because the date passed before review; these never count"
                            }
                          },
                          "required": [
                            "admin",
                            "judge",
                            "spotCheck",
                            "firstAt",
                            "lastAt",
                            "items"
                          ],
                          "description": "Who rejected this source's events in the last 90 days and when; null when that lookup failed"
                        },
                        "rejectsHref": {
                          "type": "string",
                          "description": "The admin page listing those rejected events"
                        },
                        "read": {
                          "type": "object",
                          "properties": {
                            "line": {
                              "type": [
                                "string",
                                "null"
                              ],
                              "description": "What we think happened, in plain words"
                            },
                            "suggest": {
                              "type": [
                                "string",
                                "null"
                              ],
                              "enum": [
                                "trust",
                                "probation",
                                "block",
                                null
                              ],
                              "description": "The suggested decision, never chosen for you"
                            },
                            "lateReadIds": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              },
                              "description": "Judge 'wrong date' rejects made after the event was over (suggested for overturn)"
                            }
                          },
                          "required": [
                            "line",
                            "suggest",
                            "lateReadIds"
                          ]
                        },
                        "waiting": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "properties": {
                            "count": {
                              "type": "integer"
                            },
                            "next": {
                              "type": [
                                "object",
                                "null"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "title": {
                                  "type": "string"
                                },
                                "startDate": {
                                  "type": [
                                    "string",
                                    "null"
                                  ]
                                }
                              },
                              "required": [
                                "id",
                                "title",
                                "startDate"
                              ]
                            }
                          },
                          "required": [
                            "count",
                            "next"
                          ],
                          "description": "Its new events waiting in the queue; null when that lookup failed"
                        }
                      },
                      "required": [
                        "record",
                        "rejections",
                        "rejectsHref",
                        "read",
                        "waiting"
                      ]
                    }
                  ]
                },
                "description": "Newest first. Decide with PATCH /api/admin/sources/{id}: Trust again { trust: \"trusted\" }, Keep on probation { probation: \"restart\" }, or Block { status: \"rejected\", trust: \"blocked\", rejectReason, rejectNote } (closes its waiting events)"
              },
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "key",
              "title",
              "severity",
              "total",
              "items",
              "nextCursor"
            ]
          }
        ]
      },
      "Inbox": {
        "type": "object",
        "properties": {
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InboxGroup"
            }
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "enum": [
                    "paused",
                    "ingest",
                    "added",
                    "spotChecks",
                    "review",
                    "claims",
                    "invites",
                    "reachByHand",
                    "organizerEdits",
                    "profiles",
                    "pictures",
                    "sourceChecks",
                    "trustLost",
                    "corrections",
                    "candidates",
                    "trust"
                  ]
                },
                "message": {
                  "type": "string"
                }
              },
              "required": [
                "key",
                "message"
              ]
            }
          }
        },
        "required": [
          "groups",
          "errors"
        ]
      },
      "InboxGroupPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {}
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "total": {
            "type": "integer"
          },
          "counts": {
            "type": "object",
            "properties": {
              "all": {
                "type": "integer"
              },
              "has": {
                "type": "integer"
              },
              "none": {
                "type": "integer"
              },
              "unread": {
                "type": "integer"
              }
            },
            "required": [
              "all",
              "has",
              "none",
              "unread"
            ],
            "description": "candidates only (WI-802): how many new sources each `preview` filter holds"
          },
          "view": {
            "type": "object",
            "properties": {
              "preview": {
                "type": "string",
                "enum": [
                  "all",
                  "has",
                  "none",
                  "unread"
                ]
              },
              "sort": {
                "type": "string",
                "enum": [
                  "newest",
                  "upcoming"
                ]
              }
            },
            "required": [
              "preview",
              "sort"
            ],
            "description": "candidates only (WI-802): the filter and sort this page used"
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ]
      },
      "IngestRun": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "startedAt": {
            "type": "string"
          },
          "finishedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "trigger": {
            "type": "string",
            "enum": [
              "cli",
              "api",
              "cron"
            ]
          },
          "sourcesAttempted": {
            "type": "integer"
          },
          "pagesChanged": {
            "type": "integer"
          },
          "eventsExtracted": {
            "type": "integer"
          },
          "eventsQueued": {
            "type": "integer"
          },
          "eventsAutoPublished": {
            "type": "integer"
          },
          "inputTokens": {
            "type": "integer"
          },
          "outputTokens": {
            "type": "integer"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sourceId": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "message": {
                  "type": "string"
                },
                "level": {
                  "type": "string",
                  "enum": [
                    "error",
                    "warning"
                  ]
                }
              },
              "required": [
                "sourceId",
                "message",
                "level"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "ok",
              "partial",
              "failed"
            ]
          }
        },
        "required": [
          "id",
          "startedAt",
          "finishedAt",
          "trigger",
          "sourcesAttempted",
          "pagesChanged",
          "eventsExtracted",
          "eventsQueued",
          "eventsAutoPublished",
          "inputTokens",
          "outputTokens",
          "errors",
          "status"
        ]
      },
      "IngestRunDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/IngestRun"
          },
          {
            "type": "object",
            "properties": {
              "sources": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "candidate",
                        "active",
                        "paused",
                        "rejected"
                      ]
                    },
                    "consecutiveFailures": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "status",
                    "consecutiveFailures"
                  ]
                },
                "description": "Every source the run's errors and warnings name, as it stands now (a deleted source is absent)"
              },
              "updatesMerged": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Updates auto-merged onto published events; null while the run is still running"
              },
              "duplicatesSettled": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Duplicates auto-settled onto published events; null while the run is still running"
              },
              "details": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "fetched": {
                    "type": "integer"
                  },
                  "filled": {
                    "type": "integer"
                  },
                  "skipped": {
                    "type": "object",
                    "properties": {
                      "budget": {
                        "type": "integer"
                      },
                      "robots": {
                        "type": "integer"
                      },
                      "errors": {
                        "type": "integer"
                      }
                    },
                    "required": [
                      "budget",
                      "robots",
                      "errors"
                    ]
                  }
                },
                "required": [
                  "fetched",
                  "filled",
                  "skipped"
                ],
                "description": "Detail pages read, events filled and events skipped; null when none qualified or the run is still running"
              },
              "missingHidden": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Events auto-hidden as no longer listed on their source; null while the run is still running"
              },
              "missingReturned": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Events brought back once their source listed them again; null while the run is still running"
              },
              "secondOpinion": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "checked": {
                    "type": "integer"
                  },
                  "confirmed": {
                    "type": "integer"
                  },
                  "closed": {
                    "type": "integer"
                  },
                  "forYou": {
                    "type": "integer"
                  }
                },
                "required": [
                  "checked",
                  "confirmed",
                  "closed",
                  "forYou"
                ],
                "description": "Unsure events read again by the second opinion: checked, confirmed, closed on their own and left for review; null when none was checked or the run is still running"
              },
              "judge": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "published": {
                    "type": "integer"
                  },
                  "merged": {
                    "type": "integer"
                  },
                  "rejected": {
                    "type": "integer"
                  },
                  "closed": {
                    "type": "integer"
                  },
                  "left": {
                    "type": "integer"
                  }
                },
                "required": [
                  "published",
                  "merged",
                  "rejected",
                  "closed",
                  "left"
                ],
                "description": "Waiting items the judge decided at the end of the run: published, merged, rejected, closed and left for review; null when it decided nothing or the run is still running"
              },
              "reread": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "checked": {
                    "type": "integer"
                  },
                  "confirmed": {
                    "type": "integer"
                  },
                  "fixed": {
                    "type": "integer"
                  },
                  "cancelled": {
                    "type": "integer"
                  },
                  "forYou": {
                    "type": "integer"
                  }
                },
                "required": [
                  "checked",
                  "confirmed",
                  "fixed",
                  "cancelled",
                  "forYou"
                ],
                "description": "Live listings the daily re-read checked against their own page: confirmed, dates fixed, cancelled and sent to you as cards; null when it checked none or the run is still running"
              },
              "years": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "confirmed": {
                    "type": "integer"
                  },
                  "held": {
                    "type": "integer"
                  }
                },
                "required": [
                  "confirmed",
                  "held"
                ],
                "description": "Extracted events whose year their own page confirmed, and events held for a check because the page didn't show it; null when the run extracted none or is still running"
              },
              "intake": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "unchanged": {
                    "type": "integer"
                  },
                  "waiting": {
                    "type": "integer"
                  },
                  "past": {
                    "type": "integer"
                  },
                  "failed": {
                    "type": "integer"
                  }
                },
                "required": [
                  "unchanged",
                  "waiting",
                  "past",
                  "failed"
                ],
                "description": "Extracted events that weren't sent on: already listed with nothing new, matching an item already waiting for review, already over, or refused; null when there were none or the run is still running"
              },
              "pages": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "vps": {
                    "type": "integer"
                  },
                  "cloud": {
                    "type": "integer"
                  },
                  "healthFailed": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "vps",
                  "cloud",
                  "healthFailed"
                ],
                "description": "Pages fetched from our own page server (the VPS) and from Firecrawl cloud, and whether the run's VPS health check failed; null when the VPS isn't configured, the run fetched no pages or it is still running"
              },
              "previousRunId": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The run that started just before this one"
              },
              "nextRunId": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The run that started just after this one"
              }
            },
            "required": [
              "sources",
              "updatesMerged",
              "duplicatesSettled",
              "details",
              "missingHidden",
              "missingReturned",
              "secondOpinion",
              "judge",
              "reread",
              "years",
              "intake",
              "pages",
              "previousRunId",
              "nextRunId"
            ]
          }
        ]
      },
      "Place": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "lat": {
            "type": "number"
          },
          "lng": {
            "type": "number"
          }
        },
        "required": [
          "label",
          "state",
          "lat",
          "lng"
        ]
      },
      "Preferences": {
        "type": "object",
        "properties": {
          "crafts": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[a-z0-9-]{2,40}$"
            },
            "maxItems": 20
          },
          "formats": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "in_person",
                "online"
              ]
            },
            "minItems": 1,
            "maxItems": 2
          },
          "freeOnly": {
            "type": "boolean"
          },
          "when": {
            "type": "string",
            "enum": [
              "weekend",
              "next30",
              "next90"
            ]
          },
          "place": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "label": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "pattern": "^[^\\x00-\\x1F\\x7F]*$"
              }
            },
            "required": [
              "label"
            ]
          },
          "radius": {
            "anyOf": [
              {
                "type": "number",
                "enum": [
                  25
                ]
              },
              {
                "type": "number",
                "enum": [
                  50
                ]
              },
              {
                "type": "number",
                "enum": [
                  100
                ]
              },
              {
                "type": "number",
                "enum": [
                  250
                ]
              }
            ]
          },
          "sort": {
            "type": "string",
            "enum": [
              "date",
              "distance"
            ],
            "description": "The results' order: date (soonest first, the default when missing) or distance (nearest first, used only with a place)."
          },
          "showOnline": {
            "type": "boolean",
            "description": "The 'Show online events' switch: the Online events band under local results (true, the default when missing) or one quiet line instead (false)."
          }
        },
        "required": [
          "crafts",
          "formats",
          "freeOnly",
          "when",
          "place",
          "radius"
        ]
      },
      "PreferencesPatch": {
        "type": "object",
        "properties": {
          "crafts": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[a-z0-9-]{2,40}$"
            },
            "maxItems": 20
          },
          "formats": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "in_person",
                "online"
              ]
            },
            "minItems": 1,
            "maxItems": 2
          },
          "freeOnly": {
            "type": "boolean"
          },
          "when": {
            "type": "string",
            "enum": [
              "weekend",
              "next30",
              "next90"
            ]
          },
          "place": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "label": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100,
                "pattern": "^[^\\x00-\\x1F\\x7F]*$"
              }
            },
            "required": [
              "label"
            ]
          },
          "radius": {
            "anyOf": [
              {
                "type": "number",
                "enum": [
                  25
                ]
              },
              {
                "type": "number",
                "enum": [
                  50
                ]
              },
              {
                "type": "number",
                "enum": [
                  100
                ]
              },
              {
                "type": "number",
                "enum": [
                  250
                ]
              }
            ]
          },
          "sort": {
            "type": "string",
            "enum": [
              "date",
              "distance"
            ],
            "description": "The results' order: date (soonest first, the default when missing) or distance (nearest first, used only with a place)."
          },
          "showOnline": {
            "type": "boolean",
            "description": "The 'Show online events' switch: the Online events band under local results (true, the default when missing) or one quiet line instead (false)."
          }
        }
      },
      "PreferencesState": {
        "type": "object",
        "properties": {
          "preferences": {
            "$ref": "#/components/schemas/Preferences"
          },
          "source": {
            "type": "string",
            "enum": [
              "account",
              "cookie",
              "default"
            ]
          }
        },
        "required": [
          "preferences",
          "source"
        ]
      },
      "PreferencesResult": {
        "type": "object",
        "properties": {
          "preferences": {
            "$ref": "#/components/schemas/Preferences"
          }
        },
        "required": [
          "preferences"
        ]
      },
      "QualityIssue": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventTitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "eventSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "code": {
            "type": "string",
            "description": "The rule's code, e.g. D_TZ, DUP_EVENT, L_WRONG_STATE"
          },
          "severity": {
            "type": "string",
            "enum": [
              "critical",
              "high",
              "medium",
              "low"
            ]
          },
          "detail": {
            "type": "object",
            "additionalProperties": {}
          },
          "firstSeen": {
            "type": "string"
          },
          "lastSeen": {
            "type": "string"
          },
          "resolvedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "actionTaken": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the check did: hidden, zone_fixed, card, kept, or null"
          }
        },
        "required": [
          "id",
          "eventId",
          "eventTitle",
          "eventSlug",
          "code",
          "severity",
          "detail",
          "firstSeen",
          "lastSeen",
          "resolvedAt",
          "actionTaken"
        ]
      },
      "QualityIssuePage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/QualityIssue"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items",
          "nextCursor"
        ]
      },
      "Reread": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventTitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "eventSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "at": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The page read; null when it couldn't be read"
          },
          "verdict": {
            "type": "string",
            "enum": [
              "confirmed",
              "cancelled",
              "differs",
              "unclear"
            ]
          },
          "action": {
            "type": "string",
            "enum": [
              "verified",
              "hidden",
              "corrected",
              "card",
              "none"
            ],
            "description": "What the re-read did: verified the listing, cancelled it, corrected its date, raised a card for you, or nothing"
          },
          "answers": {
            "type": "object",
            "additionalProperties": {},
            "description": "Each question's yes, no or unclear, and the page's own date; `error` when the page couldn't be read"
          },
          "quotes": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The page's own words behind each answer, only ones really on the page"
          },
          "pageHash": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "eventId",
          "eventTitle",
          "eventSlug",
          "at",
          "url",
          "verdict",
          "action",
          "answers",
          "quotes",
          "pageHash"
        ]
      },
      "RereadPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Reread"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items",
          "nextCursor"
        ]
      },
      "SavedItem": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Event"
          },
          {
            "type": "object",
            "properties": {
              "savedAt": {
                "type": "string"
              },
              "listing": {
                "type": "string",
                "enum": [
                  "listed",
                  "cancelled",
                  "unlisted"
                ]
              },
              "nextStartDate": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "nextEndDate": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "savedAt",
              "listing",
              "nextStartDate",
              "nextEndDate"
            ]
          }
        ]
      },
      "SavedEventIds": {
        "type": "object",
        "properties": {
          "ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "ids"
        ]
      },
      "SaveResult": {
        "type": "object",
        "properties": {
          "saved": {
            "type": "boolean"
          }
        },
        "required": [
          "saved"
        ]
      },
      "Series": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "normalizedName": {
            "type": "string"
          },
          "usualMonth": {
            "type": [
              "number",
              "null"
            ]
          },
          "frequency": {
            "type": "string",
            "enum": [
              "annual",
              "biannual",
              "monthly",
              "other"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "normalizedName",
          "usualMonth",
          "frequency"
        ]
      },
      "StatChip": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "href": {
            "type": "string"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "caption": {
            "type": [
              "string",
              "null"
            ],
            "description": "Shown under the compact value (e.g. \"published / queued\"); null with no caption"
          },
          "srValue": {
            "type": [
              "string",
              "null"
            ],
            "description": "The whole-sentence value read as this chip's accessible name (e.g. \"8 published, 88 sent to the queue\"); null when the visible value already says everything"
          },
          "changeLabel": {
            "type": [
              "string",
              "null"
            ],
            "description": "\"+12 since Oct 4\" / \"-3 since Oct 4\" / \"No change since Oct 4\"; null with nothing to compare against"
          },
          "changeDirection": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "up",
              "down",
              "flat",
              null
            ]
          },
          "series": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "number"
            },
            "description": "Oldest to newest, at most 14 points; null with fewer than 2"
          }
        },
        "required": [
          "key",
          "label",
          "href",
          "value",
          "caption",
          "srValue",
          "changeLabel",
          "changeDirection",
          "series"
        ]
      },
      "StatChips": {
        "type": "object",
        "properties": {
          "chips": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatChip"
            }
          }
        },
        "required": [
          "chips"
        ]
      },
      "MySuggestion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "startDate": {
            "type": "string"
          },
          "endDate": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "published",
              "not_accepted"
            ]
          },
          "eventSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "reasons": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "submittedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "title",
          "startDate",
          "endDate",
          "status",
          "eventSlug",
          "reasons",
          "submittedAt"
        ]
      },
      "TaxonomyEntry": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "parentSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "sortOrder": {
            "type": "integer"
          }
        },
        "required": [
          "slug",
          "label",
          "description",
          "parentSlug",
          "active",
          "sortOrder"
        ]
      },
      "Taxonomy": {
        "type": "object",
        "properties": {
          "craftTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxonomyEntry"
            }
          },
          "eventTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxonomyEntry"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxonomyEntry"
            }
          }
        },
        "required": [
          "craftTypes",
          "eventTypes",
          "tags"
        ]
      },
      "SiteInfo": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": [
              "string",
              "null"
            ]
          },
          "accentHex": {
            "type": "string"
          },
          "allowAll": {
            "type": "boolean"
          },
          "allowedCraftTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "slug",
          "name",
          "tagline",
          "accentHex",
          "allowAll",
          "allowedCraftTypes"
        ]
      },
      "Tenant": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "hosts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": [
              "string",
              "null"
            ]
          },
          "accentHex": {
            "type": "string"
          },
          "allowAll": {
            "type": "boolean"
          },
          "allowedCraftTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "owningCraftTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "canonicalPriority": {
            "type": "integer"
          },
          "imageStylePrompt": {
            "type": [
              "string",
              "null"
            ]
          },
          "isDefault": {
            "type": "boolean"
          },
          "theme": {
            "type": "string",
            "enum": [
              "county-fair",
              "craft-paper",
              "quilt-show",
              "gallery-linen",
              "sunny-fair"
            ]
          },
          "seasonMode": {
            "type": "string",
            "enum": [
              "auto",
              "fixed",
              "off"
            ]
          },
          "seasonFixed": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "fall",
              "holiday",
              "winter",
              "spring",
              "summer",
              null
            ]
          },
          "palette": {
            "type": [
              "string",
              "null"
            ],
            "description": "The chosen color palette; null means the theme's default"
          }
        },
        "required": [
          "slug",
          "hosts",
          "name",
          "tagline",
          "accentHex",
          "allowAll",
          "allowedCraftTypes",
          "owningCraftTypes",
          "canonicalPriority",
          "imageStylePrompt",
          "isDefault",
          "theme",
          "seasonMode",
          "seasonFixed",
          "palette"
        ]
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "displayName": {
            "type": [
              "string",
              "null"
            ]
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "organizer",
              "admin"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "remindersEnabled": {
            "type": "boolean",
            "description": "Whether the nightly saved-event reminder email is on for this account"
          },
          "welcomeEmails": {
            "type": "boolean",
            "description": "Whether the new-account welcome series' remaining emails are still on for this account"
          }
        },
        "required": [
          "id",
          "email",
          "displayName",
          "role",
          "createdAt",
          "remindersEnabled",
          "welcomeEmails"
        ]
      },
      "AdminUser": {
        "allOf": [
          {
            "$ref": "#/components/schemas/User"
          },
          {
            "type": "object",
            "properties": {
              "isSuspended": {
                "type": "boolean"
              },
              "lastSignInAt": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "suggestionTrust": {
                "type": "string",
                "enum": [
                  "untrusted",
                  "trusted",
                  "blocked"
                ]
              },
              "suggestionCounts": {
                "type": "object",
                "properties": {
                  "suggested": {
                    "type": "integer"
                  },
                  "published": {
                    "type": "integer"
                  }
                },
                "required": [
                  "suggested",
                  "published"
                ]
              },
              "eventsManaged": {
                "type": "integer",
                "description": "How many events this user owns as their organizer"
              }
            },
            "required": [
              "isSuspended",
              "lastSignInAt",
              "suggestionTrust",
              "suggestionCounts",
              "eventsManaged"
            ]
          }
        ]
      },
      "AdminUserManagedEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "startDate": {
            "type": "string"
          },
          "endDate": {
            "type": [
              "string",
              "null"
            ]
          },
          "nextStartDate": {
            "type": [
              "string",
              "null"
            ],
            "description": "The next occurrence's start date (today or later); null when it has none"
          },
          "status": {
            "type": "string",
            "enum": [
              "published",
              "cancelled",
              "hidden"
            ]
          },
          "featuredUntil": {
            "type": [
              "string",
              "null"
            ],
            "description": "The ends_on of the event's active or soonest upcoming feature; null when it isn't featured"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "slug",
          "title",
          "startDate",
          "endDate",
          "nextStartDate",
          "status",
          "featuredUntil",
          "city",
          "state"
        ]
      },
      "AdminUserClaim": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventTitle": {
            "type": "string"
          },
          "eventSlug": {
            "type": "string"
          },
          "eventStatus": {
            "type": "string",
            "enum": [
              "published",
              "cancelled",
              "hidden"
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "email_match",
              "admin",
              "invite"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected",
              "withdrawn"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "decidedAt": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "eventId",
          "eventTitle",
          "eventSlug",
          "eventStatus",
          "method",
          "status",
          "createdAt",
          "decidedAt"
        ]
      },
      "AdminUserRecentEdit": {
        "type": "object",
        "properties": {
          "auditId": {
            "type": "string"
          },
          "eventId": {
            "type": "string"
          },
          "eventTitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "eventSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "eventStatus": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "published",
              "cancelled",
              "hidden",
              null
            ],
            "description": "Null when the event no longer exists"
          },
          "at": {
            "type": "string"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The fields the edit changed"
          }
        },
        "required": [
          "auditId",
          "eventId",
          "eventTitle",
          "eventSlug",
          "eventStatus",
          "at",
          "fields"
        ]
      },
      "AdminUserWaiting": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The submission id"
          },
          "title": {
            "type": "string"
          },
          "startDate": {
            "type": "string"
          },
          "endDate": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "title",
          "startDate",
          "endDate",
          "city",
          "state",
          "createdAt"
        ]
      },
      "AdminProfileCard": {
        "type": "object",
        "properties": {
          "displayName": {
            "type": [
              "string",
              "null"
            ]
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "isPublic": {
            "type": "boolean",
            "description": "True only for an organizer with a display name and a slug"
          },
          "about": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "website": {
            "type": [
              "string",
              "null"
            ]
          },
          "crafts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Craft labels, in taxonomy order"
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarSmallUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "defaultAvatar": {
            "type": "string"
          },
          "checkedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "showChecked": {
            "type": "boolean",
            "description": "Shown only when there's About text or a picture"
          },
          "savedText": {
            "type": "string",
            "description": "Saved place and crafts from users.preferences in plain words, or 'None saved'"
          },
          "remindersEnabled": {
            "type": "boolean"
          }
        },
        "required": [
          "displayName",
          "slug",
          "isPublic",
          "about",
          "city",
          "state",
          "website",
          "crafts",
          "avatarUrl",
          "avatarSmallUrl",
          "defaultAvatar",
          "checkedAt",
          "showChecked",
          "savedText",
          "remindersEnabled"
        ]
      },
      "UserCounts": {
        "type": "object",
        "properties": {
          "saved": {
            "type": [
              "integer",
              "null"
            ],
            "description": "How many events they have saved"
          },
          "submissions": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "live": {
                "type": "integer"
              },
              "waiting": {
                "type": "integer"
              },
              "notAccepted": {
                "type": "integer"
              }
            },
            "required": [
              "live",
              "waiting",
              "notAccepted"
            ],
            "description": "Their own event_submissions by outcome, not counting source checks"
          },
          "claims": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Their own claims, not counting the bookkeeping claim for an event they added"
          },
          "emailsSent": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Emails logged to this account; null before migration 027"
          }
        },
        "required": [
          "saved",
          "submissions",
          "claims",
          "emailsSent"
        ]
      },
      "AdminUserDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AdminUser"
          },
          {
            "type": "object",
            "properties": {
              "managedEvents": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AdminUserManagedEvent"
                }
              },
              "claims": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AdminUserClaim"
                }
              },
              "recentEdits": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "$ref": "#/components/schemas/AdminUserRecentEdit"
                },
                "description": "Their last 10 organizer edits, newest first; null when the lookup failed"
              },
              "waiting": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "$ref": "#/components/schemas/AdminUserWaiting"
                },
                "description": "Their added events waiting for review, oldest first; null when the lookup failed"
              },
              "profile": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/AdminProfileCard"
                  },
                  {
                    "type": [
                      "object",
                      "null"
                    ],
                    "description": "The profile card's data; null when the account has no profile row yet"
                  }
                ]
              },
              "counts": {
                "$ref": "#/components/schemas/UserCounts"
              }
            },
            "required": [
              "managedEvents",
              "claims",
              "recentEdits",
              "waiting",
              "profile",
              "counts"
            ]
          }
        ]
      },
      "ActivityItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "sign_in",
              "saved",
              "submission",
              "claim",
              "organizer_edit",
              "picture",
              "profile",
              "email",
              "admin_action"
            ]
          },
          "at": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "href": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "kind",
          "at",
          "text",
          "href"
        ]
      },
      "UserActivityPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityItem"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "partial": {
            "type": "boolean",
            "description": "True when at least one kind of activity failed to load this page"
          }
        },
        "required": [
          "items",
          "nextCursor",
          "partial"
        ]
      },
      "AdminOrganizer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "displayName": {
            "type": [
              "string",
              "null"
            ]
          },
          "publicSlug": {
            "type": [
              "string",
              "null"
            ],
            "description": "Their public /organizers/{slug} page, only while their profile is public"
          },
          "role": {
            "type": "string",
            "enum": [
              "user",
              "organizer",
              "admin"
            ]
          },
          "isSuspended": {
            "type": "boolean"
          },
          "trust": {
            "type": "string",
            "enum": [
              "untrusted",
              "trusted",
              "blocked"
            ]
          },
          "events": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "upcoming": {
                "type": "integer"
              },
              "total": {
                "type": "integer"
              },
              "next": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "slug": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "published",
                      "cancelled",
                      "hidden"
                    ]
                  },
                  "date": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "slug",
                  "title",
                  "status",
                  "date"
                ]
              }
            },
            "required": [
              "upcoming",
              "total",
              "next"
            ],
            "description": "Upcoming published events (by next occurrence), every event they own, and the next one; null when the lookup failed"
          },
          "waiting": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Their added events waiting for review; null when the lookup failed"
          },
          "claims": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "approved": {
                "type": "integer"
              },
              "pending": {
                "type": "integer"
              }
            },
            "required": [
              "approved",
              "pending"
            ]
          },
          "joined": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "how": {
                "type": "string",
                "enum": [
                  "invite",
                  "claim",
                  "added"
                ]
              },
              "at": {
                "type": "string"
              }
            },
            "required": [
              "how",
              "at"
            ],
            "description": "How they became an organizer, earliest first: an invite, a claim, or an added event of their own"
          },
          "lastActiveAt": {
            "type": [
              "string",
              "null"
            ],
            "description": "The latest of their last sign-in, latest organizer edit and latest added event"
          }
        },
        "required": [
          "id",
          "email",
          "displayName",
          "publicSlug",
          "role",
          "isSuspended",
          "trust",
          "events",
          "waiting",
          "claims",
          "joined",
          "lastActiveAt"
        ]
      },
      "AdminOrganizerPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdminOrganizer"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "total": {
            "type": "integer"
          }
        },
        "required": [
          "items",
          "nextCursor",
          "total"
        ]
      },
      "Me": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "session",
              "apiKey"
            ]
          },
          "scope": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "read",
              "user",
              "admin",
              null
            ]
          },
          "user": {
            "allOf": [
              {
                "$ref": "#/components/schemas/User"
              },
              {
                "type": [
                  "object",
                  "null"
                ]
              }
            ]
          },
          "profile": {
            "allOf": [
              {
                "$ref": "#/components/schemas/HeaderProfile"
              },
              {
                "type": [
                  "object",
                  "null"
                ],
                "description": "The account's picture and display name for the site header; null with no user or when it can't be read"
              }
            ]
          }
        },
        "required": [
          "kind",
          "scope",
          "user",
          "profile"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/api/account": {
      "get": {
        "summary": "Get my account",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update my display name, reminder setting or welcome emails",
        "description": "Send displayName, remindersEnabled, welcomeEmails, or any combination; at least one is required. displayName is the profile's display name (the same one PATCH /api/account/profile sets, with the same rules for the public address); blank clears it. welcomeEmails is the new-account welcome series' own \"Stop these emails\" switch.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "displayName": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 60
                  },
                  "remindersEnabled": {
                    "type": "boolean"
                  },
                  "welcomeEmails": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete my account (irreversible)",
        "description": "Anonymizes your account, clears your saved search preferences, signs you out everywhere and revokes your API keys.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/claims": {
      "get": {
        "summary": "List my event claims",
        "description": "This account's claims to manage events, newest first (up to 100): pending, approved, rejected (with the admin's note) or withdrawn, each with its event.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyClaims"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/events": {
      "get": {
        "summary": "List my events",
        "description": "Events this account manages, in any status (up to 200): upcoming soonest first and past newest first, each with its join and contact details.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyEvents"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Add a new event of mine",
        "description": "Adds an event from any signed-in account. organizer_email defaults to the account's own email. An admin-trusted account's event with nothing to check (no possible duplicate or other flag) is published at once and owned by this account; anything else waits for review, and is owned by this account once approved. The account becomes an organizer (with a public organizer page) only when one of its events publishes, never while it waits. A past date is 400.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrganizerEventInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizerEventCreated"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/events/{id}": {
      "get": {
        "summary": "Get one of my events",
        "description": "One event this account manages, in any status, with its join and contact details. Someone else's event is 404.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyEvent"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Edit one of my events",
        "description": "Changes an event this account manages, live. Only its listing fields can change (never its status, address slug or owner); a changed date, time, place or price marks it Updated. A cancelled event can't be edited (409). Someone else's event is 404.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "summary": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 300
                  },
                  "description": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 5000
                  },
                  "start_date": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 10
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 10
                  },
                  "start_time": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 8
                  },
                  "end_time": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 8
                  },
                  "timezone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 64
                  },
                  "recurrence": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "location_kind": {
                    "type": "string",
                    "enum": [
                      "venue",
                      "online",
                      "hybrid",
                      "multi"
                    ]
                  },
                  "venue": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "street_address": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "city": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  },
                  "state": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 40
                  },
                  "postal_code": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^\\d{5}$"
                  },
                  "url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^https?:\\/\\//i"
                  },
                  "signup_note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "price_note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "is_free": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "join_platform": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "zoom",
                      "meet",
                      "teams",
                      "webex",
                      "facebook",
                      "youtube",
                      "other",
                      null
                    ]
                  },
                  "join_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  },
                  "join_meeting_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "join_passcode": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "join_phone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "contact_name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120
                  },
                  "contact_email": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "contact_phone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "craft_types": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "event_type": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "languages": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 40
                    },
                    "maxItems": 5
                  },
                  "hosted_by": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120
                  },
                  "schedule_change": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "postponed",
                      "rescheduled",
                      "moved_online",
                      null
                    ],
                    "description": "postponed (new date to come), rescheduled or moved_online; null for scheduled (runs as listed). Cancelling is the status field (admin) or the cancel route (organizer)"
                  },
                  "previous_start_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 10,
                    "description": "A rescheduled event's earlier start date (YYYY-MM-DD); defaults to the start date this edit moves"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyEvent"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/events/{id}/cancel": {
      "post": {
        "summary": "Cancel one of my events",
        "description": "Cancels an event this account manages. It leaves the directory, and everyone who saved it gets an email that it was cancelled. Cancelling is one-way: only an admin can reinstate it. Cancelling an already-cancelled event changes nothing. Someone else's event is 404.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyEventCancelled"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/events/{id}/images": {
      "get": {
        "summary": "List my event's pictures",
        "description": "The pictures on an event this account manages, in order (the first is the cover). An admin may list any event's. Someone else's event is 404.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventImages"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Add a picture to my event",
        "description": "Adds a picture to a published event this account manages, live at once, after the others. Send multipart/form-data with a file (at most 4 MB) and alt, a description of 1 to 200 characters; MCP callers send JSON with the file as base64. The picture is re-encoded as 1600px and 600px wide WebP with none of the original's metadata kept. At most 6 pictures an event and 30 uploads a day. An unpublished event is a 400; someone else's event is 404.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/EventImageUpload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventImages"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "413 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "429 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/events/{id}/images/{imageId}": {
      "patch": {
        "summary": "Change a picture on my event",
        "description": "Changes a picture's description, focus point or place in the order (position 0 makes it the cover; the others move along). An admin may change any event's pictures. Someone else's event, or a picture not on this event, is 404.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "imageId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventImagePatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventImages"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Remove a picture from my event",
        "description": "Removes a picture and its files; the next one becomes the cover. An admin may remove any event's pictures. Someone else's event, or a picture not on this event, is 404.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "required": true,
            "name": "imageId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventImages"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/profile": {
      "get": {
        "summary": "Get my profile",
        "description": "This account's profile: display name, public address, About, website, town and state, crafts and picture. Created on first read with a random craft badge.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyProfile"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update my profile",
        "description": "Send any of displayName, about, website, city, state and crafts; blank clears a field. A new display name sets the public address (/organizers/{slug}) unless it changed under 30 days ago, when the old one is kept and slugLocked is true. An organizer's About change is queued for an admin check.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProfilePatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyProfile"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/profile/avatar": {
      "post": {
        "summary": "Upload my picture",
        "description": "Replaces the profile picture. Send multipart/form-data with a file (at most 4 MB) and an optional crop, a JSON string {x, y, size} of whole numbers in the picture's upright pixels; MCP callers send the file as base64. The picture is re-encoded as 512px and 96px squares with none of the original's metadata kept. At most 10 pictures a day. An organizer's new picture is queued for an admin check.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AvatarUpload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyProfile"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "413 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "429 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Use my default badge",
        "description": "Removes the uploaded picture, so the profile shows its built-in craft badge again.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyProfile"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/profile/avatar/shuffle": {
      "post": {
        "summary": "Shuffle my default badge",
        "description": "Picks a different built-in craft badge at random. An uploaded picture, if any, still shows instead.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MyProfile"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/recommended": {
      "get": {
        "summary": "Events suggested for me",
        "description": "Up to 6 upcoming events like the ones this account saved (\"Suggested for you\" on the account page), never one it already saved: the 2 top-level crafts seen on the most saves (the most saved event type when no save has a craft); within 100 miles of the account's saved place, else of the center of its densest cluster of saved in-person events, nearest first (250 miles when that leaves fewer than 3), else in the state seen on the most saves, soonest first; over the next 60 days. Empty with no saves.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSearchItem"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/saved": {
      "get": {
        "summary": "List my saved events",
        "description": "Upcoming saved events (soonest occurrence first) or past ones (newest first), 20 per page, filtered to crafts the current tenant allows. A saved event that was later cancelled or hidden still appears, with its current listing status.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "upcoming",
                "past"
              ],
              "default": "upcoming"
            },
            "required": false,
            "name": "when",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SavedItem"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/saved/ids": {
      "get": {
        "summary": "List my saved event ids",
        "description": "At most 500 event ids, filtered to crafts the current tenant allows, used to fill in the saved heart on a page.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedEventIds"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/account/suggestions": {
      "get": {
        "summary": "List my suggested events",
        "description": "Every event this account has suggested, newest first: pending, published (with its event) or not accepted (with plain reason labels). The admin's free-text note is never included.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MySuggestion"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/api-keys": {
      "get": {
        "summary": "List API keys",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": false,
            "name": "userId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create an API key (plaintext returned once)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80
                  },
                  "scope": {
                    "type": "string",
                    "enum": [
                      "read",
                      "user",
                      "admin"
                    ]
                  },
                  "userId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "name",
                  "scope"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "$ref": "#/components/schemas/ApiKey"
                    },
                    "plaintext": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "key",
                    "plaintext"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/api-keys/{id}": {
      "delete": {
        "summary": "Revoke an API key",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKey"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/appearance": {
      "get": {
        "summary": "The site's theme, season and color settings, with every theme to choose from",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminAppearance"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Change the site's theme, season or color setting",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "theme": {
                    "type": "string",
                    "enum": [
                      "county-fair",
                      "craft-paper",
                      "quilt-show",
                      "gallery-linen",
                      "sunny-fair"
                    ]
                  },
                  "seasonMode": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "fixed",
                      "off"
                    ]
                  },
                  "seasonFixed": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "fall",
                      "holiday",
                      "winter",
                      "spring",
                      "summer",
                      null
                    ]
                  },
                  "palette": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40,
                    "description": "A color palette of the theme; null for its default"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appearance"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/audit": {
      "get": {
        "summary": "Admin audit log, newest first",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "required": false,
            "name": "action",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": false,
            "name": "actorUserId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "required": false,
            "name": "targetType",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "targetId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditRecord"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/automation/summary": {
      "get": {
        "summary": "This week's automation summary: auto-published events, auto-merged updates, source trust changes and spot checks",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AutomationSummary"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/claims": {
      "get": {
        "summary": "List claims to manage events (oldest first)",
        "description": "Claims by status (default pending), each with its event, the claimant's email and the event's current owner's email when it has one (a dispute).",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "withdrawn"
              ],
              "default": "pending"
            },
            "required": false,
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdminClaim"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/claims/{id}/approve": {
      "post": {
        "summary": "Approve a claim and make the claimant the event's owner",
        "description": "Makes the claimant the event's owner (replacing any earlier owner's approved claim), makes them an organizer and emails them; an owner it replaces is emailed that they no longer manage the event. 409 when the claim was already decided or the event's owner changed while saving.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClaimResult"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/claims/{id}/reject": {
      "post": {
        "summary": "Reject a claim",
        "description": "Rejects a pending claim, with an optional note (up to 300 characters) shown to the claimant and sent in the email. 409 when the claim was already decided.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "maxLength": 300
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClaimResult"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/corrections": {
      "get": {
        "summary": "Correction requests inbox (oldest first)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "resolved",
                "dismissed"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Correction"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/corrections/{id}": {
      "patch": {
        "summary": "Resolve or dismiss a correction request",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "resolved",
                      "dismissed"
                    ]
                  },
                  "note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 1000
                  },
                  "eventAction": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "hide",
                      "cancel",
                      null
                    ]
                  }
                },
                "required": [
                  "status"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Correction"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/corrections/{id}/apply": {
      "post": {
        "summary": "Apply a Postponed or New date correction request to its event",
        "description": "WI-107. Postponed marks the event postponed (new date to come); a New date request (kind rescheduled) moves the event to `startDate` or the request's own date, keeping its length, and marks it rescheduled from the date it had. Resolves the request in the same call; a request is never applied on its own. 409 once handled; 503 before migration 044.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "startDate": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "For a rescheduled request: the new start date, overriding the request's own"
                  },
                  "note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Correction"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/daily-actions": {
      "get": {
        "summary": "List daily actions",
        "description": "Open actions first (oldest raised first), then closed actions (newest closed first); optionally filtered to one status. kind narrows to plain actions or Claude's own findings (a row from before migration 032 always reads as kind \"action\"). 503 until the daily report is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "done",
                "dropped"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "action",
                "finding"
              ]
            },
            "required": false,
            "name": "kind",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyActionList"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/daily-actions/{id}": {
      "patch": {
        "summary": "Close a daily action as done or dropped",
        "description": "{ status: \"done\" | \"dropped\", reason? } up to 300 characters. 404 for an unknown id; 409 once it's already closed (a race, such as a double click or two tabs, never re-closes it or changes its reason). 503 until the daily report is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "done",
                      "dropped"
                    ]
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 300
                  }
                },
                "required": [
                  "status"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyAction"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/daily-reports": {
      "get": {
        "summary": "List daily reports (newest first)",
        "description": "Each day's report without its snapshot, 30 a page, newest first. 503 until the daily report is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyReportList"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/daily-reports/{date}": {
      "get": {
        "summary": "Get one day's report",
        "description": "The full report (snapshot, flags, words) for one Pacific date (YYYY-MM-DD). 404 when there is none; 503 until the daily report is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "date"
            },
            "required": true,
            "name": "date",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DailyReport"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/dashboard": {
      "get": {
        "summary": "Admin dashboard tiles",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminDashboard"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/data-fixes": {
      "get": {
        "summary": "List the rule-based data fixes from the last 14 days",
        "description": "The five kinds of rule-based data fix (pause a junk source, hide a past one-off event, hide a no-longer-listed event, close a stale queue item, or close one a second opinion confirmed isn't a real crafting event or is already over), newest first, at most 200, each with whether it's already been undone some other way.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFixList"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/data-fixes/{auditId}/undo": {
      "post": {
        "summary": "Undo one of the five rule-based data fixes",
        "description": "Reverses a junk-source pause, a past-event hide, a no-longer-listed hide, a stale-queue close or a second-opinion close by its own audit entry, each through a write guarded on exactly the state the fix left behind - never the generic admin PATCH routes, which carry no such guard. 404 for an unknown audit id, or one whose action isn't one of the five fix shapes `GET /api/admin/data-fixes` itself lists. 409 \"This changed since it was fixed, so it can't be undone here.\" when the target already moved on some other way since the fix ran.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            },
            "required": true,
            "name": "auditId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/emails": {
      "get": {
        "summary": "List the emails the site sent (newest first)",
        "description": "The email log, 50 a page, newest first, optionally one kind and/or one delivery status. A recipient that is an organizer with a public profile carries its organizer slug. 503 until the email log is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "sign_in",
                "reminder",
                "change",
                "event_live",
                "claim_decision",
                "organizer_invite",
                "invite_reminder",
                "welcome"
              ]
            },
            "required": false,
            "name": "kind",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "sent",
                "delivered",
                "bounced",
                "complained",
                "failed"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailLogPage"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/emails/{id}": {
      "get": {
        "summary": "Get one sent email with its text",
        "description": "One email from the log with its plain-text part as sent (a sign-in email's code and link blanked). bodyText is null for an email sent before text was kept. 404 for an unknown id; 503 until the email log is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailDetail"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events": {
      "get": {
        "summary": "Admin event list (newest first)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "published",
                "cancelled",
                "hidden"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "public",
                "scrape",
                "organizer"
              ]
            },
            "required": false,
            "name": "origin",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200,
              "description": "Search: matches the title or the slug, case-insensitively; a pasted event web address (/events/<slug>) searches its slug."
            },
            "required": false,
            "description": "Search: matches the title or the slug, case-insensitively; a pasted event web address (/events/<slug>) searches its slug.",
            "name": "q",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdminEventListItem"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events/auto-published": {
      "get": {
        "summary": "Auto-published events from the last N days, with a deterministic weekly spot-check sample",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30,
              "default": 7
            },
            "required": false,
            "name": "days",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/AdminEventListItem"
                          },
                          {
                            "type": "object",
                            "properties": {
                              "sampled": {
                                "type": "boolean"
                              }
                            },
                            "required": [
                              "sampled"
                            ]
                          }
                        ]
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events/{id}": {
      "get": {
        "summary": "Get one event for admin editing",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminEvent"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Edit, hide, cancel or republish an event",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "description": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 5000
                  },
                  "summary": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 280
                  },
                  "start_date": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 10
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 10
                  },
                  "start_time": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 8
                  },
                  "end_time": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 8
                  },
                  "timezone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 64
                  },
                  "recurrence": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "city": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  },
                  "state": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 40
                  },
                  "venue": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "location_kind": {
                    "type": "string",
                    "enum": [
                      "venue",
                      "online",
                      "hybrid",
                      "multi"
                    ]
                  },
                  "languages": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 40
                    },
                    "maxItems": 5
                  },
                  "hosted_by": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120
                  },
                  "street_address": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "postal_code": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^\\d{5}$"
                  },
                  "signup_note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "join_platform": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "zoom",
                      "meet",
                      "teams",
                      "webex",
                      "facebook",
                      "youtube",
                      "other",
                      null
                    ]
                  },
                  "join_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  },
                  "join_meeting_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "join_passcode": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "join_phone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "contact_name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120
                  },
                  "contact_email": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "contact_phone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "craft_types": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "event_type": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^https?:\\/\\//i"
                  },
                  "organizer_name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "price_note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "is_free": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "schedule_change": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "postponed",
                      "rescheduled",
                      "moved_online",
                      null
                    ],
                    "description": "postponed (new date to come), rescheduled or moved_online; null for scheduled (runs as listed). Cancelling is the status field (admin) or the cancel route (organizer)"
                  },
                  "previous_start_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 10,
                    "description": "A rescheduled event's earlier start date (YYYY-MM-DD); defaults to the start date this edit moves"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "published",
                      "cancelled",
                      "hidden"
                    ]
                  },
                  "series_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid"
                  },
                  "source_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 1000,
                    "format": "uri"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminEvent"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events/{id}/features": {
      "post": {
        "summary": "Feature a published event",
        "description": "Adds a feature window (startsOn to endsOn, at most 366 days) to a published event. 400 for a bad window, an unpublished event, or a window that overlaps one of the event's active or upcoming features that hasn't ended early.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "startsOn": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  "endsOn": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  "note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  }
                },
                "required": [
                  "startsOn",
                  "endsOn"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feature"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events/{id}/features/{featureId}": {
      "delete": {
        "summary": "End a feature early",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "featureId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Feature"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events/{id}/owner": {
      "delete": {
        "summary": "Remove an event's owner",
        "description": "Clears the event's owner and withdraws its approved claims. The event itself is unchanged. The removed owner can ask again, but only through a claim an admin decides, never an instant email match.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events/{id}/revert": {
      "post": {
        "summary": "Undo one auto-merged update to a published event",
        "description": "Restores the event's values from before the named event.auto_update audit entry, refreshes occurrences, protects the event from future auto-merges, and scores the merged submission's spot check as rejected. 400 when that audit isn't an automatic update of this event, 409 when the event changed since (an admin edit, or a later auto-merge touching the same fields).",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "auditId": {
                    "type": "string",
                    "pattern": "^\\d+$"
                  }
                },
                "required": [
                  "auditId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminEvent"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/events/{id}/undo-organizer-edit": {
      "post": {
        "summary": "Undo one organizer edit to an owned event",
        "description": "Restores the event's values from before the named event.organizer_update audit entry, refreshes occurrences and marks the event admin-edited. The undo counts as a strike against the organizer. 400 when that audit isn't an organizer edit of this event, 409 when the event changed since (a later admin edit, or a later edit, auto-merge or undo touching the same fields).",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "auditId": {
                    "type": "string",
                    "pattern": "^\\d+$"
                  }
                },
                "required": [
                  "auditId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminEvent"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/features": {
      "get": {
        "summary": "List featured events by status",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "upcoming",
                "past"
              ],
              "default": "active"
            },
            "required": false,
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureListResult"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/gate/buckets/{bucket}": {
      "patch": {
        "summary": "Retired: bands no longer go live or shadow on their own",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "0.75-0.85",
                "0.85-0.9",
                "0.9+"
              ]
            },
            "required": true,
            "name": "bucket",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "live": {
                    "type": "boolean"
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "required": [
                  "live"
                ]
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "410 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/gate/report": {
      "get": {
        "summary": "Auto-approval gate report: per-band precision and readiness",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GateReport"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/gate/settings": {
      "get": {
        "summary": "The auto-approval gate's switch, quality target and threshold, with per-candidate evidence",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GateSettingsResponse"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Turn auto-approval on or off, change its quality target, or resume after a pause",
        "description": "Body { enabled?, target? }, at least one field. target is 0.90, 0.95 or 0.98. Sending enabled: true while paused clears the pause.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "target": {
                    "anyOf": [
                      {
                        "type": "number",
                        "enum": [
                          0.9
                        ]
                      },
                      {
                        "type": "number",
                        "enum": [
                          0.95
                        ]
                      },
                      {
                        "type": "number",
                        "enum": [
                          0.98
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GateSettings"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/growth": {
      "get": {
        "summary": "How the site is growing",
        "description": "The invite funnel (could invite, sent, reminded, claimed, opted out, bounced, claim rate, featured spots left), what organizers do after claiming (organizers, events they manage, their share of upcoming events, the last 30 days' edits, added events and pictures), the last 8 Monday-start Pacific weeks, newest first, and the welcome series' own numbers (each step's sent, skipped and stopped counts, and how many of the people who started it saved or added an event within 14 days, or saved preferences within a day; null before migration 035).",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrowthSummary"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/hubs": {
      "get": {
        "summary": "List the state and category hub pages",
        "description": "Every hub (/quilt-shows/washington and the like) with its in-person events in the next 12 months, its shows and festivals, whether it passes the index rule, whether it is indexed now, and its intro. configured is false before migration 045 (no intros, nothing indexed).",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HubAdminList"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/hubs/{category}/{state}": {
      "patch": {
        "summary": "Save or approve a hub's intro",
        "description": "{ intro, approve }. approve: true stores the intro approved, so the hub is indexed once it also passes the rule (a hub is never first indexed without an approved intro); approve: false stores it as a draft and withdraws any approval. state is the two-letter code. No long dashes (use a hyphen or comma). Audited hub.intro. 404 for an unknown hub; 503 before migration 045.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{3,60}$"
            },
            "required": true,
            "name": "category",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z]{2}$"
            },
            "required": true,
            "name": "state",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "intro": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "approve": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "intro",
                  "approve"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HubStatus"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/images/{id}/check": {
      "post": {
        "summary": "Mark an organizer's event picture as checked",
        "description": "The picture looks fine: it leaves the inbox's Pictures to check. Takes no body. 404 for an unknown picture; 409 when it was already checked or removed.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/images/{id}/remove": {
      "post": {
        "summary": "Remove an organizer's event picture",
        "description": "Removes the picture from its event (the next one becomes the cover), deletes its files and marks it checked. Takes no body. Counts as a strike against the organizer who uploaded it, like an undone edit. 404 for an unknown picture; 409 when it was already removed.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/inbox": {
      "get": {
        "summary": "Everything that needs an admin, grouped and in priority order",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Inbox"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/inbox/{group}": {
      "get": {
        "summary": "The next page of one inbox group",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "description": "One group key, in priority order: paused, ingest, added, spotChecks, review, claims, invites, reachByHand (organizers to message by hand), organizerEdits, profiles, pictures, sourceChecks, trustLost (sources that lost trust, with who rejected them), corrections, candidates, trust (sources ready to trust)"
            },
            "required": true,
            "description": "One group key, in priority order: paused, ingest, added, spotChecks, review, claims, invites, reachByHand (organizers to message by hand), organizerEdits, profiles, pictures, sourceChecks, trustLost (sources that lost trust, with who rejected them), corrections, candidates, trust (sources ready to trust)",
            "name": "group",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "has",
                "none",
                "unread"
              ],
              "description": "candidates only (WI-802): has (upcoming events on the page), none (read, no upcoming dates), unread (the page couldn't be read to count), all (default)"
            },
            "required": false,
            "description": "candidates only (WI-802): has (upcoming events on the page), none (read, no upcoming dates), unread (the page couldn't be read to count), all (default)",
            "name": "preview",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "newest",
                "upcoming"
              ],
              "description": "candidates only (WI-802): newest (default) or upcoming (most upcoming events first)"
            },
            "required": false,
            "description": "candidates only (WI-802): newest (default) or upcoming (most upcoming events first)",
            "name": "sort",
            "in": "query"
          },
          {
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0,
              "maximum": 1000,
              "description": "Items acted on since the cursor's page loaded; moves an offset-paged group's cursor back so none are skipped"
            },
            "required": false,
            "description": "Items acted on since the cursor's page loaded; moves an offset-paged group's cursor back so none are skipped",
            "name": "removed",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxGroupPage"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/ingest/runs": {
      "get": {
        "summary": "List ingest runs",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/IngestRun"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Run ingest now (synchronous, up to 10 sources)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "maxSources": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10
                  },
                  "sourceIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "maxItems": 10
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestRun"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/ingest/runs/{id}": {
      "get": {
        "summary": "Get one ingest run, with the sources it names and its run-wide counts",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestRunDetail"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/organizer-edits/{auditId}/ok": {
      "post": {
        "summary": "Mark an organizer edit as fine",
        "description": "Takes the named event.organizer_update audit entry out of the inbox's organizer edits without changing the event. 404 when that audit isn't an organizer edit.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            },
            "required": true,
            "name": "auditId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/invites": {
      "get": {
        "summary": "List organizer invites (oldest first)",
        "description": "status defaults to \"review\": every draft plus every sent invite with a reminder draft waiting - the inbox group's own set. Pass a single InviteStatus (draft, sent, skipped, claimed, stopped, expired) to filter instead.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "anyOf": [
                {
                  "type": "string",
                  "enum": [
                    "review"
                  ]
                },
                {
                  "type": "string",
                  "enum": [
                    "draft",
                    "sent",
                    "skipped",
                    "claimed",
                    "stopped",
                    "expired"
                  ]
                }
              ],
              "default": "review"
            },
            "required": false,
            "name": "status",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InviteList"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/invites/{id}": {
      "patch": {
        "summary": "Edit a draft invite's optional opening line",
        "description": "{ intro } up to 300 characters, or null to clear it. Only a draft can be edited; 409 once it's sent, skipped or closed.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "intro": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 300
                  }
                },
                "required": [
                  "intro"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminInvite"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/invites/{id}/never": {
      "post": {
        "summary": "Never contact this address",
        "description": "Suppresses the invite's address for good and deletes a draft or stops a sent invite. Takes no body.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/invites/{id}/preview": {
      "get": {
        "summary": "Preview the exact email a send would produce",
        "description": "The invite or reminder email rendered from the live template, with a placeholder claim link - a real one is minted only once the invite is actually sent.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitePreview"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/invites/{id}/send": {
      "post": {
        "summary": "Send a draft invite, or the reminder for a sent one",
        "description": "Sends the first email for a draft, or the one reminder for a sent invite with a pending reminder draft. Takes no body. 409 when neither applies, the mailing address is empty, sending is paused, the address is suppressed, or none of the invite's events still qualify.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminInvite"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "502": {
            "description": "502 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/invites/{id}/skip": {
      "post": {
        "summary": "Skip a draft invite, or a pending reminder draft",
        "description": "Turns a draft into skipped, or marks a sent invite's pending reminder draft skipped (the invite itself stays sent until claimed or expired). Takes no body. 409 when there's nothing waiting to skip.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/hand": {
      "post": {
        "summary": "Reach by hand (WI-591): mark an organizer reached, skipped or never to list. Sends nothing",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "organizerKey": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "The organizer's key from the reachByHand inbox group"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "reached",
                      "skip",
                      "never"
                    ],
                    "description": "reached: off the list for 60 days; skip: 90 days; never: for good"
                  }
                },
                "required": [
                  "organizerKey",
                  "action"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/hand/message": {
      "post": {
        "summary": "Reach by hand (WI-591): mint the organizer's own claim link and return a friendly message for an admin to paste on Facebook or Instagram himself. Sends nothing",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "organizerKey": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300,
                    "description": "The organizer's key from the reachByHand inbox group"
                  }
                },
                "required": [
                  "organizerKey"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "claimUrl": {
                      "type": "string"
                    },
                    "expiresOn": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message",
                    "claimUrl",
                    "expiresOn"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/settings": {
      "get": {
        "summary": "The outreach mailing address and pause state",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutreachSettings"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Set the mailing address, or resume after a safety pause",
        "description": "Body { postalAddress?, resume? }. postalAddress is trimmed and must be 5 to 300 characters; nothing sends until it's set. resume: true clears a safety pause (the same way sending is first turned on).",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "postalAddress": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 300
                  },
                  "resume": {
                    "type": "boolean",
                    "enum": [
                      true
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutreachSettings"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/summary": {
      "get": {
        "summary": "The invites inbox group's numbers",
        "description": "How many invites are drafted, sent (one email per organizer address), reminded and claimed, with the claimed event count and the events listed across sent invites, how many addresses opted out or bounced, and how many of the first-25 featured spots are left, plus the same numbers in plain words.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutreachSummary"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/suppressions": {
      "get": {
        "summary": "List addresses that asked not to be contacted (newest first)",
        "description": "50 a page: opt-outs, 'not mine' reports, bounces, complaints and admin 'never contact's.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Suppression"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/outreach/suppressions/{email}": {
      "delete": {
        "summary": "Let a suppressed address receive invites again",
        "description": "Removes the address from the do-not-contact list. 404 when it isn't suppressed.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "email"
            },
            "required": true,
            "name": "email",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/profiles": {
      "get": {
        "summary": "List organizer profiles to check (oldest change first)",
        "description": "Organizers' profiles whose About text or picture changed since an admin last checked them, plus organizer profiles never checked that have About text or a picture (for example someone made an organizer after writing them). Act on each with POST /api/admin/profiles/{userId}/check or /remove.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfilesToCheckPage"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/profiles/{userId}/check": {
      "post": {
        "summary": "Mark an organizer's profile as checked",
        "description": "The profile looks fine: it leaves the profiles to check until its About text or picture changes again. The body is optional; with changedAt (the item's, as loaded) a profile changed since is a 409 and stays unchecked. 404 for an unknown user.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "userId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckProfileBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/profiles/{userId}/remove": {
      "post": {
        "summary": "Remove an organizer's picture or About text",
        "description": "Removes the profile's picture (and its files) or clears its About text, and marks the profile checked. Counts as a strike against the organizer, like an undone edit. 404 for an unknown user; 409 when there is no picture or About text left to remove, or, with changedAt (the item's, as loaded), when the profile changed since.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "userId",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveProfileContentBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/quality/issues": {
      "get": {
        "summary": "List the nightly quality check's issues (newest first)",
        "description": "The nightly quality check's issues over live listings, open (the default) or resolved, optionally one rule code, 50 a page, newest first, each with its event's title and slug. 503 until the quality check is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "resolved"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[A-Z_]{2,40}$"
            },
            "required": false,
            "name": "code",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QualityIssuePage"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/quality/rereads": {
      "get": {
        "summary": "List the daily re-reads of live listings (newest first)",
        "description": "Each morning's re-reads of live listings against their own page: what the page said, the quotes behind it, and what the re-read did (verified, cancelled, corrected the date, raised a card, or nothing). Optionally one event's, 50 a page, newest first. 503 until the re-read is set up.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": false,
            "name": "eventId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RereadPage"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/series": {
      "get": {
        "summary": "List event series",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Series"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create an event series",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "usualMonth": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "minimum": 1,
                    "maximum": 12
                  },
                  "frequency": {
                    "type": "string",
                    "enum": [
                      "annual",
                      "biannual",
                      "monthly",
                      "other"
                    ]
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Series"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/sources": {
      "get": {
        "summary": "List scrape sources",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "candidate",
                "active",
                "paused",
                "rejected"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "untrusted",
                "suggested",
                "trusted",
                "blocked"
              ]
            },
            "required": false,
            "name": "trust",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "youtube"
              ],
              "description": "WI-512: only YouTube channel sources (read through the YouTube API)"
            },
            "required": false,
            "description": "WI-512: only YouTube channel sources (read through the YouTube API)",
            "name": "kind",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Source"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Register a scrape source",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "url": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "craftTypes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "state": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "candidate",
                      "active",
                      "paused",
                      "rejected"
                    ]
                  },
                  "notes": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 2000
                  }
                },
                "required": [
                  "name",
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Source"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/sources/discover": {
      "post": {
        "summary": "Search the web for candidate sources (craft + state)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "craft": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 60
                  },
                  "state": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 40
                  },
                  "online": {
                    "type": "boolean"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10,
                    "default": 5
                  }
                },
                "required": [
                  "craft"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Source"
                      }
                    },
                    "skipped": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string"
                          },
                          "reason": {
                            "type": "string",
                            "enum": [
                              "aggregator",
                              "known",
                              "invalid",
                              "over_limit",
                              "single_event",
                              "blocked_host"
                            ]
                          }
                        },
                        "required": [
                          "url",
                          "reason"
                        ]
                      }
                    }
                  },
                  "required": [
                    "created",
                    "skipped"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/sources/{id}": {
      "get": {
        "summary": "Get a scrape source",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Source"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update a source (status, trust, details)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "url": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "craftTypes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "state": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "candidate",
                      "active",
                      "paused",
                      "rejected"
                    ]
                  },
                  "notes": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 2000
                  },
                  "trust": {
                    "type": "string",
                    "enum": [
                      "untrusted",
                      "suggested",
                      "trusted",
                      "blocked"
                    ]
                  },
                  "rejectReason": {
                    "type": "string",
                    "enum": [
                      "not_event_source",
                      "not_crafting",
                      "wrong_craft",
                      "out_of_area",
                      "duplicate",
                      "date_passed",
                      "site_dead",
                      "wrong_dates",
                      "other"
                    ],
                    "description": "Why you're rejecting it (only with status rejected): not_event_source, not_crafting, wrong_craft, out_of_area, duplicate, date_passed, site_dead, wrong_dates or other (other needs rejectNote). Discovery stops proposing other pages of a site rejected for any but duplicate and date_passed. With trust blocked too, the source's waiting new events are closed"
                  },
                  "rejectNote": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 300,
                    "description": "Your own words on the rejection (only with status rejected)"
                  },
                  "probation": {
                    "type": "string",
                    "enum": [
                      "restart"
                    ],
                    "description": "Keep on probation (WI-336): start a fresh probation, so its events publish with a spot check on each and rejects from before today no longer count. Not with trust"
                  },
                  "home": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "properties": {
                      "venue": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "street": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "city": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 80
                      },
                      "state": {
                        "type": "string",
                        "maxLength": 40
                      },
                      "postal": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "pattern": "^\\d{5}$"
                      }
                    },
                    "required": [
                      "city",
                      "state"
                    ],
                    "description": "The source's own place, or null to clear it (WI-292). Setting it also fills that source's waiting classes and club nights that name no town"
                  },
                  "outreachEmail": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200,
                    "description": "WI-512: a public contact email for this source's organizer, used only to draft invites (reviewed and sent by an admin), never shown on the site; null clears it"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Source"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/sources/{id}/contacts": {
      "get": {
        "summary": "An event source's organizer contact details found on its pages and events (WI-591; admin only, never public)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/OrganizerContact"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/sources/{id}/contacts/{contactId}": {
      "delete": {
        "summary": "Remove one organizer contact detail for good: later reads never bring it back (WI-591)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "contactId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "removed": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "removed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/sources/{id}/first-review": {
      "post": {
        "summary": "Approve a new source's pending events and trust it in one step",
        "description": "Approves each id as a normal admin approval (per-id failures are collected, as in bulk moderation), then trusts the source when at least one approval succeeded and it has no rejection in the last 90 days. Every id must be a new event from this source (not a source check or update), or nothing happens and it's a 400; an id already decided elsewhere is reported in failed as not_pending, one with a blocking gate flag or a likely-duplicate link is reported in failed as needs_review (\"Check this one on its own\"), and the rest still approve.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "approveIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "maxItems": 100,
                    "description": "The source's pending new events to approve (not source checks or updates), 1 to 100"
                  }
                },
                "required": [
                  "approveIds"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FirstReviewResult"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/sources/{id}/run": {
      "post": {
        "summary": "Run ingest now for one source (any status but rejected)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestRun"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/stat-chips": {
      "get": {
        "summary": "Admin stat chips: key numbers with a short history, for the row at the top of /admin (WI-231)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatChips"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions": {
      "get": {
        "summary": "Moderation queue (oldest first)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected"
              ]
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "public",
                "scrape",
                "organizer"
              ]
            },
            "required": false,
            "name": "origin",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "missing_end_date",
                "state_unclear",
                "low_confidence",
                "far_future",
                "geocode_failed",
                "town_unknown",
                "timezone_guess",
                "address_elsewhere",
                "date_inferred",
                "date_suspect",
                "possible_duplicate",
                "possible_update",
                "missing_from_source",
                "dead_link",
                "online_no_link",
                "host_abroad",
                "timezone_unknown",
                "quality_check"
              ]
            },
            "required": false,
            "name": "flag",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": false,
            "name": "sourceId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{2,40}$"
            },
            "required": false,
            "name": "craftType",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "required": false,
            "name": "clean",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "created",
                "gate"
              ]
            },
            "required": false,
            "name": "sort",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "queue",
                "spot-check"
              ]
            },
            "required": false,
            "name": "view",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Submission"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/bulk": {
      "post": {
        "summary": "Approve or reject up to 100 submissions",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "approve",
                      "reject"
                    ]
                  },
                  "ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "maxItems": 100
                  },
                  "reasons": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "not_event",
                        "not_crafting",
                        "wrong_date",
                        "wrong_place",
                        "duplicate",
                        "other"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 6
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "required": [
                  "action",
                  "ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "failed": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "code",
                          "message"
                        ]
                      }
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        },
                        "required": [
                          "id",
                          "warnings"
                        ]
                      },
                      "description": "Approvals that published with a warning (a likely duplicate or a suspect date)"
                    }
                  },
                  "required": [
                    "ok",
                    "failed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}": {
      "get": {
        "summary": "Submission with its duplicate/update target and field diff",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "submission": {
                      "$ref": "#/components/schemas/Submission"
                    },
                    "target": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/AdminEvent"
                        },
                        {
                          "type": [
                            "object",
                            "null"
                          ]
                        }
                      ]
                    },
                    "diff": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "field": {
                            "type": "string"
                          },
                          "before": {},
                          "after": {}
                        },
                        "required": [
                          "field"
                        ]
                      }
                    },
                    "suggestedSeries": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "name"
                      ]
                    }
                  },
                  "required": [
                    "submission",
                    "target",
                    "diff",
                    "suggestedSeries"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Edit a pending submission",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "description": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 5000
                  },
                  "summary": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 280
                  },
                  "start_date": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 10
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 10
                  },
                  "start_time": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 8
                  },
                  "end_time": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 8
                  },
                  "timezone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 64
                  },
                  "recurrence": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "city": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  },
                  "state": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 40
                  },
                  "venue": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "location_kind": {
                    "type": "string",
                    "enum": [
                      "venue",
                      "online",
                      "hybrid",
                      "multi"
                    ]
                  },
                  "languages": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 40
                    },
                    "maxItems": 5
                  },
                  "hosted_by": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120
                  },
                  "street_address": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "postal_code": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^\\d{5}$"
                  },
                  "signup_note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "join_platform": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "zoom",
                      "meet",
                      "teams",
                      "webex",
                      "facebook",
                      "youtube",
                      "other",
                      null
                    ]
                  },
                  "join_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  },
                  "join_meeting_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "join_passcode": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "join_phone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "contact_name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120
                  },
                  "contact_email": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "contact_phone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "craft_types": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "event_type": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 40
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^https?:\\/\\//i"
                  },
                  "organizer_name": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "price_note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  },
                  "is_free": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Submission"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/approve": {
      "post": {
        "summary": "Publish a submission (or apply its update)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "edits": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "description": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 5000
                      },
                      "summary": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 280
                      },
                      "start_date": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 10
                      },
                      "end_date": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 10
                      },
                      "start_time": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 8
                      },
                      "end_time": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 8
                      },
                      "timezone": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 64
                      },
                      "recurrence": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "city": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 100
                      },
                      "state": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 40
                      },
                      "venue": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "location_kind": {
                        "type": "string",
                        "enum": [
                          "venue",
                          "online",
                          "hybrid",
                          "multi"
                        ]
                      },
                      "languages": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 40
                        },
                        "maxItems": 5
                      },
                      "hosted_by": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 120
                      },
                      "street_address": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "postal_code": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "pattern": "^\\d{5}$"
                      },
                      "signup_note": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "join_platform": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "enum": [
                          "zoom",
                          "meet",
                          "teams",
                          "webex",
                          "facebook",
                          "youtube",
                          "other",
                          null
                        ]
                      },
                      "join_url": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 500
                      },
                      "join_meeting_id": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "join_passcode": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "join_phone": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "contact_name": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 120
                      },
                      "contact_email": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "contact_phone": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "craft_types": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 60
                        },
                        "maxItems": 20
                      },
                      "event_type": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "tags": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 60
                        },
                        "maxItems": 20
                      },
                      "url": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "pattern": "^https?:\\/\\//i"
                      },
                      "organizer_name": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "price_note": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "is_free": {
                        "type": [
                          "boolean",
                          "null"
                        ]
                      }
                    }
                  },
                  "seriesId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eventId": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "action": {
                      "type": "string",
                      "enum": [
                        "created",
                        "updated"
                      ]
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Shown to the admin after an approval that published despite a likely duplicate or a suspect date"
                    },
                    "issues": {
                      "type": "array",
                      "items": {
                        "oneOf": [
                          {
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "duplicate"
                                ]
                              },
                              "slug": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "title": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              }
                            },
                            "required": [
                              "kind",
                              "slug",
                              "title"
                            ]
                          },
                          {
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "date"
                                ]
                              },
                              "reasons": {
                                "type": "array",
                                "items": {
                                  "type": "string",
                                  "enum": [
                                    "beyond_year",
                                    "name_year",
                                    "name_month"
                                  ]
                                }
                              }
                            },
                            "required": [
                              "kind",
                              "reasons"
                            ]
                          },
                          {
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "check_failed"
                                ]
                              }
                            },
                            "required": [
                              "kind"
                            ]
                          }
                        ]
                      },
                      "description": "The same warnings as data: the likely duplicate's slug and title, the date's reasons, or a check that couldn't run"
                    }
                  },
                  "required": [
                    "eventId",
                    "slug",
                    "action"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/approve-and-trust": {
      "post": {
        "summary": "Approve a submission and trust the person who added it",
        "description": "Approves exactly as POST /api/admin/submissions/{id}/approve does, then sets the submitter's suggestion trust to trusted (audited user.suggestion_trust), so their later events publish without waiting. 400 when the submission has no signed-in submitter; a failed approval changes nothing (its usual 404 or 409). When the approval succeeds but the trust change fails, the answer is still 200, with trusted false and a warning.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "edits": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "description": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 5000
                      },
                      "summary": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 280
                      },
                      "start_date": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 10
                      },
                      "end_date": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 10
                      },
                      "start_time": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 8
                      },
                      "end_time": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 8
                      },
                      "timezone": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 64
                      },
                      "recurrence": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "city": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 100
                      },
                      "state": {
                        "type": "string",
                        "minLength": 2,
                        "maxLength": 40
                      },
                      "venue": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "location_kind": {
                        "type": "string",
                        "enum": [
                          "venue",
                          "online",
                          "hybrid",
                          "multi"
                        ]
                      },
                      "languages": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 40
                        },
                        "maxItems": 5
                      },
                      "hosted_by": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 120
                      },
                      "street_address": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "postal_code": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "pattern": "^\\d{5}$"
                      },
                      "signup_note": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "join_platform": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "enum": [
                          "zoom",
                          "meet",
                          "teams",
                          "webex",
                          "facebook",
                          "youtube",
                          "other",
                          null
                        ]
                      },
                      "join_url": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 500
                      },
                      "join_meeting_id": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "join_passcode": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "join_phone": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "contact_name": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 120
                      },
                      "contact_email": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "contact_phone": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "craft_types": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 60
                        },
                        "maxItems": 20
                      },
                      "event_type": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 40
                      },
                      "tags": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 60
                        },
                        "maxItems": 20
                      },
                      "url": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "pattern": "^https?:\\/\\//i"
                      },
                      "organizer_name": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "price_note": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "maxLength": 200
                      },
                      "is_free": {
                        "type": [
                          "boolean",
                          "null"
                        ]
                      }
                    }
                  },
                  "seriesId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eventId": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "action": {
                      "type": "string",
                      "enum": [
                        "created",
                        "updated"
                      ]
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Shown to the admin after an approval that published despite a likely duplicate or a suspect date"
                    },
                    "issues": {
                      "type": "array",
                      "items": {
                        "oneOf": [
                          {
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "duplicate"
                                ]
                              },
                              "slug": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "title": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              }
                            },
                            "required": [
                              "kind",
                              "slug",
                              "title"
                            ]
                          },
                          {
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "date"
                                ]
                              },
                              "reasons": {
                                "type": "array",
                                "items": {
                                  "type": "string",
                                  "enum": [
                                    "beyond_year",
                                    "name_year",
                                    "name_month"
                                  ]
                                }
                              }
                            },
                            "required": [
                              "kind",
                              "reasons"
                            ]
                          },
                          {
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "check_failed"
                                ]
                              }
                            },
                            "required": [
                              "kind"
                            ]
                          }
                        ]
                      },
                      "description": "The same warnings as data: the likely duplicate's slug and title, the date's reasons, or a check that couldn't run"
                    },
                    "userId": {
                      "type": "string",
                      "description": "The submitter now trusted"
                    },
                    "trusted": {
                      "type": "boolean",
                      "description": "False when the approval went through but the trust change failed"
                    },
                    "warning": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "eventId",
                    "slug",
                    "action",
                    "userId",
                    "trusted"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/make-owner": {
      "post": {
        "summary": "Make an organizer the owner of the event their submission duplicates",
        "description": "For a pending organizer submission that duplicates an existing event: rejects the submission (not counted against the organizer), makes its submitter the existing event's owner and records an approved claim for them. Never approves the submission. 400 when the submission isn't a pending organizer submission with a duplicate link or the event isn't published; 409 when it was decided meanwhile or someone else already manages the event (they have to be asked through a claim).",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eventId": {
                      "type": "string",
                      "description": "The existing event the organizer now owns"
                    }
                  },
                  "required": [
                    "eventId"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/merge": {
      "post": {
        "summary": "Merge a submission into an existing event",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eventId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "required": [
                  "eventId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eventId": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "eventId"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/reject": {
      "post": {
        "summary": "Reject a submission",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reasons": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "not_event",
                        "not_crafting",
                        "wrong_date",
                        "wrong_place",
                        "duplicate",
                        "other"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 6
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "required": [
                  "reasons"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/reopen": {
      "post": {
        "summary": "Reopen a submission the stale-close fixer closed",
        "description": "Puts a queue item the nightly stale-close fixer rejected (its date had passed before anyone reviewed it) back to pending, for the /admin/daily data-fixes list's Undo. 404 for an unknown id; 409 when it wasn't closed that way, or when a newer submission with the same dedupe key is already pending.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/reject-verdict": {
      "post": {
        "summary": "Agree with or overturn a reject that counts against its source",
        "description": "For the Lost trust card (WI-336). agree records that the reject stands. overturn stops it counting against the source: an event still ahead goes back to the queue, anything else is marked overturned; a judge reject is logged as a judge miss; and when no counted reject is left, the source gets back the trust it lost automatically. 404 for an unknown id; 409 when the reject no longer counts; 503 for overturn before migration 050.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "verdict": {
                    "type": "string",
                    "enum": [
                      "agree",
                      "overturn"
                    ],
                    "description": "agree keeps the reject; overturn says it wasn't the source's fault"
                  }
                },
                "required": [
                  "verdict"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verdict": {
                      "type": "string",
                      "enum": [
                        "agree",
                        "overturn"
                      ]
                    },
                    "reopened": {
                      "type": "boolean",
                      "description": "Overturned and back in the queue, since the event is still ahead"
                    },
                    "trustRestored": {
                      "type": "boolean",
                      "description": "No counted reject was left, so the source got back the trust it lost"
                    },
                    "message": {
                      "type": "string",
                      "description": "One plain sentence on what happened"
                    }
                  },
                  "required": [
                    "verdict",
                    "reopened",
                    "trustRestored",
                    "message"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/resolve-check": {
      "post": {
        "summary": "Resolve a source or quality check item: keep (on a quality card optionally with eventEdits, fixes to the event), hide or cancel the event",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "keep",
                      "hide",
                      "cancel"
                    ]
                  },
                  "eventEdits": {
                    "type": "object",
                    "properties": {
                      "start_date": {
                        "type": "string"
                      },
                      "end_date": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "start_time": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "end_time": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "city": {
                        "type": "string"
                      }
                    },
                    "description": "With keep, on a nightly quality card only: fixes to the event (start_date, end_date, start_time, end_time, city)"
                  }
                },
                "required": [
                  "action"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eventId": {
                      "type": "string"
                    },
                    "action": {
                      "type": "string",
                      "enum": [
                        "keep",
                        "hide",
                        "cancel"
                      ]
                    }
                  },
                  "required": [
                    "eventId",
                    "action"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/submissions/{id}/spot-check": {
      "post": {
        "summary": "Record a spot check of an auto-published event",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "result": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "rejected",
                      "edited"
                    ]
                  },
                  "reasons": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "not_event",
                        "not_crafting",
                        "wrong_date",
                        "wrong_place",
                        "duplicate",
                        "other"
                      ]
                    },
                    "minItems": 1,
                    "maxItems": 6
                  }
                },
                "required": [
                  "result"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/taxonomy/{kind}": {
      "get": {
        "summary": "List a taxonomy (optionally including inactive)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "craft_types",
                "event_types",
                "tags"
              ]
            },
            "required": true,
            "name": "kind",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "required": false,
            "name": "includeInactive",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TaxonomyEntry"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Add a taxonomy entry",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "craft_types",
                "event_types",
                "tags"
              ]
            },
            "required": true,
            "name": "kind",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "slug": {
                    "type": "string",
                    "pattern": "^[a-z0-9-]{2,40}$"
                  },
                  "label": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "description": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  },
                  "parentSlug": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^[a-z0-9-]{2,40}$"
                  },
                  "sortOrder": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10000
                  }
                },
                "required": [
                  "slug",
                  "label"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxonomyEntry"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/taxonomy/{kind}/{slug}": {
      "patch": {
        "summary": "Edit or deactivate a taxonomy entry",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "craft_types",
                "event_types",
                "tags"
              ]
            },
            "required": true,
            "name": "kind",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{2,40}$"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "description": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  },
                  "parentSlug": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "pattern": "^[a-z0-9-]{2,40}$"
                  },
                  "sortOrder": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10000
                  },
                  "active": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxonomyEntry"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/tenants": {
      "get": {
        "summary": "List sites (tenants)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Tenant"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a site (tenant)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "hosts": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^(localhost(:\\d+)?|[a-z0-9-]+(\\.[a-z0-9-]+)+)$"
                    },
                    "minItems": 1,
                    "maxItems": 10
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "tagline": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120,
                    "default": null
                  },
                  "accentHex": {
                    "type": "string",
                    "pattern": "^#[0-9a-fA-F]{6}$",
                    "default": "#ca5321"
                  },
                  "allowAll": {
                    "type": "boolean",
                    "default": false
                  },
                  "allowedCraftTypes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 50
                    },
                    "maxItems": 50,
                    "default": []
                  },
                  "owningCraftTypes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 50
                    },
                    "maxItems": 50,
                    "default": []
                  },
                  "canonicalPriority": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10000,
                    "default": 100
                  },
                  "imageStylePrompt": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 2000,
                    "default": null
                  },
                  "slug": {
                    "type": "string",
                    "pattern": "^[a-z0-9-]{2,40}$"
                  }
                },
                "required": [
                  "hosts",
                  "name",
                  "slug"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/tenants/{slug}": {
      "get": {
        "summary": "Get a site (tenant)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update a site (tenant)",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "hosts": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^(localhost(:\\d+)?|[a-z0-9-]+(\\.[a-z0-9-]+)+)$"
                    },
                    "minItems": 1,
                    "maxItems": 10
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "tagline": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 120
                  },
                  "accentHex": {
                    "type": "string",
                    "pattern": "^#[0-9a-fA-F]{6}$"
                  },
                  "allowAll": {
                    "type": "boolean"
                  },
                  "allowedCraftTypes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 50
                    },
                    "maxItems": 50
                  },
                  "owningCraftTypes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 50
                    },
                    "maxItems": 50
                  },
                  "canonicalPriority": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10000
                  },
                  "imageStylePrompt": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 2000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/organizers": {
      "get": {
        "summary": "List organizers and the events they manage",
        "description": "Every organizer (role organizer, or anyone who owns an event or has an approved claim), 50 a page: the events they manage (upcoming, total and the next one), their added events waiting for review, their claims, trust, how they joined and when they were last active. Anyone with events waiting comes first, then the most recently active. `filter` is all, waiting, trusted or invite (joined through an invite); `q` searches name and email.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "waiting",
                "trusted",
                "invite"
              ]
            },
            "required": false,
            "name": "filter",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminOrganizerPage"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/users": {
      "get": {
        "summary": "List users",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "user",
                "organizer",
                "admin"
              ]
            },
            "required": false,
            "name": "role",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            },
            "required": false,
            "name": "suspended",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdminUser"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/users/{id}": {
      "get": {
        "summary": "Get a user, their profile card, at-a-glance counts, the events they manage, their claims, recent edits and added events waiting",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminUserDetail"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Change role, suspend or unsuspend, sign out everywhere, or set suggestion trust",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "user",
                      "organizer",
                      "admin"
                    ]
                  },
                  "isSuspended": {
                    "type": "boolean"
                  },
                  "signOutEverywhere": {
                    "type": "boolean"
                  },
                  "suggestionTrust": {
                    "type": "string",
                    "enum": [
                      "untrusted",
                      "trusted",
                      "blocked"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminUser"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/users/{id}/activity": {
      "get": {
        "summary": "The admin user page's activity timeline",
        "description": "Every kind of activity (signed in, saved, added or suggested, claimed, organizer edits, pictures, profile changes, emails sent and what an admin or the system did to the account) merged newest first, 25 a page. partial is true when at least one kind failed to load this page; a stale or malformed cursor falls back to page one.",
        "tags": [
          "admin"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserActivityPage"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/appearance": {
      "get": {
        "summary": "This site's look: its theme and the season showing today",
        "tags": [
          "platform"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appearance"
                }
              }
            }
          }
        }
      }
    },
    "/api/location/guess": {
      "get": {
        "summary": "A guess at the caller's town from their connection, shown as a suggestion only (never stored)",
        "tags": [
          "platform"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "label": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The caller's town as their connection suggests (\"Seattle, WA\"), or null outside the US or when unknown"
                    }
                  },
                  "required": [
                    "label"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "summary": "Email a magic sign-in link",
        "description": "Always returns ok for a valid email, whether or not an account exists.",
        "tags": [
          "auth"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "format": "email"
                  },
                  "redirectTo": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "website": {
                    "type": "string"
                  },
                  "turnstileToken": {
                    "type": "string"
                  }
                },
                "required": [
                  "email"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "429 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "summary": "End the browser session",
        "tags": [
          "auth"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "summary": "Who am I",
        "description": "The caller's kind and scope, its account, and the account's header profile (display name and picture).",
        "tags": [
          "auth"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/verify": {
      "post": {
        "summary": "Exchange a magic-link token for a session cookie",
        "description": "Single use. The emailed link opens /auth/verify, which calls this so link scanners cannot burn the token.",
        "tags": [
          "auth"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "token": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 200
                  }
                },
                "required": [
                  "token"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "redirectTo": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "redirectTo"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/verify-code": {
      "post": {
        "summary": "Exchange the emailed 6-digit sign-in code for a session cookie",
        "description": "Checks the code from the newest sign-in email for this address. Five wrong codes use it up. Every failure answers the same 400, whether or not the email has an account. A correct code also uses up the email's link.",
        "tags": [
          "auth"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "maxLength": 254,
                    "format": "email"
                  },
                  "code": {
                    "type": "string",
                    "maxLength": 20
                  },
                  "redirectTo": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "required": [
                  "email",
                  "code"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "redirectTo": {
                      "type": "string"
                    },
                    "firstSignIn": {
                      "type": "boolean",
                      "description": "True the moment this account's very first sign-in happened. The save panel's in-place sign-in has no page load of its own to carry welcome=1, so it reads this instead to open the \"Make it yours\" panel."
                    }
                  },
                  "required": [
                    "redirectTo",
                    "firstSignIn"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "description": "429 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events": {
      "get": {
        "summary": "Search upcoming crafting events on this site",
        "description": "Published, upcoming events with their next date in the window. Filters: q (full text with typo tolerance), craft/type/tag (comma lists of taxonomy slugs; a top-level craft also matches its child crafts, so needlework includes cross-stitch), state, when (weekend|next7|next30|next90|month:YYYY-MM) or from+to, near (a US place as 'City, ST', e.g. 'Columbus, OH', or 'all') or lat+lng, radius (25|50|100|250|any, default 100 with a location), free=1, online=1 (only online events; other values are ignored), inperson=1 (only in-person events, including multi-location; other values are ignored; online=1 and inperson=1 together cancel out to no format filter, rather than matching nothing), sort (date|distance|relevance; default best match for q, else soonest first; distance needs a location, and without one falls back to that default), tz (IANA, for date presets). Invalid filter values are ignored, except a near that matches no US place, which is a 400 validation_failed. With no state, near or lat+lng, a trailing US place in q, like 'quilt show Arizona' or 'Phoenix, AZ', sets the location: a state name or capitalized code becomes state and 'City, ST' becomes near (radius 50 unless given; a city that matches no place is retried on its last 2 words, then its last word, then falls back to its state), and the place is removed from the text query. Location is never inferred from the caller's IP. `featured` holds up to 3 featured events matching the same search; they are excluded from `items` on every page. featured=0 turns that off: no featured lookup, `featured` is empty and `items` leaves nothing out (for a client that shows its own results without a featured row).",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 400
            },
            "required": false,
            "name": "craft",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "type",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 400
            },
            "required": false,
            "name": "tag",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "required": false,
            "name": "state",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "when",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "required": false,
            "name": "near",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "lat",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "lng",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 5
            },
            "required": false,
            "name": "radius",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 1
            },
            "required": false,
            "name": "free",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "online",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "inperson",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "sort",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "required": false,
            "name": "tz",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10,
              "description": "0 skips the featured row: `featured` comes back empty and nothing is left out of `items`. Any other value is ignored."
            },
            "required": false,
            "description": "0 skips the featured row: `featured` comes back empty and nothing is left out of `items`. Any other value is ignored.",
            "name": "featured",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSearchItem"
                      }
                    },
                    "featured": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSearchItem"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "total": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "items",
                    "featured",
                    "nextCursor",
                    "total"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/counts": {
      "get": {
        "summary": "Count upcoming events per state",
        "description": "Upcoming published events in the next 12 months, grouped by US state, with each state's most common craft. `by` must be `state`.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "state"
              ]
            },
            "required": true,
            "name": "by",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StateCount"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/counts/crafts": {
      "get": {
        "summary": "Count matching events per craft",
        "description": "How many events match a search, per top-level craft, for the 'Jump to a craft' chips. Takes the same filters as GET /api/events (q, type, tag, state, when or from+to, near or lat+lng, radius, free, online, inperson, tz) and counts with every one of them except craft, which is accepted and ignored, so each craft keeps its number while one is chosen. Child crafts count toward their top-level parent (needlepoint, cross-stitch and embroidery count as needlework), and an event counts once per top-level craft, so the crafts can add up to more than `total`, the distinct number of matching events. A craft's count equals the total GET /api/events reports for that craft=<slug>, with one known exception: with a text query (q), the typo-tolerant fallback applies only when a search has no exact text match, so it can apply to the all-crafts count but not to one craft's search (or the other way round) and the numbers can then differ. Only crafts with at least one match are listed, most first, then in taxonomy order. Location is never inferred from the caller's IP; a near that matches no US place is a 400. Answers 503 not_configured while the counts aren't available.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 400
            },
            "required": false,
            "name": "craft",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "type",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 400
            },
            "required": false,
            "name": "tag",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "required": false,
            "name": "state",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "when",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "required": false,
            "name": "near",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "lat",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "lng",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 5
            },
            "required": false,
            "name": "radius",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 1
            },
            "required": false,
            "name": "free",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "online",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "inperson",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "sort",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "required": false,
            "name": "tz",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "crafts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CraftCount"
                      }
                    }
                  },
                  "required": [
                    "total",
                    "crafts"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/online-band": {
      "get": {
        "summary": "Online event picks to show beside a local search",
        "description": "The Online events band for a local search (a place with a distance, or a state): at most 3 online events anywhere that match the search's words, crafts, types, tags, price and dates, filled from other crafts only when short, each part ranked with a start in the viewer's small hours (10 pm to 7 am in tz) after the rest, then soonest, and the caller's Accept-Language first. Takes the same filters as GET /api/events. `total` and `href` are 'See all online events (N)': /online with the search's top-level crafts and Free only, counted over its next 30 days (the crafts dropped when none has an online event); `matched` is how many picks matched the search's own crafts; `crafts` the search's top-level crafts. Location is never inferred from the caller's IP; a near that matches no US place is a 400.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 400
            },
            "required": false,
            "name": "craft",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": false,
            "name": "type",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 400
            },
            "required": false,
            "name": "tag",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "required": false,
            "name": "state",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "when",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "from",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "to",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "required": false,
            "name": "near",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "lat",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20
            },
            "required": false,
            "name": "lng",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 5
            },
            "required": false,
            "name": "radius",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 1
            },
            "required": false,
            "name": "free",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "online",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "inperson",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10
            },
            "required": false,
            "name": "sort",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "required": false,
            "name": "tz",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSearchItem"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "href": {
                      "type": "string"
                    },
                    "matched": {
                      "type": "integer"
                    },
                    "crafts": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "items",
                    "total",
                    "href",
                    "matched",
                    "crafts"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}": {
      "get": {
        "summary": "Get one event by slug",
        "description": "One published event with its upcoming dates and its organizer's pictures (`images`, the first is the cover). `owned` says whether an organizer manages it, and `managedBy` names that organizer (their public page's slug, name and picture) when their profile is public. A former slug (the event was renamed when its year or town changed) answers the same event, under its current `slug`. A cancelled event whose dates aren't over yet also answers, with `cancelled` true and no upcoming dates; `scheduleChange` says when a published event is postponed, rescheduled (with `previousStartDate`) or moved online.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventDetail"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/calendar.ics": {
      "get": {
        "summary": "Download the event's next date as an .ics calendar file (STATUS:CANCELLED for a cancelled event not yet over)",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "text/calendar": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/claim": {
      "post": {
        "summary": "Claim an event to manage it",
        "description": "Asks to manage a published event. When the account's email is the event's own contact or organizer email, or is at the event website's own domain, and nobody manages the event yet, the claim is approved at once. Otherwise it waits for an admin and `note` (how you're connected to the event, up to 500 characters) is required; at most 5 claims can wait at a time. Claiming an event you already manage returns your approved claim. A hidden, cancelled, out-of-scope or unknown slug 404s.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "note": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClaimResult"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "409 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/contact": {
      "get": {
        "summary": "Get an event's organizer contact",
        "description": "The contact name, email and phone the organizer published for this event, exactly as they wrote them. 404s when the event has neither a name nor an email/phone. Rate-limited more strictly than other reads (the detail limit), and answers with Cache-Control: no-store and X-Robots-Tag: noindex.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventContact"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/corrections": {
      "post": {
        "summary": "Report an issue with an event listing",
        "description": "Anyone can flag an event as wrong, gone, cancelled, postponed or moved to a new date (rescheduled, with `newStartDate`); an admin reviews every request, none is applied on its own. Browser forms pass Turnstile; programmatic callers send an API key instead.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 120
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "correct",
                      "remove",
                      "cancelled",
                      "postponed",
                      "rescheduled"
                    ],
                    "description": "postponed: new date to come; rescheduled: it has a new date (give it as newStartDate)"
                  },
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "contactEmail": {
                    "type": "string",
                    "maxLength": 254,
                    "format": "email"
                  },
                  "newStartDate": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "For a rescheduled request: the event's new start date"
                  },
                  "website": {
                    "type": "string"
                  },
                  "turnstileToken": {
                    "type": "string"
                  }
                },
                "required": [
                  "kind",
                  "message"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "message"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/join": {
      "get": {
        "summary": "Get an online event's join details",
        "description": "The link, meeting ID, passcode and phone the organizer published for joining online, exactly as they wrote them. Shown only from 30 minutes before the start of the event's next occurrence until it ends: outside that window it answers 403 forbidden with a message saying when the details appear (details.opensAt, an ISO time, when known). 404s when the event has none of these. Rate-limited more strictly than other reads (the detail limit), and answers with Cache-Control: no-store and X-Robots-Tag: noindex.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JoinDetails"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/save": {
      "put": {
        "summary": "Save an event",
        "description": "Saves a published event the current tenant allows to the signed-in account. A hidden, cancelled, out-of-scope or unknown slug 404s. Saving twice answers the same 200.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaveResult"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Unsave an event",
        "description": "Removes an event from the signed-in account's saved list. Deleting twice is a no-op 200.",
        "tags": [
          "account"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaveResult"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/similar": {
      "get": {
        "summary": "Events like this one",
        "description": "Up to 4 upcoming events like this one (\"More like this\" on the event page), never including the event itself: the same top-level crafts (a craft's child crafts included), or the same event type when the event has no craft; within 100 miles of the event, nearest first (250 miles when that finds fewer than 2); other online events anywhere, soonest first, for an online event; the event's state, soonest first, for an in-person event without a map point; over the next 90 days. An event with neither a craft nor a type gets an empty list. A hidden, cancelled or unknown slug is a 404.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSearchItem"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/events/{slug}/not-listed": {
      "get": {
        "summary": "A withdrawn event's title and status, with events like it",
        "description": "For the address of an event this site no longer lists (hidden, or cancelled and past): its title, whether it was cancelled, and up to 4 upcoming events like it (the same search as /similar). Never its contact, join or owner details. Any other slug (unknown, published, another site's) is a 404. The event page's 404 shows this (WI-094, WI-097).",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "hidden",
                        "cancelled"
                      ],
                      "description": "hidden: no longer listed; cancelled: the organizer called it off"
                    },
                    "title": {
                      "type": "string"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSearchItem"
                      },
                      "description": "Up to 4 upcoming events like it"
                    },
                    "craftLabels": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    },
                    "typeLabels": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "status",
                    "title",
                    "items",
                    "craftLabels",
                    "typeLabels"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "summary": "Service health",
        "tags": [
          "platform"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "service": {
                      "type": "string"
                    },
                    "supabaseConfigured": {
                      "type": "boolean"
                    },
                    "time": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "service",
                    "supabaseConfigured",
                    "time"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/invites/{token}": {
      "get": {
        "summary": "Look up an organizer invite by its link token",
        "description": "The invite's still-published events to claim, and whether the link is open (\"ok\"), already used, expired or unknown. Never reveals the invited address.",
        "tags": [
          "organizers"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "token",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitePage"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/invites/{token}/claim": {
      "post": {
        "summary": "Claim events through an invite link",
        "description": "Signed in with any email - the link itself is the proof, so a forwarded invite works too. Claims a non-empty subset of the invite's own events: an unowned one becomes the caller's; one someone else owns, or one an admin removed them from, waits as a pending claim for an admin; granting anything promotes the caller to organizer and may grant the early-organizer featured perk. 410 once the link has already been used or has expired.",
        "tags": [
          "organizers"
        ],
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "token",
            "in": "path"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eventIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "minItems": 1,
                    "maxItems": 20
                  }
                },
                "required": [
                  "eventIds"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InviteClaimResult"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "410 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "summary": "Model Context Protocol endpoint (Streamable HTTP, JSON responses)",
        "description": "JSON-RPC 2.0. Every API operation is available as a tool. See /docs/mcp.",
        "tags": [
          "mcp"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "202": {
            "description": "202 response"
          }
        }
      }
    },
    "/api/network/v1/event-demand": {
      "get": {
        "summary": "Upcoming event counts by network craft",
        "description": "A daily snapshot (crafting-network/event-demand@1) of how many published events Crafting Event Finder lists in the next 60 days (today to today plus 60, Pacific), per network craft tag from the network manifest, most first then by tag. Each craft gives its label, count (distinct events with a day in the window; a repeating or running event counts once), online (online or hybrid events), earliest (the first day in the window with one) and regions (a count per US state code, with online events as `online`; a hybrid event counts in its state). A child craft rolls up to its parent's tag; an Other crafts event counts under the tags its own words name; craft-fair is never a tag, and an event with no tag is left out. Counts and dates only. The answer never depends on the caller and is recomputed at most once a day.",
        "tags": [
          "network"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schema": {
                      "type": "string",
                      "enum": [
                        "crafting-network/event-demand@1"
                      ]
                    },
                    "generated_on": {
                      "type": "string",
                      "format": "date"
                    },
                    "window": {
                      "type": "object",
                      "properties": {
                        "from": {
                          "type": "string",
                          "format": "date"
                        },
                        "to": {
                          "type": "string",
                          "format": "date"
                        }
                      },
                      "required": [
                        "from",
                        "to"
                      ]
                    },
                    "crafts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "tag": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "count": {
                            "type": "integer",
                            "minimum": 0
                          },
                          "online": {
                            "type": "integer",
                            "minimum": 0
                          },
                          "earliest": {
                            "type": "string",
                            "format": "date"
                          },
                          "regions": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "integer",
                              "minimum": 0
                            }
                          }
                        },
                        "required": [
                          "tag",
                          "label",
                          "count",
                          "online",
                          "earliest",
                          "regions"
                        ]
                      }
                    }
                  },
                  "required": [
                    "schema",
                    "generated_on",
                    "window",
                    "crafts"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "500 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/network/v1/feed": {
      "get": {
        "summary": "Crafting network feed of upcoming events",
        "description": "The crafting network's item feed (contract crafting-network/feed@1) for sister sites: Crafting Event Finder's upcoming published events, soonest first then by id, keyset-paged with an opaque cursor (next_cursor is null on the last page). limit defaults to 50, at most 100. A repeating event shows its next occurrence's dates; upcoming is judged by today's UTC date. The answer never depends on the caller's Host, IP or cookies: every url is on https://craftingeventfinder.com. craft_tags use the network vocabulary from the network manifest; a craft outside it is left out. updated_since is accepted and ignored in v1.",
        "tags": [
          "network"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 500
            },
            "required": false,
            "name": "cursor",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "required": false,
            "name": "updated_since",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schema": {
                      "type": "string",
                      "enum": [
                        "crafting-network/feed@1"
                      ]
                    },
                    "site_id": {
                      "type": "string",
                      "pattern": "^[a-z][a-z0-9_]{1,31}$"
                    },
                    "generated_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "item_id": {
                            "type": "string",
                            "minLength": 1
                          },
                          "kind": {
                            "type": "string",
                            "enum": [
                              "event",
                              "tutorial",
                              "download"
                            ]
                          },
                          "title": {
                            "type": "string",
                            "minLength": 1
                          },
                          "subtitle": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "image_url": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uri"
                          },
                          "craft_tags": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
                            }
                          },
                          "published_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updated_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "access": {
                            "type": "string",
                            "enum": [
                              "free",
                              "members",
                              "paid"
                            ]
                          },
                          "event": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "properties": {
                              "starts_on": {
                                "type": "string",
                                "format": "date"
                              },
                              "ends_on": {
                                "type": "string",
                                "format": "date"
                              },
                              "timezone": {
                                "type": "string",
                                "minLength": 1
                              },
                              "city": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "state": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "online": {
                                "type": "boolean"
                              }
                            },
                            "required": [
                              "starts_on",
                              "ends_on",
                              "timezone",
                              "city",
                              "state",
                              "online"
                            ]
                          },
                          "tutorial": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "properties": {
                              "difficulty": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "enum": [
                                  "easy",
                                  "medium",
                                  "advanced",
                                  null
                                ]
                              },
                              "duration_minutes": {
                                "type": [
                                  "integer",
                                  "null"
                                ],
                                "exclusiveMinimum": 0
                              }
                            },
                            "required": [
                              "difficulty",
                              "duration_minutes"
                            ]
                          }
                        },
                        "required": [
                          "item_id",
                          "kind",
                          "title",
                          "subtitle",
                          "url",
                          "image_url",
                          "craft_tags",
                          "published_at",
                          "updated_at",
                          "access",
                          "event",
                          "tutorial"
                        ]
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "minLength": 1
                    }
                  },
                  "required": [
                    "schema",
                    "site_id",
                    "generated_at",
                    "items",
                    "next_cursor"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/network/v1/stat-chips": {
      "get": {
        "summary": "This site's admin stat chips, for Switchboard",
        "description": "The stat chips Crafting Event Finder's own /admin shows (crafting-network/site-chips@1), computed fresh per request from the same source, so the numbers match /admin. Needs the site's network key as `Authorization: Bearer <key>` (not an account API key): no key or a wrong one is 401, a server without a key is 503. A chip with no value is left out; numbers carry `value` and `value_text`, and Last run carries `value: null` with `value_text` \"published / queued\" counts. Read-only, never cached.",
        "tags": [
          "network"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schema": {
                      "type": "string",
                      "enum": [
                        "crafting-network/site-chips@1"
                      ]
                    },
                    "site_id": {
                      "type": "string",
                      "pattern": "^[a-z][a-z0-9_]{1,31}$"
                    },
                    "generated_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "chips": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "maxLength": 64,
                            "pattern": "^[a-z0-9]+(?:[_-][a-z0-9]+)*$"
                          },
                          "label": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 60,
                            "pattern": "\\S"
                          },
                          "value": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "value_text": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 24,
                            "pattern": "\\S"
                          },
                          "caption": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "minLength": 1,
                            "maxLength": 40,
                            "pattern": "\\S"
                          },
                          "sr_value": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "minLength": 1,
                            "maxLength": 200,
                            "pattern": "\\S"
                          },
                          "change": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "properties": {
                              "direction": {
                                "type": "string",
                                "enum": [
                                  "up",
                                  "down",
                                  "flat"
                                ]
                              },
                              "text": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 80,
                                "pattern": "\\S"
                              }
                            },
                            "required": [
                              "direction",
                              "text"
                            ]
                          },
                          "series": {
                            "type": [
                              "array",
                              "null"
                            ],
                            "items": {
                              "type": "number"
                            },
                            "maxItems": 30
                          },
                          "admin_url": {
                            "type": "string",
                            "format": "uri"
                          }
                        },
                        "required": [
                          "id",
                          "label",
                          "value",
                          "value_text",
                          "admin_url"
                        ]
                      },
                      "maxItems": 40
                    }
                  },
                  "required": [
                    "schema",
                    "site_id",
                    "generated_at",
                    "chips"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "401 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/online-events": {
      "get": {
        "summary": "Online events, by day in the viewer's time zone",
        "description": "The /online page: every published online or hybrid event whose next date falls in the next 30 days (from today in tz), filtered by craft, time of day (tod), day, free and language (lang), all judged in the viewer's zone (tz), and grouped by the viewer's own start date. At most 200 events are read; `truncated` says more exist. Time of day and day are worked out per event from its own start time and zone, which is why they live here and not on GET /api/events (online=1 there lists online events by their own dates, paged).",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "maxLength": 500,
              "description": "Comma list of top-level craft slugs (any of); unknown slugs are ignored."
            },
            "required": false,
            "description": "Comma list of top-level craft slugs (any of); unknown slugs are ignored.",
            "name": "craft",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 100,
              "description": "Comma list of morning (5 am to noon), afternoon (noon to 5 pm), evening (5 pm to 5 am), judged in tz; an event with no start time never matches one."
            },
            "required": false,
            "description": "Comma list of morning (5 am to noon), afternoon (noon to 5 pm), evening (5 pm to 5 am), judged in tz; an event with no start time never matches one.",
            "name": "tod",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 20,
              "description": "today, week (the next 7 days) or weekend (this or the coming Fri to Sun), in tz."
            },
            "required": false,
            "description": "today, week (the next 7 days) or weekend (this or the coming Fri to Sun), in tz.",
            "name": "day",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 5,
              "description": "1 for free events only."
            },
            "required": false,
            "description": "1 for free events only.",
            "name": "free",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 10,
              "description": "One language code (en, es): only events known to be held in it. Without it every language shows, the caller's Accept-Language ranked first within each day."
            },
            "required": false,
            "description": "One language code (en, es): only events known to be held in it. Without it every language shows, the caller's Accept-Language ranked first within each day.",
            "name": "lang",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 64,
              "description": "The viewer's IANA time zone; days and times of day are judged in it. Default America/New_York."
            },
            "required": false,
            "description": "The viewer's IANA time zone; days and times of day are judged in it. Default America/New_York.",
            "name": "tz",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "timeZone": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "truncated": {
                      "type": "boolean"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EventSearchItem"
                      }
                    },
                    "groups": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": {
                            "type": "string",
                            "description": "The viewer's own date (YYYY-MM-DD in tz) the events in this group start on"
                          },
                          "label": {
                            "type": "string",
                            "description": "'Friday, October 16'"
                          },
                          "slugs": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "The group's events, soonest first, by slug (each is in items)"
                          }
                        },
                        "required": [
                          "date",
                          "label",
                          "slugs"
                        ]
                      }
                    }
                  },
                  "required": [
                    "timeZone",
                    "total",
                    "truncated",
                    "items",
                    "groups"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/organizers/{slug}": {
      "get": {
        "summary": "Get an organizer's public page",
        "description": "An organizer's public profile (name, About, website, town and state, crafts and picture) with their published events on this site: upcoming soonest first (at most 50), then the newest 12 past. Only organizers with a display name have a public page; anyone else is 404.",
        "tags": [
          "organizers"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOrganizer"
                }
              }
            }
          },
          "404": {
            "description": "404 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/places": {
      "get": {
        "summary": "Look up US places by name (for location search)",
        "description": "Prefix match on US Census places. Accepts 'City' or 'City, ST'. Returns up to 8, largest first.",
        "tags": [
          "events"
        ],
        "security": [],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 60
            },
            "required": true,
            "name": "q",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Place"
                      }
                    }
                  },
                  "required": [
                    "items"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/preferences": {
      "get": {
        "summary": "Get my effective search preferences",
        "description": "The account's preferences when signed in, otherwise the cef_prefs cookie's, otherwise smart defaults.",
        "tags": [
          "preferences"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreferencesState"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Save my search preferences",
        "description": "Sets the cef_prefs cookie for everyone, and syncs to the account when signed in.",
        "tags": [
          "preferences"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Preferences"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreferencesResult"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Change some of my search preferences",
        "description": "Any subset of the preference fields (for example { \"showOnline\": false }, the 'Show online events' switch), laid over the caller's current preferences (the account's when signed in, else the cef_prefs cookie's, else the defaults). Sets the cookie for everyone and syncs to the account when signed in, like PUT.",
        "tags": [
          "preferences"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreferencesPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreferencesResult"
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Reset my search preferences to defaults",
        "description": "Clears the cef_prefs cookie, and the account copy when signed in.",
        "tags": [
          "preferences"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreferencesResult"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/submissions": {
      "post": {
        "summary": "Submit an event for review",
        "description": "Goes to the moderation queue. Browser forms pass Turnstile; programmatic callers send an API key instead. A signed-in caller (session or user-scope key) skips Turnstile, is recorded as the submitter, may omit organizer_email (the account email is used), and a trusted submitter's event can publish straight away when auto-approval is on. Anonymous callers must send organizer_email.",
        "tags": [
          "submissions"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "start_date": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  "end_date": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                      },
                      {
                        "type": "string",
                        "enum": [
                          ""
                        ]
                      }
                    ]
                  },
                  "city": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "The town; required unless location_kind is online"
                  },
                  "state": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "A US state name or two-letter code; required unless location_kind is online (then taken from the time zone)"
                  },
                  "venue": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "street_address": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "postal_code": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^\\d{5}$"
                      },
                      {
                        "type": "string",
                        "enum": [
                          ""
                        ]
                      }
                    ]
                  },
                  "location_kind": {
                    "type": "string",
                    "enum": [
                      "venue",
                      "online",
                      "hybrid",
                      "multi"
                    ]
                  },
                  "timezone": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "The event's own clock (IANA, like America/Chicago); required for an online or hybrid event"
                  },
                  "languages": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 40
                    },
                    "maxItems": 5,
                    "description": "The languages the event is held in, as BCP 47 codes (en, es); leave out when unknown"
                  },
                  "hosted_by": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "The group or shop hosting an online or hybrid event"
                  },
                  "craft_types": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 60
                    },
                    "maxItems": 20,
                    "default": []
                  },
                  "event_type": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 60
                    },
                    "maxItems": 20
                  },
                  "start_time": {
                    "type": "string",
                    "maxLength": 8
                  },
                  "end_time": {
                    "type": "string",
                    "maxLength": 8
                  },
                  "is_free": {
                    "type": "boolean"
                  },
                  "price_note": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "url": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uri"
                      },
                      {
                        "type": "string",
                        "enum": [
                          ""
                        ]
                      }
                    ]
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 5000
                  },
                  "join_url": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "join_meeting_id": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "join_passcode": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "join_phone": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "contact_name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "contact_email": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "organizer_email": {
                    "type": "string"
                  },
                  "website": {
                    "type": "string"
                  },
                  "turnstileToken": {
                    "type": "string"
                  }
                },
                "required": [
                  "title",
                  "start_date"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "201 response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "message"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "400 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "403 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/taxonomy": {
      "get": {
        "summary": "Craft types, event types and tags used across the site",
        "tags": [
          "taxonomy"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Taxonomy"
                }
              }
            }
          },
          "503": {
            "description": "503 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/tenant": {
      "get": {
        "summary": "This site's name and which crafts it covers",
        "tags": [
          "platform"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "200 response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteInfo"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {}
}
