{"openapi": "3.1.0", "info": {"title": "stpeteprivatetours API", "version": "1.0.0", "description": "Public API for St. Petersburg Private Tours \u2014 optimised for AI-agent consumption."}, "paths": {"/api/v1/tours/": {"get": {"operationId": "api_api_list_tours", "summary": "List all published tours", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TourListItemOut"}, "title": "Response", "type": "array"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "Return every published tour with basic info and price bounds.", "tags": ["tours"]}}, "/api/v1/tours/{slug}/": {"get": {"operationId": "api_api_tour_detail", "summary": "Full tour detail (rates, extras, itinerary, slides, guides)", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TourDetailOut"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "Return a single tour with all nested related data.", "tags": ["tours"]}}, "/api/v1/guides/": {"get": {"operationId": "api_api_list_guides", "summary": "List guides (filter: language, tour)", "parameters": [{"in": "query", "name": "language", "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Language"}, "required": false}, {"in": "query", "name": "tour", "schema": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Tour"}, "required": false}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/GuideListOut"}, "title": "Response", "type": "array"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "List published guides. Optional filters: language prefix (e.g. 'en'), tour slug.", "tags": ["guides"]}}, "/api/v1/languages/": {"get": {"operationId": "api_api_list_languages", "summary": "Supported languages", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/LanguageOut"}, "title": "Response", "type": "array"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "tags": ["languages"]}}, "/api/v1/extras/": {"get": {"operationId": "api_api_list_extras", "summary": "All extras with rates", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ExtraListOut"}, "title": "Response", "type": "array"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "tags": ["extras"]}}, "/api/v1/availability/": {"post": {"operationId": "api_api_check_availability", "summary": "Check available start times and guides for a tour on a date", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AvailabilityResponse"}}}}, "400": {"description": "Bad Request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "Return available time slots and guides for a tour/date/participants/extras.\n\nReuses the same conflict-detection logic as the HTMX frontend\n(users.utils.get_inactive_periods / find_period_intersection) so the API\nand website stay consistent.", "tags": ["availability"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AvailabilityRequest"}}}, "required": true}}}}, "components": {"schemas": {"TourListItemOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "slug": {"title": "Slug", "type": "string"}, "title": {"title": "Title", "type": "string"}, "title_sub": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Title Sub"}, "header": {"title": "Header", "type": "string"}, "highlights": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Highlights"}, "duration_minutes": {"title": "Duration Minutes", "type": "integer"}, "order": {"title": "Order", "type": "integer"}, "is_featured": {"title": "Is Featured", "type": "boolean"}, "is_published": {"title": "Is Published", "type": "boolean"}, "open_time": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Open Time"}, "close_time": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Close Time"}, "rate_includes": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Rate Includes"}, "cancellation_policy": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Cancellation Policy"}, "image_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Image Url"}, "default_rate": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Default Rate"}, "min_rate_rub": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Min Rate Rub"}, "max_rate_rub": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Max Rate Rub"}}, "required": ["id", "slug", "title", "header", "duration_minutes", "order", "is_featured", "is_published"], "title": "TourListItemOut", "type": "object"}, "ErrorOut": {"properties": {"detail": {"title": "Detail", "type": "string"}}, "required": ["detail"], "title": "ErrorOut", "type": "object"}, "ExtraOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "title": {"title": "Title", "type": "string"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Description"}, "duration_minutes": {"title": "Duration Minutes", "type": "integer"}, "rate_includes": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Rate Includes"}, "cancellation_policy": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Cancellation Policy"}, "rates": {"default": [], "items": {"$ref": "#/components/schemas/RateOut"}, "title": "Rates", "type": "array"}}, "required": ["id", "title", "duration_minutes"], "title": "ExtraOut", "type": "object"}, "GuideOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "slug": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Slug"}, "email": {"title": "Email", "type": "string"}, "phone": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Phone"}, "description": {"title": "Description", "type": "string"}, "image_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Image Url"}, "is_published": {"title": "Is Published", "type": "boolean"}, "languages": {"default": [], "items": {"$ref": "#/components/schemas/LanguageOut"}, "title": "Languages", "type": "array"}, "tours": {"default": [], "items": {"type": "integer"}, "title": "Tours", "type": "array"}, "extras": {"default": [], "items": {"type": "integer"}, "title": "Extras", "type": "array"}}, "required": ["id", "name", "email", "description", "is_published"], "title": "GuideOut", "type": "object"}, "ItineraryItemOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "title": {"title": "Title", "type": "string"}, "content": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Content"}}, "required": ["id", "title"], "title": "ItineraryItemOut", "type": "object"}, "LanguageOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "prefix": {"title": "Prefix", "type": "string"}, "flag": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Flag"}, "is_published": {"title": "Is Published", "type": "boolean"}}, "required": ["id", "name", "prefix", "is_published"], "title": "LanguageOut", "type": "object"}, "RateOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "rate": {"title": "Rate", "type": "integer"}, "min_participants": {"title": "Min Participants", "type": "integer"}, "max_participants": {"title": "Max Participants", "type": "integer"}}, "required": ["id", "rate", "min_participants", "max_participants"], "title": "RateOut", "type": "object"}, "SlideOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "order": {"title": "Order", "type": "integer"}, "image_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Image Url"}}, "required": ["id", "order"], "title": "SlideOut", "type": "object"}, "TourDetailOut": {"description": "Full tour detail including nested related objects.", "properties": {"id": {"title": "Id", "type": "integer"}, "slug": {"title": "Slug", "type": "string"}, "title": {"title": "Title", "type": "string"}, "title_sub": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Title Sub"}, "header": {"title": "Header", "type": "string"}, "highlights": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Highlights"}, "duration_minutes": {"title": "Duration Minutes", "type": "integer"}, "order": {"title": "Order", "type": "integer"}, "is_featured": {"title": "Is Featured", "type": "boolean"}, "is_published": {"title": "Is Published", "type": "boolean"}, "open_time": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Open Time"}, "close_time": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Close Time"}, "rate_includes": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Rate Includes"}, "cancellation_policy": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Cancellation Policy"}, "image_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Image Url"}, "default_rate": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Default Rate"}, "min_rate_rub": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Min Rate Rub"}, "max_rate_rub": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Max Rate Rub"}, "rates": {"default": [], "items": {"$ref": "#/components/schemas/RateOut"}, "title": "Rates", "type": "array"}, "extras": {"default": [], "items": {"$ref": "#/components/schemas/ExtraOut"}, "title": "Extras", "type": "array"}, "itinerary": {"default": [], "items": {"$ref": "#/components/schemas/ItineraryItemOut"}, "title": "Itinerary", "type": "array"}, "slides": {"default": [], "items": {"$ref": "#/components/schemas/SlideOut"}, "title": "Slides", "type": "array"}, "guides": {"default": [], "items": {"$ref": "#/components/schemas/GuideOut"}, "title": "Guides", "type": "array"}}, "required": ["id", "slug", "title", "header", "duration_minutes", "order", "is_featured", "is_published"], "title": "TourDetailOut", "type": "object"}, "GuideListOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "slug": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Slug"}, "image_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Image Url"}, "is_published": {"title": "Is Published", "type": "boolean"}, "languages": {"default": [], "items": {"type": "string"}, "title": "Languages", "type": "array"}, "tours": {"default": [], "items": {"type": "integer"}, "title": "Tours", "type": "array"}}, "required": ["id", "name", "is_published"], "title": "GuideListOut", "type": "object"}, "ExtraListOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "title": {"title": "Title", "type": "string"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Description"}, "duration_minutes": {"title": "Duration Minutes", "type": "integer"}, "rate_includes": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Rate Includes"}, "cancellation_policy": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": "", "title": "Cancellation Policy"}, "min_rate_rub": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Min Rate Rub"}, "max_rate_rub": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Max Rate Rub"}}, "required": ["id", "title", "duration_minutes"], "title": "ExtraListOut", "type": "object"}, "AvailabilityResponse": {"properties": {"tour_slug": {"title": "Tour Slug", "type": "string"}, "date": {"title": "Date", "type": "string"}, "participants": {"title": "Participants", "type": "integer"}, "duration_minutes": {"title": "Duration Minutes", "type": "integer"}, "slots": {"items": {"$ref": "#/components/schemas/TimeSlotOut"}, "title": "Slots", "type": "array"}, "guides": {"items": {"$ref": "#/components/schemas/GuideAvailabilityOut"}, "title": "Guides", "type": "array"}, "recommended_slots": {"default": [], "items": {"type": "string"}, "title": "Recommended Slots", "type": "array"}, "note": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Note"}}, "required": ["tour_slug", "date", "participants", "duration_minutes", "slots", "guides"], "title": "AvailabilityResponse", "type": "object"}, "GuideAvailabilityOut": {"properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "image_url": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Image Url"}}, "required": ["id", "name"], "title": "GuideAvailabilityOut", "type": "object"}, "TimeSlotOut": {"properties": {"start_time": {"title": "Start Time", "type": "string"}, "end_time": {"title": "End Time", "type": "string"}, "available": {"title": "Available", "type": "boolean"}}, "required": ["start_time", "end_time", "available"], "title": "TimeSlotOut", "type": "object"}, "AvailabilityRequest": {"properties": {"tour_slug": {"title": "Tour Slug", "type": "string"}, "date": {"title": "Date", "type": "string"}, "participants": {"default": 1, "title": "Participants", "type": "integer"}, "extras": {"default": [], "items": {"type": "integer"}, "title": "Extras", "type": "array"}}, "required": ["tour_slug", "date"], "title": "AvailabilityRequest", "type": "object"}}}, "servers": []}