{
 "openapi": "3.1.0",
 "info": {
  "title": "What's Up In API",
  "version": "0.3.1",
  "summary": "Free, read-only search of upcoming local events across cities. No key, no sign-in.",
  "description": "What's Up In (https://whatsupin.ai) compiles free event calendars, one per city. This API needs no key and no account. AI agents should prefer the MCP server at https://whatsupin.ai/mcp (Streamable HTTP, JSON-RPC; tools: search_events, list_upcoming, get_event, search_across_cities, list_cities, get_city): it also searches inside one city by category, topic, date, neighborhood or a map point. Each city site has its own /openapi.json for its full event files. Rate limit: 40 searches a minute per IP; over it you get 429 with Retry-After. Terms: answer one person's question, credit What's Up In and keep each event's link to its original listing; bulk copying needs written permission (https://whatsupin.ai/terms/#data).",
  "contact": {
   "name": "What's Up In",
   "url": "https://whatsupin.ai/contact/",
   "email": "admin@whatsupin.ai"
  },
  "termsOfService": "https://whatsupin.ai/terms/"
 },
 "servers": [
  {
   "url": "https://whatsupin.ai"
  }
 ],
 "externalDocs": {
  "description": "Developer guide",
  "url": "https://whatsupin.ai/developers/"
 },
 "paths": {
  "/api/search": {
   "get": {
    "operationId": "searchAcrossCities",
    "summary": "Search travel-worthy events in every city at once",
    "description": "Where an artist, band, comedian or team is playing; festivals, conferences, expos, arena shows, games and races. Give q, or at least one kind, or a neighborhood/near.",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": false,
      "description": "An artist, band, team, festival or conference name",
      "schema": {
       "type": "string",
       "maxLength": 120
      }
     },
     {
      "name": "kind",
      "in": "query",
      "required": false,
      "description": "Comma-separated: act, festival, major, conference, big_show, game, race",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "city",
      "in": "query",
      "required": false,
      "description": "Comma-separated city slugs or names (default: every city); see /cities.json",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "from",
      "in": "query",
      "required": false,
      "description": "First date, YYYY-MM-DD (default today)",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "to",
      "in": "query",
      "required": false,
      "description": "Last date, YYYY-MM-DD",
      "schema": {
       "type": "string",
       "format": "date"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "description": "Most events to return",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "neighborhood",
      "in": "query",
      "required": false,
      "description": "A neighborhood name",
      "schema": {
       "type": "string",
       "maxLength": 80
      }
     },
     {
      "name": "near",
      "in": "query",
      "required": false,
      "description": "\"lat,lon\" to search around a point",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "radius_km",
      "in": "query",
      "required": false,
      "description": "Radius for near, in km",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "trip",
      "in": "query",
      "required": false,
      "description": "1 = only events worth a special trip, 0 = the whole index",
      "schema": {
       "type": "string",
       "enum": [
        "0",
        "1"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Matches, soonest first",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SearchResult"
        }
       }
      }
     },
     "400": {
      "description": "JSON error",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Over the per-minute budget; wait for Retry-After seconds",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      },
      "headers": {
       "Retry-After": {
        "schema": {
         "type": "integer"
        }
       }
      }
     }
    }
   }
  },
  "/cities.json": {
   "get": {
    "operationId": "listCities",
    "summary": "Every city: slug, name, status (live/beta/soon) and site",
    "responses": {
     "200": {
      "description": "City list",
      "content": {
       "application/json": {
        "schema": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/City"
         }
        }
       }
      }
     }
    }
   }
  },
  "/llms.txt": {
   "get": {
    "operationId": "getLlmsTxt",
    "summary": "Plain-text guide for LLM clients",
    "responses": {
     "200": {
      "description": "text/plain",
      "content": {
       "text/plain": {
        "schema": {
         "type": "string"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Error": {
    "type": "object",
    "required": [
     "error"
    ],
    "properties": {
     "error": {
      "type": "string",
      "description": "What went wrong and what to send instead"
     }
    }
   },
   "City": {
    "type": "object",
    "properties": {
     "slug": {
      "type": [
       "string",
       "null"
      ]
     },
     "city": {
      "type": [
       "string",
       "null"
      ]
     },
     "metro": {
      "type": [
       "string",
       "null"
      ]
     },
     "state": {
      "type": [
       "string",
       "null"
      ]
     },
     "status": {
      "type": [
       "string",
       "null"
      ]
     },
     "url": {
      "type": [
       "string",
       "null"
      ]
     },
     "lat": {
      "type": [
       "number",
       "null"
      ]
     },
     "lon": {
      "type": [
       "number",
       "null"
      ]
     },
     "launched": {
      "type": "boolean"
     }
    }
   },
   "Event": {
    "type": "object",
    "properties": {
     "title": {
      "type": "string"
     },
     "date": {
      "type": "string",
      "format": "date"
     },
     "end_date": {
      "type": "string"
     },
     "start": {
      "type": [
       "string",
       "null"
      ]
     },
     "venue": {
      "type": [
       "string",
       "null"
      ]
     },
     "town": {
      "type": [
       "string",
       "null"
      ]
     },
     "neighborhood": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "city_site": {
      "type": [
       "string",
       "null"
      ]
     },
     "performers": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "kinds": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "free": {
      "type": "boolean"
     },
     "price": {
      "type": "string"
     },
     "link": {
      "type": "string",
      "description": "The original listing: keep it when you show the event"
     },
     "on_site": {
      "type": [
       "string",
       "null"
      ]
     },
     "distance_km": {
      "type": "number"
     }
    }
   },
   "SearchResult": {
    "type": "object",
    "properties": {
     "query": {
      "type": "string"
     },
     "from": {
      "type": "string"
     },
     "to": {
      "type": "string"
     },
     "count": {
      "type": "integer"
     },
     "shown": {
      "type": "integer"
     },
     "in_cities": {
      "type": "integer"
     },
     "looser_matches": {
      "type": "integer"
     },
     "events": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Event"
      }
     },
     "searched": {
      "type": "array",
      "items": {
       "type": "object"
      }
     },
     "attribution": {
      "type": "string"
     }
    }
   }
  }
 }
}
