{"openapi":"3.1.0","info":{"title":"Refuje Public API","version":"2026-08-12","description":"Read-only public JSON API for Refuje travel content: things-to-do activities, blog posts, and field-guide destinations/experiences. No authentication is required except where a security requirement is declared (the enquiry endpoint). Endpoints not listed here are internal and not a stable contract. Paginated lists use the envelope {count, next, previous, results}.","contact":{"name":"Refuje","email":"myrefuje@gmail.com","url":"https://refuje.com/developers"}},"servers":[{"url":"https://api.refuje.com/api/v1"}],"tags":[{"name":"Things to do","description":"Bookable activity marketplace: published activities, destinations, states, and providers."},{"name":"Blog","description":"Published editorial content."},{"name":"Destinations & experiences","description":"Field-guide destinations, curated experiences, and map data."}],"paths":{"/marketplace/public/all-activities/":{"get":{"tags":["Things to do"],"operationId":"listAllActivities","summary":"List publicly listed activities","parameters":[{"name":"page","in":"query","required":false,"description":"Page number. Out-of-range pages return the last page instead of 404; a non-integer value falls back to page 1 (`page=last` is not supported).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 60).","schema":{"type":"integer","minimum":1,"maximum":60,"default":24}},{"name":"interest","in":"query","required":false,"description":"Filter by the controlled discovery interest. The response echoes an applied_interest capability marker when supported.","schema":{"type":"string","enum":["cycling","stargazing","trekking-hiking","food-tastings","culture-heritage","camping","nature-wildlife","wellness","boating","jeep-drives","walks"]}},{"name":"theme","in":"query","required":false,"description":"Filter by theme tag. Unknown values are silently ignored.","schema":{"type":"string","enum":["history","culture","food","nature","adventure","wellness"]}},{"name":"type","in":"query","required":false,"description":"Filter by offering type. Unknown values are silently ignored.","schema":{"type":"string","enum":["tour","activity","ticket","rental","transport","other"]}},{"name":"difficulty","in":"query","required":false,"description":"Filter by difficulty. Unknown values are silently ignored.","schema":{"type":"string","enum":["easy","moderate","challenging","expert"]}},{"name":"duration","in":"query","required":false,"description":"Duration bucket: under-2h (<120 min), half-day (120–359 min), full-day (≥360 min). Unknown values are silently ignored.","schema":{"type":"string","enum":["under-2h","half-day","full-day"]}},{"name":"sort","in":"query","required":false,"description":"Sort order. Default is -updated_at (newest first). Unknown values are silently ignored.","schema":{"type":"string","enum":["updated_at","-updated_at","duration","-duration","duration_minutes","-duration_minutes"]}}],"responses":{"200":{"description":"Paginated activity cards.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ActivityCard"}},"applied_interest":{"type":["string","null"],"description":"Controlled interest actually applied by this backend."}}}}}}}}},"/marketplace/public/destinations/sitemap/":{"get":{"tags":["Things to do"],"operationId":"marketplaceDestinationsSitemap","summary":"Marketplace destinations index","responses":{"200":{"description":"All marketplace-enabled destinations with published inventory.","content":{"application/json":{"schema":{"type":"object","properties":{"destinations":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"updated_at":{"type":["string","null"],"format":"date-time","description":"Most recent activity update in this destination."}}}}}}}}}}}},"/marketplace/public/destinations/{slug}/activities/":{"get":{"tags":["Things to do"],"operationId":"listDestinationActivities","summary":"List published activities for a destination","parameters":[{"name":"slug","in":"path","required":true,"description":"Destination slug (see the destinations sitemap).","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Out-of-range pages return the last page instead of 404; a non-integer value falls back to page 1 (`page=last` is not supported).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 60).","schema":{"type":"integer","minimum":1,"maximum":60,"default":24}},{"name":"interest","in":"query","required":false,"description":"Filter by the controlled discovery interest. The response echoes an applied_interest capability marker when supported.","schema":{"type":"string","enum":["cycling","stargazing","trekking-hiking","food-tastings","culture-heritage","camping","nature-wildlife","wellness","boating","jeep-drives","walks"]}},{"name":"theme","in":"query","required":false,"description":"Filter by theme tag. Unknown values are silently ignored.","schema":{"type":"string","enum":["history","culture","food","nature","adventure","wellness"]}},{"name":"type","in":"query","required":false,"description":"Filter by offering type. Unknown values are silently ignored.","schema":{"type":"string","enum":["tour","activity","ticket","rental","transport","other"]}},{"name":"difficulty","in":"query","required":false,"description":"Filter by difficulty. Unknown values are silently ignored.","schema":{"type":"string","enum":["easy","moderate","challenging","expert"]}},{"name":"duration","in":"query","required":false,"description":"Duration bucket: under-2h (<120 min), half-day (120–359 min), full-day (≥360 min). Unknown values are silently ignored.","schema":{"type":"string","enum":["under-2h","half-day","full-day"]}},{"name":"sort","in":"query","required":false,"description":"Sort order. Default is -updated_at (newest first). Unknown values are silently ignored.","schema":{"type":"string","enum":["updated_at","-updated_at","duration","-duration","duration_minutes","-duration_minutes"]}}],"responses":{"200":{"description":"Paginated activity cards plus destination metadata. A filter that matches nothing returns an empty results array, not 404.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ActivityCard"}},"applied_interest":{"type":["string","null"],"description":"Controlled interest actually applied by this backend."},"destination":{"$ref":"#/components/schemas/MarketplaceDestination"},"seo":{"oneOf":[{"$ref":"#/components/schemas/SeoOverride"},{"type":"null"}]}}}}}},"404":{"description":"Resource not found, or not currently eligible for public listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/marketplace/public/states/sitemap/":{"get":{"tags":["Things to do"],"operationId":"marketplaceStatesSitemap","summary":"States index","responses":{"200":{"description":"States that currently have published activities. Order is unspecified.","content":{"application/json":{"schema":{"type":"object","properties":{"states":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"updated_at":{"type":["string","null"],"format":"date-time"}}}}}}}}}}}},"/marketplace/public/states/{slug}/activities/":{"get":{"tags":["Things to do"],"operationId":"listStateActivities","summary":"List published activities for a state","parameters":[{"name":"slug","in":"path","required":true,"description":"State slug (see the states sitemap).","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Out-of-range pages return the last page instead of 404; a non-integer value falls back to page 1 (`page=last` is not supported).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 60).","schema":{"type":"integer","minimum":1,"maximum":60,"default":24}},{"name":"interest","in":"query","required":false,"description":"Filter by the controlled discovery interest. The response echoes an applied_interest capability marker when supported.","schema":{"type":"string","enum":["cycling","stargazing","trekking-hiking","food-tastings","culture-heritage","camping","nature-wildlife","wellness","boating","jeep-drives","walks"]}},{"name":"theme","in":"query","required":false,"description":"Filter by theme tag. Unknown values are silently ignored.","schema":{"type":"string","enum":["history","culture","food","nature","adventure","wellness"]}},{"name":"type","in":"query","required":false,"description":"Filter by offering type. Unknown values are silently ignored.","schema":{"type":"string","enum":["tour","activity","ticket","rental","transport","other"]}},{"name":"difficulty","in":"query","required":false,"description":"Filter by difficulty. Unknown values are silently ignored.","schema":{"type":"string","enum":["easy","moderate","challenging","expert"]}},{"name":"duration","in":"query","required":false,"description":"Duration bucket: under-2h (<120 min), half-day (120–359 min), full-day (≥360 min). Unknown values are silently ignored.","schema":{"type":"string","enum":["under-2h","half-day","full-day"]}},{"name":"sort","in":"query","required":false,"description":"Sort order. Default is -updated_at (newest first). Unknown values are silently ignored.","schema":{"type":"string","enum":["updated_at","-updated_at","duration","-duration","duration_minutes","-duration_minutes"]}}],"responses":{"200":{"description":"Paginated activity cards plus state metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ActivityCard"}},"applied_interest":{"type":["string","null"],"description":"Controlled interest actually applied by this backend."},"state":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}}}}}}}},"404":{"description":"Resource not found, or not currently eligible for public listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/marketplace/public/activities/sitemap/":{"get":{"tags":["Things to do"],"operationId":"marketplaceActivitiesSitemap","summary":"Published activities index","responses":{"200":{"description":"Activities passing the public-detail eligibility gates, minus those with an editorial noindex override, ordered by public_id. Criteria differ slightly from the listing endpoints: destination publication is not required here, and noindex-overridden activities are excluded here.","content":{"application/json":{"schema":{"type":"object","properties":{"activities":{"type":"array","items":{"type":"object","properties":{"public_id":{"type":"string","format":"uuid"},"slug":{"type":"string","description":"Falls back to the public_id string when the activity has no slug."},"editorial_slug":{"type":"string","nullable":true,"description":"Legacy editorial route that redirects to this activity."},"updated_at":{"type":"string","format":"date-time"}}}},"linked_editorial_slugs":{"type":"array","description":"All editorial routes redirected to eligible activities, including activities omitted above by noindex.","items":{"type":"string"}}}}}}}}}},"/marketplace/public/activities/{idOrSlug}/":{"get":{"tags":["Things to do"],"operationId":"getActivity","summary":"Get activity detail","parameters":[{"name":"idOrSlug","in":"path","required":true,"description":"Activity public_id (UUID) or slug — both resolve to the same resource.","schema":{"type":"string"}}],"responses":{"200":{"description":"Full activity detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityDetail"}}}},"404":{"description":"Resource not found, or not currently eligible for public listing (unpublished, paused, provider inactive, or destination disabled). The response body is empty."}}}},"/marketplace/public/activities/{publicId}/enquire/":{"post":{"tags":["Things to do"],"operationId":"enquireActivity","summary":"Submit a booking enquiry","description":"Creates a booking enquiry (lead) for an activity. This endpoint is used by the refuje.com booking flow and requires: an httpOnly JWT access-token cookie issued after phone-OTP verification, whose verified phone claim must equal the submitted guest_phone, plus CSRF double-submit (X-CSRFToken header matching the csrftoken cookie). It is not callable with no credentials.","security":[{"cookieAuth":[],"csrfToken":[]}],"parameters":[{"name":"publicId","in":"path","required":true,"description":"Activity public_id (UUID only — the slug form is not accepted here).","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnquireRequest"}}}},"responses":{"201":{"description":"Enquiry created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnquireResponse"}}}},"400":{"description":"Validation error (field-error object), stale/missing consent versions, or a lead-creation error (detail is a list of strings in that case)."},"401":{"description":"No phone-verified access token. Body: {\"detail\": \"Verify your phone number before submitting an enquiry.\"}"},"403":{"description":"CSRF failure, or the verified phone number does not match guest_phone."},"404":{"description":"Resource not found, or not currently eligible for public listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/marketplace/public/providers/sitemap/":{"get":{"tags":["Things to do"],"operationId":"providersSitemap","summary":"Providers index","responses":{"200":{"description":"Approved, active providers with published inventory, ordered by slug.","content":{"application/json":{"schema":{"type":"object","properties":{"providers":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time"}}}}}}}}}}}},"/marketplace/public/providers/{slug}/":{"get":{"tags":["Things to do"],"operationId":"getProvider","summary":"Get provider profile","parameters":[{"name":"slug","in":"path","required":true,"description":"Provider slug (see the providers sitemap).","schema":{"type":"string"}}],"responses":{"200":{"description":"Provider profile.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderDetail"}}}},"404":{"description":"Resource not found, or not currently eligible for public listing (unpublished, paused, provider inactive, or destination disabled). The response body is empty."}}}},"/marketplace/public/providers/{slug}/activities/":{"get":{"tags":["Things to do"],"operationId":"listProviderActivities","summary":"List a provider's published activities","description":"Paginated activity cards for one provider. The theme/type/difficulty/duration/sort filters are NOT supported here, and resolved_price is always null on this endpoint's cards.","parameters":[{"name":"slug","in":"path","required":true,"description":"Provider slug.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number. Out-of-range pages return the last page instead of 404; a non-integer value falls back to page 1 (`page=last` is not supported).","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 60).","schema":{"type":"integer","minimum":1,"maximum":60,"default":24}}],"responses":{"200":{"description":"Paginated activity cards (resolved_price is null here).","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ActivityCard"}}}}}}},"404":{"description":"Resource not found, or not currently eligible for public listing (unpublished, paused, provider inactive, or destination disabled). The response body is empty."}}}},"/blog/published/":{"get":{"tags":["Blog"],"operationId":"listBlogPosts","summary":"List published blog posts","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"category","in":"query","required":false,"description":"Category slug.","schema":{"type":"string"}},{"name":"tag","in":"query","required":false,"description":"Tag slug.","schema":{"type":"string"}},{"name":"destination","in":"query","required":false,"description":"Destination slug.","schema":{"type":"string"}},{"name":"post_type","in":"query","required":false,"description":"Post type (case-insensitive).","schema":{"type":"string","enum":["GUIDE","LISTICLE","ITINERARY","REVIEW","HOW_TO","COMPARISON","NARRATIVE","NEWS"]}},{"name":"featured","in":"query","required":false,"description":"Pass the literal string true to return only featured posts. Any other value is ignored.","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"Paginated posts, newest first. Unknown filter values return an empty result set, not 404.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/BlogPostCard"}}}}}}}}}},"/blog/published/{slug}/":{"get":{"tags":["Blog"],"operationId":"getBlogPost","summary":"Get blog post detail","parameters":[{"name":"slug","in":"path","required":true,"description":"Post slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"Full post including HTML body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlogPostDetail"}}}},"404":{"description":"Resource not found, or not currently eligible for public listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/blog/featured/":{"get":{"tags":["Blog"],"operationId":"listFeaturedBlogPosts","summary":"List featured posts","responses":{"200":{"description":"Up to 10 featured posts, newest first. Plain array — not paginated.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlogPostCard"},"maxItems":10}}}}}}},"/blog/public-categories/":{"get":{"tags":["Blog"],"operationId":"listBlogCategories","summary":"List blog categories","responses":{"200":{"description":"All categories (including ones with no published posts), ordered by display_order then name. Plain array — not paginated.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlogCategory"}}}}}}}},"/blog/destinations/{destSlug}/":{"get":{"tags":["Blog"],"operationId":"listDestinationBlogPosts","summary":"List posts for a destination","parameters":[{"name":"destSlug","in":"path","required":true,"description":"Destination slug.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Paginated posts tagged with this destination, newest first. An unknown destination slug returns an empty result set, not 404.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/BlogPostCard"}}}}}}}}}},"/blog/feed/":{"get":{"tags":["Blog"],"operationId":"blogAtomFeed","summary":"Atom feed","responses":{"200":{"description":"Atom feed of up to 20 of the newest published, indexable (noindex=false) posts.","content":{"application/atom+xml":{"schema":{"type":"string"}}}}}}},"/destinations/":{"get":{"tags":["Destinations & experiences"],"operationId":"listDestinations","summary":"List published destinations","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"all","in":"query","required":false,"description":"Pass all=1 to disable pagination and return a plain array instead of the paginated envelope. Any other value keeps the envelope.","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Published destinations ordered by sort_order then name.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/DestinationListItem"}}}},{"type":"array","items":{"$ref":"#/components/schemas/DestinationListItem"},"description":"Plain-array form, returned when all=1 is passed."}]}}}}}}},"/destinations/{slug}/":{"get":{"tags":["Destinations & experiences"],"operationId":"getDestination","summary":"Get destination detail","parameters":[{"name":"slug","in":"path","required":true,"description":"Destination slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"Destination detail with moods and linked hotels.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DestinationDetail"}}}},"404":{"description":"Resource not found, or not currently eligible for public listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/destinations/{slug}/experiences/":{"get":{"tags":["Destinations & experiences"],"operationId":"listExperiences","summary":"List experiences for a destination","parameters":[{"name":"slug","in":"path","required":true,"description":"Destination slug.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"all","in":"query","required":false,"description":"Pass all=1 to disable pagination and return a plain array instead of the paginated envelope. Any other value keeps the envelope.","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Published experiences ordered by sort_order then name. An unknown destination slug returns an empty result set, not 404.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ExperienceListItem"}}}},{"type":"array","items":{"$ref":"#/components/schemas/ExperienceListItem"},"description":"Plain-array form, returned when all=1 is passed."}]}}}}}}},"/destinations/{slug}/experiences/{code}/":{"get":{"tags":["Destinations & experiences"],"operationId":"getExperience","summary":"Get experience detail","parameters":[{"name":"slug","in":"path","required":true,"description":"Destination slug.","schema":{"type":"string"}},{"name":"code","in":"path","required":true,"description":"Experience code.","schema":{"type":"string"}}],"responses":{"200":{"description":"Full experience detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperienceDetail"}}}},"404":{"description":"Resource not found, or not currently eligible for public listing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/destinations/{slug}/geojson/":{"get":{"tags":["Destinations & experiences"],"operationId":"getDestinationGeoJson","summary":"Get destination map features","parameters":[{"name":"slug","in":"path","required":true,"description":"Destination slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"GeoJSON FeatureCollection of routes (LineString), zones (Polygon) and POIs (Point). An unknown destination returns an empty collection, not 404. Feature properties always include name, description, feature_type and category; experience_code, color, fillOpacity, poiType, folder and folderCategory appear only when set.","content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","const":"FeatureCollection"},"features":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","const":"Feature"},"geometry":{"type":"object","description":"GeoJSON geometry (Point, LineString or Polygon)."},"properties":{"type":"object"}}}}}}}}}}}},"/destinations/{slug}/nearby-places/{code}/":{"get":{"tags":["Destinations & experiences"],"operationId":"listNearbyPlaces","summary":"List nearby places for an experience","parameters":[{"name":"slug","in":"path","required":true,"description":"Destination slug.","schema":{"type":"string"}},{"name":"code","in":"path","required":true,"description":"Experience code.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Results per page (max 100).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"all","in":"query","required":false,"description":"Pass all=1 to disable pagination and return a plain array instead of the paginated envelope. Any other value keeps the envelope.","schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"Nearby places ordered by rating (highest first). Unknown slugs return an empty result set, not 404.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"count":{"type":"integer"},"next":{"type":["string","null"],"format":"uri"},"previous":{"type":["string","null"],"format":"uri"},"results":{"type":"array","items":{"$ref":"#/components/schemas/NearbyPlace"}}}},{"type":"array","items":{"$ref":"#/components/schemas/NearbyPlace"},"description":"Plain-array form, returned when all=1 is passed."}]}}}}}}}},"components":{"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"access_token","description":"httpOnly JWT access-token cookie issued by the refuje.com auth flow after phone OTP verification."},"csrfToken":{"type":"apiKey","in":"header","name":"X-CSRFToken","description":"CSRF double-submit token matching the csrftoken cookie."}},"schemas":{"Error":{"type":"object","properties":{"detail":{"type":"string"}}},"DestinationRef":{"type":"object","description":"Minimal destination reference.","properties":{"slug":{"type":"string"},"name":{"type":"string"}}},"HotelRef":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}}},"ResolvedPrice":{"type":"object","properties":{"gross_inr":{"type":"string","description":"Decimal string, INR, 2 decimal places."},"pricing_basis":{"type":"string","enum":["per_person","per_unit"]},"pricing_version":{"type":"integer","description":"Operational price contract version. Version 2 requires quantity for per-person enquiries."},"requires_guest_count":{"type":"boolean"}}},"AnalyticsMetadata":{"type":"object","properties":{"requires_supplier":{"type":"boolean"},"requires_transport":{"type":"boolean"},"requires_advance_booking":{"type":"boolean"},"fulfillment_owner":{"type":"string","enum":["refuje","supplier"]},"is_in_house":{"type":"boolean"},"availability_type":{"type":"string","enum":["advance_notice","on_request","same_day"]},"group_fit":{"type":"string","description":"One of solo, couple, family, friends, mixed — or the literal string unknown."},"guest_effort_copy":{"type":"string","description":"One of low_effort, active, adventurous, relaxing — or the literal string unknown."}}},"SeoOverride":{"type":"object","description":"Editorial SEO override. Keys appear only when set; noindex is only ever emitted as literal true.","properties":{"title":{"type":"string","maxLength":70},"description":{"type":"string","maxLength":170},"og_image_url":{"type":"string","format":"uri"},"noindex":{"type":"boolean","const":true}}},"MarketplaceDestination":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"state_name":{"type":["string","null"]},"tagline":{"type":"string"},"description":{"type":"string"},"cover_image_url":{"type":["string","null"],"format":"uri"}}},"ActivityMedia":{"type":"object","properties":{"id":{"type":"integer"},"media_type":{"type":"string","enum":["image","video"]},"image_url":{"type":["string","null"],"format":"uri"},"file_url":{"type":["string","null"],"format":"uri"},"media_url":{"type":["string","null"],"format":"uri","description":"image_url when present, otherwise file_url."},"thumbnail_url":{"type":["string","null"],"format":"uri"},"alt_text":{"type":"string"},"display_order":{"type":"integer"}}},"ProviderSummary":{"type":"object","properties":{"public_id":{"type":"string","format":"uuid"},"slug":{"type":["string","null"]},"name":{"type":"string"},"listing_proof_key":{"type":"string","format":"uuid"}}},"ProviderDetail":{"type":"object","properties":{"slug":{"type":"string"},"listing_proof_key":{"type":"string","format":"uuid"},"name":{"type":"string"},"logo_url":{"type":["string","null"],"format":"uri"},"tagline":{"type":"string"},"destinations_served":{"type":"array","items":{"$ref":"#/components/schemas/DestinationRef"}},"published_activity_count":{"type":"integer"},"description":{"type":"string"},"cover_image_url":{"type":["string","null"],"format":"uri"},"seo":{"oneOf":[{"$ref":"#/components/schemas/SeoOverride"},{"type":"null"}]}}},"ActivityCard":{"type":"object","properties":{"public_id":{"type":"string","format":"uuid"},"slug":{"type":["string","null"]},"title":{"type":"string"},"short_description":{"type":"string"},"offering_type":{"type":"string","enum":["tour","activity","ticket","rental","transport","other"]},"theme_tags":{"type":"array","items":{"type":"string"},"description":"Vocabulary: history, culture, food, nature, adventure, wellness."},"duration_minutes":{"type":"integer","minimum":1},"difficulty_level":{"type":"string","description":"easy, moderate, challenging, expert — or empty string when unset."},"pricing_basis":{"type":"string","enum":["per_person","per_unit"]},"primary_image_url":{"type":["string","null"],"format":"uri"},"destination":{"oneOf":[{"$ref":"#/components/schemas/DestinationRef"},{"type":"null"}]},"available_at_hotels":{"type":"array","items":{"$ref":"#/components/schemas/HotelRef"},"maxItems":3,"description":"Capped at 3 entries; see available_at_hotel_count for the true total."},"available_at_hotel_count":{"type":"integer"},"resolved_price":{"oneOf":[{"$ref":"#/components/schemas/ResolvedPrice"},{"type":"null"}],"description":"Null on the provider-activities endpoint."},"analytics_metadata":{"$ref":"#/components/schemas/AnalyticsMetadata"}}},"ActivityDetail":{"type":"object","description":"Full public activity detail.","properties":{"public_id":{"type":"string","format":"uuid"},"slug":{"type":["string","null"]},"offering_type":{"type":"string","enum":["tour","activity","ticket","rental","transport","other"]},"title":{"type":"string"},"short_description":{"type":"string"},"description":{"type":"string"},"theme_tags":{"type":"array","items":{"type":"string"}},"pricing_basis":{"type":"string","enum":["per_person","per_unit"]},"duration_minutes":{"type":"integer"},"max_group_size":{"type":["integer","null"]},"min_group_size":{"type":["integer","null"]},"pickup_type":{"type":"string","enum":["pickup_available","fixed_meeting_point"]},"meeting_point_description":{"type":"string"},"parking_instructions":{"type":"string"},"inclusions":{"type":"array","items":{"type":"string"}},"exclusions":{"type":"array","items":{"type":"string"}},"what_makes_it_special":{"type":"string"},"private_customizable":{"type":"boolean"},"difficulty_level":{"type":"string"},"age_restrictions":{"type":"string"},"health_restrictions":{"type":"string"},"physical_fitness_requirement":{"type":"string"},"weather_dependency":{"type":"boolean"},"accessibility_notes":{"type":"string"},"kids_suitability_notes":{"type":"string"},"is_high_risk":{"type":"boolean"},"high_risk_categories":{"type":"array","items":{"type":"string"},"description":"Vocabulary: trekking, water, snow, adventure, offroad, altitude, biking."},"weekly_off_days":{"type":"array","items":{"type":"string"},"description":"Three-letter uppercase day codes (MON…SUN), by convention."},"seasonality":{"type":"string","enum":["year_round","date_range"]},"season_start":{"type":["string","null"],"format":"date"},"season_end":{"type":["string","null"],"format":"date"},"blackout_dates":{"type":"array","items":{"type":"string"},"description":"ISO YYYY-MM-DD strings, by convention."},"request_receiving_start_time":{"type":"string","format":"time"},"request_receiving_end_time":{"type":"string","format":"time"},"same_day_request_cutoff":{"type":["string","null"],"format":"time"},"suggested_time_slots":{"type":"array","items":{"type":"string"},"maxItems":24,"description":"HH:MM strings."},"destination":{"oneOf":[{"$ref":"#/components/schemas/DestinationRef"},{"type":"null"}]},"primary_image_url":{"type":["string","null"],"format":"uri"},"media":{"type":"array","items":{"$ref":"#/components/schemas/ActivityMedia"}},"provider":{"$ref":"#/components/schemas/ProviderSummary"},"available_at_hotels":{"type":"array","items":{"$ref":"#/components/schemas/HotelRef"},"maxItems":3},"available_at_hotel_count":{"type":"integer"},"analytics_metadata":{"$ref":"#/components/schemas/AnalyticsMetadata"},"resolved_price":{"$ref":"#/components/schemas/ResolvedPrice"},"seo":{"oneOf":[{"$ref":"#/components/schemas/SeoOverride"},{"type":"null"}]},"related_posts":{"type":"array","items":{"$ref":"#/components/schemas/BlogPostCard"},"maxItems":4},"related_hubs":{"type":"array","items":{"$ref":"#/components/schemas/HubCard"},"maxItems":4}}},"HubCard":{"type":"object","description":"Published travel-hub page reference.","properties":{"id":{"type":"integer"},"title":{"type":"string"},"slug":{"type":"string"},"slug_path":{"type":"string"},"place_scope":{"type":"string"},"published_at":{"type":["string","null"],"format":"date-time"},"indexable_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"cover_image":{"type":["string","null"],"format":"uri"},"cover_image_alt":{"type":"string"},"meta_title":{"type":"string"},"meta_description":{"type":"string"}}},"EnquireRequest":{"type":"object","required":["guest_phone","accepted_terms_versions"],"properties":{"guest_phone":{"type":"string","maxLength":32,"description":"Phone number; non-digits are stripped and 11–15 digits are required. Must match the OTP-verified phone claim on the access token."},"accepted_terms_versions":{"type":"object","required":["t_and_c","privacy","activity_terms"],"properties":{"t_and_c":{"type":"string"},"privacy":{"type":"string"},"activity_terms":{"type":"string"}},"description":"Current published version strings of the three consent documents. Stale versions are rejected with 400."},"guest_name":{"type":"string","maxLength":150},"guest_email":{"type":"string","format":"email"},"guest_count":{"type":["integer","null"],"minimum":1,"maximum":99},"preferred_date":{"type":["string","null"],"format":"date"},"preferred_time":{"type":["string","null"],"format":"time"},"guest_note":{"type":"string","maxLength":2000},"cta_source":{"type":"string","maxLength":40},"stay_tab_route":{"type":"string","maxLength":80},"qr_source":{"type":"string","maxLength":60}}},"EnquireResponse":{"type":"object","properties":{"lead_id":{"type":"string"},"whatsapp_url":{"type":"string","format":"uri"},"phone_display":{"type":"string"},"provider_name":{"type":"string"}}},"BlogCategory":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string"},"display_order":{"type":"integer"}}},"BlogTag":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"}}},"BlogPostCard":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"slug":{"type":"string"},"excerpt":{"type":"string"},"cover_image":{"type":["string","null"],"format":"uri"},"cover_image_alt":{"type":"string"},"post_type":{"type":"string","enum":["GUIDE","LISTICLE","ITINERARY","REVIEW","HOW_TO","COMPARISON","NARRATIVE","NEWS"]},"status":{"type":"string","description":"Always PUBLISHED on public endpoints."},"is_featured":{"type":"boolean"},"noindex":{"type":"boolean"},"published_at":{"type":["string","null"],"format":"date-time"},"updated_content_at":{"type":["string","null"],"format":"date-time"},"reading_time_minutes":{"type":"integer"},"word_count":{"type":"integer"},"author":{"type":["integer","null"]},"author_name":{"type":"string"},"author_slug":{"type":"string","description":"Empty string when the post has no author."},"category_names":{"type":"array","items":{"type":"string"}},"destination_names":{"type":"array","items":{"type":"string"}},"primary_destination_slug":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"BlogDestinationMinimal":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"name":{"type":"string"},"center_lat":{"type":"number"},"center_lng":{"type":"number"}}},"BlogGalleryImage":{"type":"object","properties":{"id":{"type":"integer"},"image":{"type":"string","format":"uri"},"alt_text":{"type":"string"},"caption":{"type":"string"},"blurhash":{"type":"string"},"display_order":{"type":"integer"}}},"BookingCta":{"description":"Marketplace call-to-action attached to a post; null when no eligible activity exists. Discriminated by kind.","oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"global"}}},{"type":"object","properties":{"kind":{"type":"string","const":"state"},"state":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}}}}},{"type":"object","properties":{"kind":{"type":"string","const":"activities"},"activities":{"type":"array","items":{"$ref":"#/components/schemas/ActivityCard"},"maxItems":4},"destination":{"oneOf":[{"$ref":"#/components/schemas/DestinationRef"},{"type":"null"}]}}}]},"BlogPostDetail":{"allOf":[{"$ref":"#/components/schemas/BlogPostCard"},{"type":"object","properties":{"body":{"type":"string","description":"Post body as sanitized HTML."},"author_display_name":{"type":"string"},"author_bio":{"type":"string"},"is_active":{"type":"boolean"},"meta_title":{"type":"string","maxLength":70},"meta_description":{"type":"string","maxLength":160},"og_image":{"type":["string","null"],"format":"uri"},"canonical_url":{"type":"string"},"table_of_contents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"level":{"type":"integer"}}},"description":"Heading outline. Item shape is by convention, not schema-enforced."},"categories":{"type":"array","items":{"$ref":"#/components/schemas/BlogCategory"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/BlogTag"}},"destinations":{"type":"array","items":{"$ref":"#/components/schemas/BlogDestinationMinimal"}},"primary_destination":{"type":["integer","null"]},"gallery_images":{"type":"array","items":{"$ref":"#/components/schemas/BlogGalleryImage"}},"booking_cta":{"oneOf":[{"$ref":"#/components/schemas/BookingCta"},{"type":"null"}]}}}]},"DestinationListItem":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"tagline":{"type":"string"},"cover_image":{"type":["string","null"],"format":"uri"},"center_lng":{"type":"number"},"center_lat":{"type":"number"},"background_color":{"type":"string"},"text_color":{"type":"string"},"mood_count":{"type":"integer"},"experience_count":{"type":"integer"}}},"Mood":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"tagline":{"type":"string"},"tip":{"type":"string"},"support_line":{"type":"string"},"color":{"type":"string"},"card_background":{"type":"string"},"illustration":{"type":["string","null"],"format":"uri"},"is_special":{"type":"boolean"},"sort_order":{"type":"integer"},"experience_codes":{"type":"array","items":{"type":"string"}}}},"DestinationDetail":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"tagline":{"type":"string"},"description":{"type":"string"},"center_lng":{"type":"number"},"center_lat":{"type":"number"},"default_zoom":{"type":"number"},"default_pitch":{"type":"number"},"default_bearing":{"type":"number"},"mapbox_style":{"type":"string"},"bounds_sw_lng":{"type":["number","null"]},"bounds_sw_lat":{"type":["number","null"]},"bounds_ne_lng":{"type":["number","null"]},"bounds_ne_lat":{"type":["number","null"]},"background_color":{"type":"string"},"text_color":{"type":"string"},"moods":{"type":"array","items":{"$ref":"#/components/schemas/Mood"}},"linked_hotels":{"type":"array","items":{"$ref":"#/components/schemas/HotelRef"}}}},"ExperienceListItem":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"display_name":{"type":"string"},"tagline":{"type":"string"},"experience_type":{"type":"string"},"color":{"type":"string"},"duration":{"type":"string"},"effort":{"type":"string","description":"easy, gentle, fair, moderate, challenging — or empty string."},"distance":{"type":"string"},"mood_slug":{"type":"string","description":"Empty string when the experience has no mood."},"thumbnail":{"type":["string","null"],"format":"uri"},"price":{"type":["string","null"],"description":"Display price; only present when enabled for cards."}}},"ExperienceImage":{"type":"object","properties":{"image":{"type":"string","format":"uri"},"alt_text":{"type":"string"},"sort_order":{"type":"integer"}}},"ExperienceDetail":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"display_name":{"type":"string"},"slug":{"type":"string"},"tagline":{"type":"string"},"experience_type":{"type":"string"},"color":{"type":"string"},"duration":{"type":"string"},"effort":{"type":"string"},"distance":{"type":"string"},"best_time":{"type":"string"},"about":{"type":"array","description":"Free-form JSON content blocks; inner shape is not schema-enforced."},"what_you_get":{"type":"array","description":"Free-form JSON content blocks; inner shape is not schema-enforced."},"why_we_chose_this":{"type":"string"},"golden_way":{"type":"string"},"breakdown":{"type":"object","description":"Free-form JSON; inner shape is not schema-enforced."},"center_lng":{"type":"number"},"center_lat":{"type":"number"},"zoom":{"type":"number"},"mood_slug":{"type":"string"},"images":{"type":"array","items":{"$ref":"#/components/schemas/ExperienceImage"}},"related_experience_codes":{"type":"array","items":{"type":"string"}},"price":{"type":["string","null"],"description":"Display price; only present when enabled for detail pages."}}},"NearbyPlace":{"type":"object","properties":{"google_place_id":{"type":"string"},"name":{"type":"string"},"place_type":{"type":"string"},"primary_type":{"type":"string"},"rating":{"type":["number","null"]},"user_rating_count":{"type":["integer","null"]},"address":{"type":"string"},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]}}}}}}