{"openapi":"3.0.3","info":{"title":"VeganBites Public API","description":"Public read-only API for querying vegan and vegetarian restaurant data worldwide. No authentication required for basic access. Rate limited to 100 requests/minute.","version":"1.0.0","contact":{"name":"VeganBites","url":"https://veganbites.xyz"},"license":{"name":"Public Access","url":"https://veganbites.xyz/api-docs"}},"servers":[{"url":"https://veganbites.xyz","description":"Production"}],"paths":{"/api/v1/restaurants":{"get":{"summary":"List restaurants","description":"Get a paginated list of restaurants with optional filters for city, country, region, cuisine type, and restaurant category.","operationId":"listRestaurants","tags":["Restaurants"],"parameters":[{"name":"city","in":"query","schema":{"type":"string"},"description":"Filter by city name (case-insensitive)","example":"Tokyo"},{"name":"country","in":"query","schema":{"type":"string"},"description":"Filter by country name (case-insensitive)","example":"Japan"},{"name":"region","in":"query","schema":{"type":"string"},"description":"Filter by region (e.g., \"Asia\", \"Europe\", \"North America\")","example":"Asia"},{"name":"cuisine","in":"query","schema":{"type":"string"},"description":"Filter by cuisine type (case-insensitive)","example":"Japanese"},{"name":"type","in":"query","schema":{"type":"string","enum":["vegan","vegetarian"]},"description":"Filter by restaurant category"},{"name":"listing_type","in":"query","schema":{"type":"string","enum":["restaurant","coffee_shop","grocery"]},"description":"Filter by listing type"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Number of results per page (max 100)"},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Number of results to skip for pagination"}],"responses":{"200":{"description":"List of restaurants","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestaurantListResponse"},"example":{"data":[{"id":1,"name":"Green Garden","slug":"green-garden-tokyo","description":"Organic vegan dining","address":"1-2-3 Shibuya","city":"Tokyo","state":null,"country":"Japan","country_code":"JP","region":"Asia","latitude":35.6762,"longitude":139.6503,"category":"vegan","cuisine_type":"Japanese","vegan_rating":5,"price_range":2,"phone":null,"website":null,"tags":["organic","gluten-free"],"is_featured":true,"hours":{"monday":"11am-9pm"}}],"meta":{"total":350,"limit":20,"offset":0,"count":20}}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/restaurants/search":{"get":{"summary":"Search restaurants","description":"Full-text search across restaurant names, cuisines, cities, and descriptions. Uses PostgreSQL full-text search with ILIKE fallback for partial matches.","operationId":"searchRestaurants","tags":["Restaurants"],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Search query (searches names, cuisines, cities, descriptions)","example":"ramen"},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":100},"description":"Number of results per page (max 100)"},{"name":"offset","in":"query","schema":{"type":"integer","default":0,"minimum":0},"description":"Number of results to skip for pagination"}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Missing search query","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/api/v1/restaurants/{id}":{"get":{"summary":"Get restaurant details","description":"Get full details for a single restaurant by ID, including menu items and review statistics.","operationId":"getRestaurant","tags":["Restaurants"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"description":"Restaurant ID","example":1}],"responses":{"200":{"description":"Restaurant details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestaurantDetailResponse"}}}},"400":{"description":"Invalid restaurant ID"},"404":{"description":"Restaurant not found"},"500":{"description":"Internal server error"}}}},"/api/v1/cities":{"get":{"summary":"List cities","description":"Get all cities that have restaurants, with restaurant counts, grouped by country.","operationId":"listCities","tags":["Geography"],"parameters":[{"name":"country","in":"query","schema":{"type":"string"},"description":"Filter cities by country name","example":"Japan"},{"name":"region","in":"query","schema":{"type":"string"},"description":"Filter cities by region","example":"Asia"}],"responses":{"200":{"description":"Cities grouped by country","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CitiesResponse"},"example":{"data":[{"country":"Japan","country_code":"JP","region":"Asia","cities":[{"city":"Tokyo","state":null,"restaurant_count":350},{"city":"Kyoto","state":null,"restaurant_count":175}]}]}}}}}}},"/api/v1/countries":{"get":{"summary":"List countries","description":"Get all countries that have restaurants, with restaurant and city counts, grouped by region.","operationId":"listCountries","tags":["Geography"],"parameters":[{"name":"region","in":"query","schema":{"type":"string"},"description":"Filter by region","example":"Asia"}],"responses":{"200":{"description":"Countries grouped by region","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountriesResponse"},"example":{"data":[{"region":"Asia","countries":[{"country":"Japan","country_code":"JP","restaurant_count":650,"city_count":3}]}]}}}}}}},"/api/v1/stats":{"get":{"summary":"Get aggregate stats","description":"Get high-level statistics about the VeganBites database. Useful for AI agents to understand the scope of available data.","operationId":"getStats","tags":["Meta"],"responses":{"200":{"description":"Aggregate statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatsResponse"},"example":{"data":{"total_restaurants":7200,"total_cities":55,"total_countries":17,"total_regions":8,"total_cuisine_types":51,"categories":[{"type":"vegan","count":5400},{"type":"vegetarian","count":1800}],"api_version":"v1","documentation":"https://veganbites.xyz/api-docs"}}}}}}}}},"components":{"schemas":{"Restaurant":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"city":{"type":"string"},"state":{"type":"string","nullable":true},"country":{"type":"string"},"country_code":{"type":"string","description":"ISO 3166-1 alpha-2 country code"},"region":{"type":"string","nullable":true,"description":"Geographic region (e.g., Asia, Europe)"},"latitude":{"type":"number","format":"float"},"longitude":{"type":"number","format":"float"},"category":{"type":"string","enum":["vegan","vegetarian"],"description":"Restaurant category"},"cuisine_type":{"type":"string","nullable":true},"vegan_rating":{"type":"integer","minimum":1,"maximum":5},"price_range":{"type":"integer","minimum":1,"maximum":4,"description":"1=$ 2=$$ 3=$$$ 4=$$$$"},"phone":{"type":"string","nullable":true},"website":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}},"is_featured":{"type":"boolean"},"hours":{"type":"object","description":"Opening hours by day (JSONB)"}}},"RestaurantDetail":{"allOf":[{"$ref":"#/components/schemas/Restaurant"},{"type":"object","properties":{"review_count":{"type":"integer"},"avg_rating":{"type":"number","nullable":true},"menu_items":{"type":"array","items":{"$ref":"#/components/schemas/MenuItem"}}}}]},"MenuItem":{"type":"object","properties":{"category":{"type":"string"},"item_name":{"type":"string"},"description":{"type":"string","nullable":true},"price":{"type":"number","format":"float","nullable":true}}},"PaginationMeta":{"type":"object","properties":{"total":{"type":"integer","description":"Total matching results"},"limit":{"type":"integer"},"offset":{"type":"integer"},"count":{"type":"integer","description":"Number of results in this response"}}},"RestaurantListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Restaurant"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"SearchResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Restaurant"}},"meta":{"allOf":[{"$ref":"#/components/schemas/PaginationMeta"},{"type":"object","properties":{"query":{"type":"string"}}}]}}},"RestaurantDetailResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RestaurantDetail"}}},"CitiesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string"},"country_code":{"type":"string"},"region":{"type":"string"},"cities":{"type":"array","items":{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string","nullable":true},"restaurant_count":{"type":"integer"}}}}}}}}},"CountriesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"region":{"type":"string"},"countries":{"type":"array","items":{"type":"object","properties":{"country":{"type":"string"},"country_code":{"type":"string"},"restaurant_count":{"type":"integer"},"city_count":{"type":"integer"}}}}}}}}},"StatsResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"total_restaurants":{"type":"integer"},"total_cities":{"type":"integer"},"total_countries":{"type":"integer"},"total_regions":{"type":"integer"},"total_cuisine_types":{"type":"integer"},"categories":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"count":{"type":"integer"}}}},"api_version":{"type":"string"},"documentation":{"type":"string","format":"uri"}}}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"retry_after_seconds":{"type":"integer"}}}}},"tags":[{"name":"Restaurants","description":"Browse and search the restaurant directory"},{"name":"Geography","description":"Explore cities and countries with restaurant data"},{"name":"Meta","description":"API statistics and metadata"}]}